summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--core/array.cpp2
-rw-r--r--core/bind/core_bind.cpp11
-rw-r--r--core/bind/core_bind.h3
-rw-r--r--core/error_macros.h2
-rw-r--r--core/image.cpp23
-rw-r--r--core/image.h6
-rw-r--r--core/io/resource_loader.cpp33
-rw-r--r--core/io/resource_loader.h2
-rw-r--r--core/math/expression.cpp2136
-rw-r--r--core/math/expression.h325
-rw-r--r--core/os/file_access.cpp1
-rw-r--r--core/register_core_types.cpp2
-rw-r--r--core/script_language.h9
-rw-r--r--core/sort.h34
-rw-r--r--core/variant.h6
-rw-r--r--core/variant_call.cpp82
-rw-r--r--doc/classes/Color.xml2
-rw-r--r--doc/classes/SceneTree.xml8
-rw-r--r--drivers/dummy/rasterizer_dummy.h14
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.cpp16
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp2
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp237
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.h16
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp76
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.h17
-rw-r--r--drivers/gles2/shader_compiler_gles2.cpp4
-rw-r--r--drivers/gles2/shader_gles2.cpp59
-rw-r--r--drivers/gles2/shader_gles2.h2
-rw-r--r--drivers/gles2/shaders/scene.glsl108
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp82
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp239
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h23
-rw-r--r--drivers/gles3/shader_compiler_gles3.cpp7
-rw-r--r--drivers/gles3/shader_compiler_gles3.h1
-rw-r--r--drivers/gles3/shaders/scene.glsl14
-rw-r--r--editor/code_editor.cpp23
-rw-r--r--editor/code_editor.h4
-rw-r--r--editor/doc/doc_data.cpp5
-rw-r--r--editor/editor_about.cpp2
-rw-r--r--editor/editor_help.cpp13
-rw-r--r--editor/editor_inspector.cpp78
-rw-r--r--editor/editor_inspector.h3
-rw-r--r--editor/editor_node.cpp63
-rw-r--r--editor/editor_plugin.cpp13
-rw-r--r--editor/editor_plugin.h2
-rw-r--r--editor/editor_properties.cpp109
-rw-r--r--editor/editor_spin_slider.cpp31
-rw-r--r--editor/editor_spin_slider.h4
-rw-r--r--editor/editor_themes.cpp3
-rw-r--r--editor/icons/icon_add_atlas_tile.svg3
-rw-r--r--editor/icons/icon_add_autotile.svg3
-rw-r--r--editor/icons/icon_add_single_tile.svg3
-rw-r--r--editor/icons/icon_information_sign.svg70
-rw-r--r--editor/icons/icon_texture_3_d.svg75
-rw-r--r--editor/icons/icon_texture_array.svg77
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp39
-rw-r--r--editor/import/editor_scene_importer_gltf.h1
-rw-r--r--editor/import/resource_importer_layered_texture.cpp274
-rw-r--r--editor/import/resource_importer_layered_texture.h57
-rw-r--r--editor/inspector_dock.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp2
-rw-r--r--editor/plugins/path_editor_plugin.cpp93
-rw-r--r--editor/plugins/path_editor_plugin.h18
-rw-r--r--editor/plugins/script_editor_plugin.cpp2
-rw-r--r--editor/plugins/script_text_editor.cpp75
-rw-r--r--editor/plugins/script_text_editor.h3
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp364
-rw-r--r--editor/plugins/spatial_editor_plugin.h138
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp28
-rw-r--r--editor/plugins/texture_region_editor_plugin.h5
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp20
-rw-r--r--editor/plugins/tile_map_editor_plugin.h1
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp1906
-rw-r--r--editor/plugins/tile_set_editor_plugin.h160
-rw-r--r--editor/scene_tree_dock.cpp30
-rw-r--r--editor/spatial_editor_gizmos.cpp3194
-rw-r--r--editor/spatial_editor_gizmos.h497
-rw-r--r--modules/bullet/bullet_physics_server.cpp14
-rw-r--r--modules/bullet/bullet_physics_server.h3
-rw-r--r--modules/bullet/rigid_body_bullet.cpp18
-rw-r--r--modules/bullet/rigid_body_bullet.h9
-rw-r--r--modules/bullet/space_bullet.cpp34
-rw-r--r--modules/csg/csg_gizmos.cpp77
-rw-r--r--modules/csg/csg_gizmos.h24
-rw-r--r--modules/etc/image_etc.cpp29
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp2
-rw-r--r--modules/gdnative/nativescript/nativescript.h2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.cpp2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.h2
-rw-r--r--modules/gdscript/gdscript.cpp172
-rw-r--r--modules/gdscript/gdscript.h45
-rw-r--r--modules/gdscript/gdscript_editor.cpp19
-rw-r--r--modules/gdscript/gdscript_parser.cpp433
-rw-r--r--modules/gdscript/gdscript_parser.h24
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp21
-rw-r--r--modules/gdscript/gdscript_tokenizer.h22
-rw-r--r--modules/mono/csharp_script.h2
-rw-r--r--modules/squish/image_compress_squish.cpp31
-rw-r--r--modules/visual_script/visual_script.cpp2
-rw-r--r--modules/visual_script/visual_script.h2
-rw-r--r--modules/visual_script/visual_script_nodes.cpp6
-rw-r--r--scene/2d/physics_body_2d.cpp37
-rw-r--r--scene/2d/tile_map.cpp8
-rw-r--r--scene/3d/camera.cpp10
-rw-r--r--scene/3d/physics_body.cpp38
-rw-r--r--scene/3d/skeleton.cpp92
-rw-r--r--scene/3d/skeleton.h6
-rw-r--r--scene/3d/spatial.cpp5
-rw-r--r--scene/3d/spatial.h1
-rw-r--r--scene/gui/line_edit.cpp2
-rw-r--r--scene/gui/text_edit.cpp2
-rw-r--r--scene/register_scene_types.cpp8
-rw-r--r--scene/resources/bit_mask.cpp119
-rw-r--r--scene/resources/bit_mask.h2
-rw-r--r--scene/resources/material.cpp4
-rw-r--r--scene/resources/physics_material.cpp76
-rw-r--r--scene/resources/physics_material.h32
-rw-r--r--scene/resources/sky_box.cpp16
-rw-r--r--scene/resources/texture.cpp360
-rw-r--r--scene/resources/texture.h82
-rw-r--r--scene/resources/tile_set.cpp25
-rw-r--r--scene/resources/tile_set.h2
-rw-r--r--servers/physics/body_pair_sw.cpp34
-rw-r--r--servers/physics/body_sw.cpp16
-rw-r--r--servers/physics/body_sw.h8
-rw-r--r--servers/physics/collision_solver_sat.cpp62
-rw-r--r--servers/physics/physics_server_sw.cpp14
-rw-r--r--servers/physics/physics_server_sw.h4
-rw-r--r--servers/physics_2d/body_2d_sw.cpp16
-rw-r--r--servers/physics_2d/body_2d_sw.h8
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp34
-rw-r--r--servers/physics_2d/physics_2d_server_sw.cpp16
-rw-r--r--servers/physics_2d/physics_2d_server_sw.h4
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.h3
-rw-r--r--servers/physics_2d_server.h13
-rw-r--r--servers/physics_server.h13
-rw-r--r--servers/register_server_types.cpp2
-rw-r--r--servers/server_wrap_mt_common.h7
-rw-r--r--servers/visual/rasterizer.h27
-rw-r--r--servers/visual/shader_language.cpp155
-rw-r--r--servers/visual/shader_language.h12
-rw-r--r--servers/visual/visual_server_raster.h12
-rw-r--r--servers/visual/visual_server_wrap_mt.h12
-rw-r--r--servers/visual_server.cpp24
-rw-r--r--servers/visual_server.h41
147 files changed, 9499 insertions, 4061 deletions
diff --git a/.travis.yml b/.travis.yml
index 133a134758..e89774a2a2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -63,12 +63,10 @@ matrix:
- env: GODOT_TARGET=osx TOOLS=yes CACHE_NAME=${GODOT_TARGET}-tools-clang
os: osx
- osx_image: xcode9.3
compiler: clang
- env: GODOT_TARGET=iphone TOOLS=no CACHE_NAME=${GODOT_TARGET}-clang
os: osx
- osx_image: xcode9.3
compiler: clang
- env: GODOT_TARGET=server TOOLS=yes CACHE_NAME=${GODOT_TARGET}-tools-gcc
diff --git a/core/array.cpp b/core/array.cpp
index 96e64294ed..44c553e4eb 100644
--- a/core/array.cpp
+++ b/core/array.cpp
@@ -259,7 +259,7 @@ Array &Array::sort_custom(Object *p_obj, const StringName &p_function) {
ERR_FAIL_NULL_V(p_obj, *this);
- SortArray<Variant, _ArrayVariantSortCustom> avs;
+ SortArray<Variant, _ArrayVariantSortCustom, true> avs;
avs.compare.obj = p_obj;
avs.compare.func = p_function;
avs.sort(_p->array.ptrw(), _p->array.size());
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index af1d49ae8c..04e6f51b0d 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -112,11 +112,15 @@ PoolStringArray _ResourceLoader::get_dependencies(const String &p_path) {
return ret;
};
-bool _ResourceLoader::has(const String &p_path) {
+bool _ResourceLoader::has_cached(const String &p_path) {
String local_path = ProjectSettings::get_singleton()->localize_path(p_path);
return ResourceCache::has(local_path);
-};
+}
+
+bool _ResourceLoader::exists(const String &p_path, const String &p_type_hint) {
+ return ResourceLoader::exists(p_path, p_type_hint);
+}
void _ResourceLoader::_bind_methods() {
@@ -125,7 +129,8 @@ void _ResourceLoader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_recognized_extensions_for_type", "type"), &_ResourceLoader::get_recognized_extensions_for_type);
ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &_ResourceLoader::set_abort_on_missing_resources);
ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &_ResourceLoader::get_dependencies);
- ClassDB::bind_method(D_METHOD("has", "path"), &_ResourceLoader::has);
+ ClassDB::bind_method(D_METHOD("has_cached", "path"), &_ResourceLoader::has_cached);
+ ClassDB::bind_method(D_METHOD("exists", "path", "type_hint"), &_ResourceLoader::exists, DEFVAL(""));
}
_ResourceLoader::_ResourceLoader() {
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 1729c23779..8327149f49 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -55,7 +55,8 @@ public:
PoolVector<String> get_recognized_extensions_for_type(const String &p_type);
void set_abort_on_missing_resources(bool p_abort);
PoolStringArray get_dependencies(const String &p_path);
- bool has(const String &p_path);
+ bool has_cached(const String &p_path);
+ bool exists(const String &p_path, const String &p_type_hint = "");
_ResourceLoader();
};
diff --git a/core/error_macros.h b/core/error_macros.h
index 3587e01d54..bee738ceea 100644
--- a/core/error_macros.h
+++ b/core/error_macros.h
@@ -313,7 +313,7 @@ extern bool _err_error_exists;
#define WARN_DEPRECATED \
{ \
- static bool warning_shown = false; \
+ static volatile bool warning_shown = false; \
if (!warning_shown) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future", ERR_HANDLER_WARNING); \
_err_error_exists = false; \
diff --git a/core/image.cpp b/core/image.cpp
index 19440d1718..65905c83e8 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -987,8 +987,10 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &
int pixsize = get_format_pixel_size(p_format);
int pixshift = get_format_pixel_rshift(p_format);
int block = get_format_block_size(p_format);
- int minw, minh;
- get_format_min_pixel_size(p_format, minw, minh);
+ //technically, you can still compress up to 1 px no matter the format, so commenting this
+ //int minw, minh;
+ //get_format_min_pixel_size(p_format, minw, minh);
+ int minw = 1, minh = 1;
while (true) {
@@ -1304,7 +1306,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0);
if (size != p_data.size()) {
- ERR_EXPLAIN("Expected data size of " + itos(size) + " in Image::create()");
+ ERR_EXPLAIN("Expected data size of " + itos(size) + " bytes in Image::create(), got instead " + itos(p_data.size()) + " bytes.");
ERR_FAIL_COND(p_data.size() != size);
}
@@ -1592,10 +1594,10 @@ Error Image::save_png(const String &p_path) const {
return save_png_func(p_path, Ref<Image>((Image *)this));
}
-int Image::get_image_data_size(int p_width, int p_height, Format p_format, int p_mipmaps) {
+int Image::get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps) {
int mm;
- return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmaps);
+ return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmaps ? -1 : 0);
}
int Image::get_image_required_mipmaps(int p_width, int p_height, Format p_format) {
@@ -2376,6 +2378,17 @@ Image::DetectChannels Image::get_detected_channels() {
return DETECTED_RGBA;
}
+void Image::optimize_channels() {
+ switch (get_detected_channels()) {
+ case DETECTED_L: convert(FORMAT_L8); break;
+ case DETECTED_LA: convert(FORMAT_LA8); break;
+ case DETECTED_R: convert(FORMAT_R8); break;
+ case DETECTED_RG: convert(FORMAT_RG8); break;
+ case DETECTED_RGB: convert(FORMAT_RGB8); break;
+ case DETECTED_RGBA: convert(FORMAT_RGBA8); break;
+ }
+}
+
void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_width"), &Image::get_width);
diff --git a/core/image.h b/core/image.h
index 8c4854e053..c8dd647c31 100644
--- a/core/image.h
+++ b/core/image.h
@@ -116,7 +116,8 @@ public:
enum CompressSource {
COMPRESS_SOURCE_GENERIC,
COMPRESS_SOURCE_SRGB,
- COMPRESS_SOURCE_NORMAL
+ COMPRESS_SOURCE_NORMAL,
+ COMPRESS_SOURCE_LAYERED,
};
//some functions provided by something else
@@ -272,7 +273,7 @@ public:
static int get_format_block_size(Format p_format);
static void get_format_min_pixel_size(Format p_format, int &r_w, int &r_h);
- static int get_image_data_size(int p_width, int p_height, Format p_format, int p_mipmaps = 0);
+ static int get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps = false);
static int get_image_required_mipmaps(int p_width, int p_height, Format p_format);
enum CompressMode {
@@ -329,6 +330,7 @@ public:
};
DetectChannels get_detected_channels();
+ void optimize_channels();
Color get_pixelv(const Point2 &p_src) const;
Color get_pixel(int p_x, int p_y) const;
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index c44d2597a7..ab2d18eb1b 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -123,6 +123,9 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const Stri
return ril;
}
+bool ResourceFormatLoader::exists(const String &p_path) const {
+ return FileAccess::exists(p_path); //by default just check file
+}
RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error) {
String path = p_path;
@@ -239,6 +242,36 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
return res;
}
+bool ResourceLoader::exists(const String &p_path, const String &p_type_hint) {
+
+ String local_path;
+ if (p_path.is_rel_path())
+ local_path = "res://" + p_path;
+ else
+ local_path = ProjectSettings::get_singleton()->localize_path(p_path);
+
+ if (ResourceCache::has(local_path)) {
+
+ return false; //if cached, it probably exists i guess
+ }
+
+ bool xl_remapped = false;
+ String path = _path_remap(local_path, &xl_remapped);
+
+ // Try all loaders and pick the first match for the type hint
+ for (int i = 0; i < loader_count; i++) {
+
+ if (!loader[i]->recognize_path(path, p_type_hint)) {
+ continue;
+ }
+
+ if (loader[i]->exists(path))
+ return true;
+ }
+
+ return false;
+}
+
Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) {
if (r_error)
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 9be82abb42..f78464ef0c 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -60,6 +60,7 @@ class ResourceFormatLoader {
public:
virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
+ virtual bool exists(const String &p_path) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const;
@@ -106,6 +107,7 @@ class ResourceLoader {
public:
static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL);
static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL);
+ static bool exists(const String &p_path, const String &p_type_hint = "");
static void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions);
static void add_resource_format_loader(ResourceFormatLoader *p_format_loader, bool p_at_front = false);
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
new file mode 100644
index 0000000000..a161dbddba
--- /dev/null
+++ b/core/math/expression.cpp
@@ -0,0 +1,2136 @@
+#include "expression.h"
+
+#include "class_db.h"
+#include "func_ref.h"
+#include "io/marshalls.h"
+#include "math_funcs.h"
+#include "os/os.h"
+#include "reference.h"
+#include "variant_parser.h"
+
+const char *Expression::func_name[Expression::FUNC_MAX] = {
+ "sin",
+ "cos",
+ "tan",
+ "sinh",
+ "cosh",
+ "tanh",
+ "asin",
+ "acos",
+ "atan",
+ "atan2",
+ "sqrt",
+ "fmod",
+ "fposmod",
+ "floor",
+ "ceil",
+ "round",
+ "abs",
+ "sign",
+ "pow",
+ "log",
+ "exp",
+ "is_nan",
+ "is_inf",
+ "ease",
+ "decimals",
+ "stepify",
+ "lerp",
+ "inverse_lerp",
+ "range_lerp",
+ "dectime",
+ "randomize",
+ "randi",
+ "randf",
+ "rand_range",
+ "seed",
+ "rand_seed",
+ "deg2rad",
+ "rad2deg",
+ "linear2db",
+ "db2linear",
+ "polar2cartesian",
+ "cartesian2polar",
+ "wrapi",
+ "wrapf",
+ "max",
+ "min",
+ "clamp",
+ "nearest_po2",
+ "weakref",
+ "funcref",
+ "convert",
+ "typeof",
+ "type_exists",
+ "char",
+ "str",
+ "print",
+ "printerr",
+ "printraw",
+ "var2str",
+ "str2var",
+ "var2bytes",
+ "bytes2var",
+ "color_named",
+};
+
+Expression::BuiltinFunc Expression::find_function(const String &p_string) {
+
+ for (int i = 0; i < FUNC_MAX; i++) {
+ if (p_string == func_name[i])
+ return BuiltinFunc(i);
+ }
+
+ return FUNC_MAX;
+}
+
+String Expression::get_func_name(BuiltinFunc p_func) {
+
+ ERR_FAIL_INDEX_V(p_func, FUNC_MAX, String());
+ return func_name[p_func];
+}
+
+int Expression::get_func_argument_count(BuiltinFunc p_func) {
+
+ switch (p_func) {
+
+ case MATH_RANDOMIZE:
+ case MATH_RAND:
+ case MATH_RANDF:
+ return 0;
+ case MATH_SIN:
+ case MATH_COS:
+ case MATH_TAN:
+ case MATH_SINH:
+ case MATH_COSH:
+ case MATH_TANH:
+ case MATH_ASIN:
+ case MATH_ACOS:
+ case MATH_ATAN:
+ case MATH_SQRT:
+ case MATH_FLOOR:
+ case MATH_CEIL:
+ case MATH_ROUND:
+ case MATH_ABS:
+ case MATH_SIGN:
+ case MATH_LOG:
+ case MATH_EXP:
+ case MATH_ISNAN:
+ case MATH_ISINF:
+ case MATH_DECIMALS:
+ case MATH_SEED:
+ case MATH_RANDSEED:
+ case MATH_DEG2RAD:
+ case MATH_RAD2DEG:
+ case MATH_LINEAR2DB:
+ case MATH_DB2LINEAR:
+ case LOGIC_NEAREST_PO2:
+ case OBJ_WEAKREF:
+ case TYPE_OF:
+ case TEXT_CHAR:
+ case TEXT_STR:
+ case TEXT_PRINT:
+ case TEXT_PRINTERR:
+ case TEXT_PRINTRAW:
+ case VAR_TO_STR:
+ case STR_TO_VAR:
+ case VAR_TO_BYTES:
+ case BYTES_TO_VAR:
+ case TYPE_EXISTS:
+ return 1;
+ case MATH_ATAN2:
+ case MATH_FMOD:
+ case MATH_FPOSMOD:
+ case MATH_POW:
+ case MATH_EASE:
+ case MATH_STEPIFY:
+ case MATH_RANDOM:
+ case MATH_POLAR2CARTESIAN:
+ case MATH_CARTESIAN2POLAR:
+ case LOGIC_MAX:
+ case LOGIC_MIN:
+ case FUNC_FUNCREF:
+ case TYPE_CONVERT:
+ case COLORN:
+ return 2;
+ case MATH_LERP:
+ case MATH_INVERSE_LERP:
+ case MATH_DECTIME:
+ case MATH_WRAP:
+ case MATH_WRAPF:
+ case LOGIC_CLAMP:
+ return 3;
+ case MATH_RANGE_LERP:
+ return 5;
+ case FUNC_MAX: {
+ }
+ }
+ return 0;
+}
+
+#define VALIDATE_ARG_NUM(m_arg) \
+ if (!p_inputs[m_arg]->is_num()) { \
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; \
+ r_error.argument = m_arg; \
+ r_error.expected = Variant::REAL; \
+ return; \
+ }
+
+void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Variant::CallError &r_error, String &r_error_str) {
+
+ switch (p_func) {
+ case MATH_SIN: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::sin((double)*p_inputs[0]);
+ } break;
+ case MATH_COS: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::cos((double)*p_inputs[0]);
+ } break;
+ case MATH_TAN: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::tan((double)*p_inputs[0]);
+ } break;
+ case MATH_SINH: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::sinh((double)*p_inputs[0]);
+ } break;
+ case MATH_COSH: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::cosh((double)*p_inputs[0]);
+ } break;
+ case MATH_TANH: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::tanh((double)*p_inputs[0]);
+ } break;
+ case MATH_ASIN: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::asin((double)*p_inputs[0]);
+ } break;
+ case MATH_ACOS: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::acos((double)*p_inputs[0]);
+ } break;
+ case MATH_ATAN: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::atan((double)*p_inputs[0]);
+ } break;
+ case MATH_ATAN2: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *r_return = Math::atan2((double)*p_inputs[0], (double)*p_inputs[1]);
+ } break;
+ case MATH_SQRT: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::sqrt((double)*p_inputs[0]);
+ } break;
+ case MATH_FMOD: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *r_return = Math::fmod((double)*p_inputs[0], (double)*p_inputs[1]);
+ } break;
+ case MATH_FPOSMOD: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *r_return = Math::fposmod((double)*p_inputs[0], (double)*p_inputs[1]);
+ } break;
+ case MATH_FLOOR: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::floor((double)*p_inputs[0]);
+ } break;
+ case MATH_CEIL: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::ceil((double)*p_inputs[0]);
+ } break;
+ case MATH_ROUND: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::round((double)*p_inputs[0]);
+ } break;
+ case MATH_ABS: {
+
+ if (p_inputs[0]->get_type() == Variant::INT) {
+
+ int64_t i = *p_inputs[0];
+ *r_return = ABS(i);
+ } else if (p_inputs[0]->get_type() == Variant::REAL) {
+
+ real_t r = *p_inputs[0];
+ *r_return = Math::abs(r);
+ } else {
+
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::REAL;
+ }
+ } break;
+ case MATH_SIGN: {
+
+ if (p_inputs[0]->get_type() == Variant::INT) {
+
+ int64_t i = *p_inputs[0];
+ *r_return = i < 0 ? -1 : (i > 0 ? +1 : 0);
+ } else if (p_inputs[0]->get_type() == Variant::REAL) {
+
+ real_t r = *p_inputs[0];
+ *r_return = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0);
+ } else {
+
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::REAL;
+ }
+ } break;
+ case MATH_POW: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *r_return = Math::pow((double)*p_inputs[0], (double)*p_inputs[1]);
+ } break;
+ case MATH_LOG: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::log((double)*p_inputs[0]);
+ } break;
+ case MATH_EXP: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::exp((double)*p_inputs[0]);
+ } break;
+ case MATH_ISNAN: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::is_nan((double)*p_inputs[0]);
+ } break;
+ case MATH_ISINF: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::is_inf((double)*p_inputs[0]);
+ } break;
+ case MATH_EASE: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *r_return = Math::ease((double)*p_inputs[0], (double)*p_inputs[1]);
+ } break;
+ case MATH_DECIMALS: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::step_decimals((double)*p_inputs[0]);
+ } break;
+ case MATH_STEPIFY: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *r_return = Math::stepify((double)*p_inputs[0], (double)*p_inputs[1]);
+ } break;
+ case MATH_LERP: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
+ case MATH_INVERSE_LERP: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::inverse_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
+ case MATH_RANGE_LERP: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ VALIDATE_ARG_NUM(3);
+ 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_DECTIME: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::dectime((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
+ case MATH_RANDOMIZE: {
+ Math::randomize();
+
+ } break;
+ case MATH_RAND: {
+ *r_return = Math::rand();
+ } break;
+ case MATH_RANDF: {
+ *r_return = Math::randf();
+ } break;
+ case MATH_RANDOM: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *r_return = Math::random((double)*p_inputs[0], (double)*p_inputs[1]);
+ } break;
+ case MATH_SEED: {
+
+ VALIDATE_ARG_NUM(0);
+ uint64_t seed = *p_inputs[0];
+ Math::seed(seed);
+
+ } break;
+ case MATH_RANDSEED: {
+
+ VALIDATE_ARG_NUM(0);
+ uint64_t seed = *p_inputs[0];
+ int ret = Math::rand_from_seed(&seed);
+ Array reta;
+ reta.push_back(ret);
+ reta.push_back(seed);
+ *r_return = reta;
+
+ } break;
+ case MATH_DEG2RAD: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::deg2rad((double)*p_inputs[0]);
+ } break;
+ case MATH_RAD2DEG: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::rad2deg((double)*p_inputs[0]);
+ } break;
+ case MATH_LINEAR2DB: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::linear2db((double)*p_inputs[0]);
+ } break;
+ case MATH_DB2LINEAR: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::db2linear((double)*p_inputs[0]);
+ } break;
+ case MATH_POLAR2CARTESIAN: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ double r = *p_inputs[0];
+ double th = *p_inputs[1];
+ *r_return = Vector2(r * Math::cos(th), r * Math::sin(th));
+ } break;
+ case MATH_CARTESIAN2POLAR: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ double x = *p_inputs[0];
+ double y = *p_inputs[1];
+ *r_return = Vector2(Math::sqrt(x * x + y * y), Math::atan2(y, x));
+ } break;
+ case MATH_WRAP: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::wrapi((int64_t)*p_inputs[0], (int64_t)*p_inputs[1], (int64_t)*p_inputs[2]);
+ } break;
+ case MATH_WRAPF: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::wrapf((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
+ case LOGIC_MAX: {
+
+ if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) {
+
+ int64_t a = *p_inputs[0];
+ int64_t b = *p_inputs[1];
+ *r_return = MAX(a, b);
+ } else {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+
+ real_t a = *p_inputs[0];
+ real_t b = *p_inputs[1];
+
+ *r_return = MAX(a, b);
+ }
+
+ } break;
+ case LOGIC_MIN: {
+
+ if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) {
+
+ int64_t a = *p_inputs[0];
+ int64_t b = *p_inputs[1];
+ *r_return = MIN(a, b);
+ } else {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+
+ real_t a = *p_inputs[0];
+ real_t b = *p_inputs[1];
+
+ *r_return = MIN(a, b);
+ }
+ } break;
+ case LOGIC_CLAMP: {
+
+ if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT && p_inputs[2]->get_type() == Variant::INT) {
+
+ int64_t a = *p_inputs[0];
+ int64_t b = *p_inputs[1];
+ int64_t c = *p_inputs[2];
+ *r_return = CLAMP(a, b, c);
+ } else {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+
+ real_t a = *p_inputs[0];
+ real_t b = *p_inputs[1];
+ real_t c = *p_inputs[2];
+
+ *r_return = CLAMP(a, b, c);
+ }
+ } break;
+ case LOGIC_NEAREST_PO2: {
+
+ VALIDATE_ARG_NUM(0);
+ int64_t num = *p_inputs[0];
+ *r_return = next_power_of_2(num);
+ } break;
+ case OBJ_WEAKREF: {
+
+ if (p_inputs[0]->get_type() != Variant::OBJECT) {
+
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+
+ return;
+ }
+
+ if (p_inputs[0]->is_ref()) {
+
+ REF r = *p_inputs[0];
+ if (!r.is_valid()) {
+
+ return;
+ }
+
+ Ref<WeakRef> wref = memnew(WeakRef);
+ wref->set_ref(r);
+ *r_return = wref;
+ } else {
+ Object *obj = *p_inputs[0];
+ if (!obj) {
+
+ return;
+ }
+ Ref<WeakRef> wref = memnew(WeakRef);
+ wref->set_obj(obj);
+ *r_return = wref;
+ }
+
+ } break;
+ case FUNC_FUNCREF: {
+
+ if (p_inputs[0]->get_type() != Variant::OBJECT) {
+
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+
+ return;
+ }
+ if (p_inputs[1]->get_type() != Variant::STRING && p_inputs[1]->get_type() != Variant::NODE_PATH) {
+
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::STRING;
+
+ return;
+ }
+
+ Ref<FuncRef> fr = memnew(FuncRef);
+
+ fr->set_instance(*p_inputs[0]);
+ fr->set_function(*p_inputs[1]);
+
+ *r_return = fr;
+
+ } break;
+ case TYPE_CONVERT: {
+
+ VALIDATE_ARG_NUM(1);
+ int type = *p_inputs[1];
+ if (type < 0 || type >= Variant::VARIANT_MAX) {
+
+ r_error_str = RTR("Invalid type argument to convert(), use TYPE_* constants.");
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::INT;
+ return;
+
+ } else {
+
+ *r_return = Variant::construct(Variant::Type(type), p_inputs, 1, r_error);
+ }
+ } break;
+ case TYPE_OF: {
+
+ *r_return = p_inputs[0]->get_type();
+
+ } break;
+ case TYPE_EXISTS: {
+
+ *r_return = ClassDB::class_exists(*p_inputs[0]);
+
+ } break;
+ case TEXT_CHAR: {
+
+ CharType result[2] = { *p_inputs[0], 0 };
+
+ *r_return = String(result);
+
+ } break;
+ case TEXT_STR: {
+
+ String str = *p_inputs[0];
+
+ *r_return = str;
+
+ } break;
+ case TEXT_PRINT: {
+
+ String str = *p_inputs[0];
+ print_line(str);
+
+ } break;
+
+ case TEXT_PRINTERR: {
+
+ String str = *p_inputs[0];
+
+ //str+="\n";
+ print_error(str);
+
+ } break;
+ case TEXT_PRINTRAW: {
+ String str = *p_inputs[0];
+
+ //str+="\n";
+ OS::get_singleton()->print("%s", str.utf8().get_data());
+
+ } break;
+ case VAR_TO_STR: {
+
+ String vars;
+ VariantWriter::write_to_string(*p_inputs[0], vars);
+ *r_return = vars;
+ } break;
+ case STR_TO_VAR: {
+
+ if (p_inputs[0]->get_type() != Variant::STRING) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+
+ return;
+ }
+
+ VariantParser::StreamString ss;
+ ss.s = *p_inputs[0];
+
+ String errs;
+ int line;
+ Error err = VariantParser::parse(&ss, *r_return, errs, line);
+
+ if (err != OK) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ *r_return = "Parse error at line " + itos(line) + ": " + errs;
+ return;
+ }
+
+ } break;
+ case VAR_TO_BYTES: {
+
+ PoolByteArray barr;
+ int len;
+ Error err = encode_variant(*p_inputs[0], NULL, len);
+ if (err) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ r_error_str = "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).";
+ return;
+ }
+
+ barr.resize(len);
+ {
+ PoolByteArray::Write w = barr.write();
+ encode_variant(*p_inputs[0], w.ptr(), len);
+ }
+ *r_return = barr;
+ } break;
+ case BYTES_TO_VAR: {
+
+ if (p_inputs[0]->get_type() != Variant::POOL_BYTE_ARRAY) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::POOL_BYTE_ARRAY;
+
+ return;
+ }
+
+ PoolByteArray varr = *p_inputs[0];
+ Variant ret;
+ {
+ PoolByteArray::Read r = varr.read();
+ Error err = decode_variant(ret, r.ptr(), varr.size(), NULL);
+ if (err != OK) {
+ r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format.");
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::POOL_BYTE_ARRAY;
+ return;
+ }
+ }
+
+ *r_return = ret;
+
+ } break;
+ case COLORN: {
+
+ VALIDATE_ARG_NUM(1);
+
+ Color color = Color::named(*p_inputs[0]);
+ color.a = *p_inputs[1];
+
+ *r_return = String(color);
+
+ } break;
+ default: {}
+ }
+}
+
+////////
+
+Error Expression::_get_token(Token &r_token) {
+
+ while (true) {
+#define GET_CHAR() (str_ofs >= expression.length() ? 0 : expression[str_ofs++])
+
+ CharType cchar = GET_CHAR();
+ if (cchar == 0) {
+ r_token.type = TK_EOF;
+ return OK;
+ }
+
+ switch (cchar) {
+
+ case 0: {
+ r_token.type = TK_EOF;
+ return OK;
+ } break;
+ case '{': {
+
+ r_token.type = TK_CURLY_BRACKET_OPEN;
+ return OK;
+ };
+ case '}': {
+
+ r_token.type = TK_CURLY_BRACKET_CLOSE;
+ return OK;
+ };
+ case '[': {
+
+ r_token.type = TK_BRACKET_OPEN;
+ return OK;
+ };
+ case ']': {
+
+ r_token.type = TK_BRACKET_CLOSE;
+ return OK;
+ };
+ case '(': {
+
+ r_token.type = TK_PARENTHESIS_OPEN;
+ return OK;
+ };
+ case ')': {
+
+ r_token.type = TK_PARENTHESIS_CLOSE;
+ return OK;
+ };
+ case ',': {
+
+ r_token.type = TK_COMMA;
+ return OK;
+ };
+ case ':': {
+
+ r_token.type = TK_COLON;
+ return OK;
+ };
+ case '.': {
+
+ r_token.type = TK_PERIOD;
+ return OK;
+ };
+ case '$': {
+
+ r_token.type = TK_INPUT;
+ int index = 0;
+ do {
+ if (expression[str_ofs] < '0' || expression[str_ofs] > '9') {
+ _set_error("Expected number after '$'");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ index *= 10;
+ index += expression[str_ofs] - '0';
+ str_ofs++;
+
+ } while (expression[str_ofs] >= '0' && expression[str_ofs] <= '9');
+
+ r_token.value = index;
+ return OK;
+ };
+ case '=': {
+
+ cchar = GET_CHAR();
+ if (cchar == '=') {
+ r_token.type = TK_OP_EQUAL;
+ } else {
+ _set_error("Expected '='");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ return OK;
+ };
+ case '!': {
+
+ if (expression[str_ofs] == '=') {
+ r_token.type = TK_OP_NOT_EQUAL;
+ str_ofs++;
+ } else {
+ r_token.type = TK_OP_NOT;
+ }
+ return OK;
+ };
+ case '>': {
+
+ if (expression[str_ofs] == '=') {
+ r_token.type = TK_OP_GREATER_EQUAL;
+ str_ofs++;
+ } else if (expression[str_ofs] == '>') {
+ r_token.type = TK_OP_SHIFT_RIGHT;
+ str_ofs++;
+ } else {
+ r_token.type = TK_OP_GREATER;
+ }
+ return OK;
+ };
+ case '<': {
+
+ if (expression[str_ofs] == '=') {
+ r_token.type = TK_OP_LESS_EQUAL;
+ str_ofs++;
+ } else if (expression[str_ofs] == '<') {
+ r_token.type = TK_OP_SHIFT_LEFT;
+ str_ofs++;
+ } else {
+ r_token.type = TK_OP_LESS;
+ }
+ return OK;
+ };
+ case '+': {
+ r_token.type = TK_OP_ADD;
+ return OK;
+ };
+ case '-': {
+ r_token.type = TK_OP_SUB;
+ return OK;
+ };
+ case '/': {
+ r_token.type = TK_OP_DIV;
+ return OK;
+ };
+ case '*': {
+ r_token.type = TK_OP_MUL;
+ return OK;
+ };
+ case '%': {
+ r_token.type = TK_OP_MOD;
+ return OK;
+ };
+ case '&': {
+
+ if (expression[str_ofs] == '&') {
+ r_token.type = TK_OP_AND;
+ str_ofs++;
+ } else {
+ r_token.type = TK_OP_BIT_AND;
+ }
+ return OK;
+ };
+ case '|': {
+
+ if (expression[str_ofs] == '|') {
+ r_token.type = TK_OP_OR;
+ str_ofs++;
+ } else {
+ r_token.type = TK_OP_BIT_OR;
+ }
+ return OK;
+ };
+ case '^': {
+
+ r_token.type = TK_OP_BIT_XOR;
+
+ return OK;
+ };
+ case '~': {
+
+ r_token.type = TK_OP_BIT_INVERT;
+
+ return OK;
+ };
+ case '"': {
+
+ String str;
+ while (true) {
+
+ CharType ch = GET_CHAR();
+
+ if (ch == 0) {
+ _set_error("Unterminated String");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ } else if (ch == '"') {
+ break;
+ } else if (ch == '\\') {
+ //escaped characters...
+
+ CharType next = GET_CHAR();
+ if (next == 0) {
+ _set_error("Unterminated String");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ CharType res = 0;
+
+ switch (next) {
+
+ case 'b': res = 8; break;
+ case 't': res = 9; break;
+ case 'n': res = 10; break;
+ case 'f': res = 12; break;
+ case 'r': res = 13; break;
+ case 'u': {
+ //hexnumbarh - oct is deprecated
+
+ for (int j = 0; j < 4; j++) {
+ CharType c = GET_CHAR();
+
+ if (c == 0) {
+ _set_error("Unterminated String");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
+
+ _set_error("Malformed hex constant in string");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ CharType v;
+ if (c >= '0' && c <= '9') {
+ v = c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ v = c - 'a';
+ v += 10;
+ } else if (c >= 'A' && c <= 'F') {
+ v = c - 'A';
+ v += 10;
+ } else {
+ ERR_PRINT("BUG");
+ v = 0;
+ }
+
+ res <<= 4;
+ res |= v;
+ }
+
+ } break;
+ //case '\"': res='\"'; break;
+ //case '\\': res='\\'; break;
+ //case '/': res='/'; break;
+ default: {
+ res = next;
+ //r_err_str="Invalid escape sequence";
+ //return ERR_PARSE_ERROR;
+ } break;
+ }
+
+ str += res;
+
+ } else {
+ str += ch;
+ }
+ }
+
+ r_token.type = TK_CONSTANT;
+ r_token.value = str;
+ return OK;
+
+ } break;
+ default: {
+
+ if (cchar <= 32) {
+ break;
+ }
+
+ if (cchar >= '0' && cchar <= '9') {
+ //a number
+
+ String num;
+#define READING_SIGN 0
+#define READING_INT 1
+#define READING_DEC 2
+#define READING_EXP 3
+#define READING_DONE 4
+ int reading = READING_INT;
+
+ CharType c = cchar;
+ bool exp_sign = false;
+ bool exp_beg = false;
+ bool is_float = false;
+
+ while (true) {
+
+ switch (reading) {
+ case READING_INT: {
+
+ if (c >= '0' && c <= '9') {
+ //pass
+ } else if (c == '.') {
+ reading = READING_DEC;
+ is_float = true;
+ } else if (c == 'e') {
+ reading = READING_EXP;
+ } else {
+ reading = READING_DONE;
+ }
+
+ } break;
+ case READING_DEC: {
+
+ if (c >= '0' && c <= '9') {
+
+ } else if (c == 'e') {
+ reading = READING_EXP;
+
+ } else {
+ reading = READING_DONE;
+ }
+
+ } break;
+ case READING_EXP: {
+
+ if (c >= '0' && c <= '9') {
+ exp_beg = true;
+
+ } else if ((c == '-' || c == '+') && !exp_sign && !exp_beg) {
+ if (c == '-')
+ is_float = true;
+ exp_sign = true;
+
+ } else {
+ reading = READING_DONE;
+ }
+ } break;
+ }
+
+ if (reading == READING_DONE)
+ break;
+ num += String::chr(c);
+ c = GET_CHAR();
+ }
+
+ str_ofs--;
+
+ r_token.type = TK_CONSTANT;
+
+ if (is_float)
+ r_token.value = num.to_double();
+ else
+ r_token.value = num.to_int();
+ return OK;
+
+ } else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') {
+
+ String id;
+ bool first = true;
+
+ while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && cchar >= '0' && cchar <= '9')) {
+
+ id += String::chr(cchar);
+ cchar = GET_CHAR();
+ first = false;
+ }
+
+ str_ofs--; //go back one
+
+ if (id == "in") {
+ r_token.type = TK_OP_IN;
+ } else if (id == "null") {
+ r_token.type = TK_CONSTANT;
+ r_token.value = Variant();
+ } else if (id == "true") {
+ r_token.type = TK_CONSTANT;
+ r_token.value = true;
+ } else if (id == "false") {
+ r_token.type = TK_CONSTANT;
+ r_token.value = false;
+ } else if (id == "PI") {
+ r_token.type = TK_CONSTANT;
+ r_token.value = Math_PI;
+ } else if (id == "TAU") {
+ r_token.type = TK_CONSTANT;
+ r_token.value = Math_TAU;
+ } else if (id == "INF") {
+ r_token.type = TK_CONSTANT;
+ r_token.value = Math_INF;
+ } else if (id == "NAN") {
+ r_token.type = TK_CONSTANT;
+ r_token.value = Math_NAN;
+ } else if (id == "not") {
+ r_token.type = TK_OP_NOT;
+ } else if (id == "or") {
+ r_token.type = TK_OP_OR;
+ } else if (id == "and") {
+ r_token.type = TK_OP_AND;
+ } else if (id == "self") {
+ r_token.type = TK_SELF;
+ } else {
+
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ if (id == Variant::get_type_name(Variant::Type(i))) {
+ r_token.type = TK_BASIC_TYPE;
+ r_token.value = i;
+ return OK;
+ }
+ }
+
+ BuiltinFunc bifunc = find_function(id);
+ if (bifunc != FUNC_MAX) {
+ r_token.type = TK_BUILTIN_FUNC;
+ r_token.value = bifunc;
+ return OK;
+ }
+
+ r_token.type = TK_IDENTIFIER;
+ r_token.value = id;
+ }
+
+ return OK;
+ } else {
+ _set_error("Unexpected character.");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ }
+ }
+ }
+
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+}
+
+const char *Expression::token_name[TK_MAX] = {
+ "CURLY BRACKET OPEN",
+ "CURLY BRACKET CLOSE",
+ "BRACKET OPEN",
+ "BRACKET CLOSE",
+ "PARENTHESIS OPEN",
+ "PARENTHESIS CLOSE",
+ "IDENTIFIER",
+ "BUILTIN FUNC",
+ "SELF",
+ "CONSTANT",
+ "BASIC TYPE",
+ "COLON",
+ "COMMA",
+ "PERIOD",
+ "OP IN",
+ "OP EQUAL",
+ "OP NOT EQUAL",
+ "OP LESS",
+ "OP LESS EQUAL",
+ "OP GREATER",
+ "OP GREATER EQUAL",
+ "OP AND",
+ "OP OR",
+ "OP NOT",
+ "OP ADD",
+ "OP SUB",
+ "OP MUL",
+ "OP DIV",
+ "OP MOD",
+ "OP SHIFT LEFT",
+ "OP SHIFT RIGHT",
+ "OP BIT AND",
+ "OP BIT OR",
+ "OP BIT XOR",
+ "OP BIT INVERT",
+ "OP INPUT",
+ "EOF",
+ "ERROR"
+};
+
+Expression::ENode *Expression::_parse_expression() {
+
+ Vector<ExpressionNode> expression;
+
+ while (true) {
+ //keep appending stuff to expression
+ ENode *expr = NULL;
+
+ Token tk;
+ _get_token(tk);
+ if (error_set)
+ return NULL;
+
+ switch (tk.type) {
+ case TK_CURLY_BRACKET_OPEN: {
+ //a dictionary
+ DictionaryNode *dn = alloc_node<DictionaryNode>();
+
+ while (true) {
+
+ int cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_CURLY_BRACKET_CLOSE) {
+ break;
+ }
+ str_ofs = cofs; //revert
+ //parse an expression
+ ENode *expr = _parse_expression();
+ if (!expr)
+ return NULL;
+ dn->dict.push_back(expr);
+
+ _get_token(tk);
+ if (tk.type != TK_COLON) {
+ _set_error("Expected ':'");
+ return NULL;
+ }
+
+ expr = _parse_expression();
+ if (!expr)
+ return NULL;
+
+ dn->dict.push_back(expr);
+
+ cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_COMMA) {
+ //all good
+ } else if (tk.type == TK_CURLY_BRACKET_CLOSE) {
+ str_ofs = cofs;
+ } else {
+ _set_error("Expected ',' or '}'");
+ }
+ }
+
+ expr = dn;
+ } break;
+ case TK_BRACKET_OPEN: {
+ //an array
+
+ ArrayNode *an = alloc_node<ArrayNode>();
+
+ while (true) {
+
+ int cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_BRACKET_CLOSE) {
+ break;
+ }
+ str_ofs = cofs; //revert
+ //parse an expression
+ ENode *expr = _parse_expression();
+ if (!expr)
+ return NULL;
+ an->array.push_back(expr);
+
+ cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_COMMA) {
+ //all good
+ } else if (tk.type == TK_BRACKET_CLOSE) {
+ str_ofs = cofs;
+ } else {
+ _set_error("Expected ',' or ']'");
+ }
+ }
+
+ expr = an;
+ } break;
+ case TK_PARENTHESIS_OPEN: {
+ //a suexpression
+ ENode *e = _parse_expression();
+ if (error_set)
+ return NULL;
+ _get_token(tk);
+ if (tk.type != TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ')'");
+ return NULL;
+ }
+
+ expr = e;
+
+ } break;
+ case TK_IDENTIFIER: {
+
+ String identifier = tk.value;
+
+ int cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_PARENTHESIS_OPEN) {
+ //function call
+ CallNode *func_call = alloc_node<CallNode>();
+ func_call->method = identifier;
+ SelfNode *self_node = alloc_node<SelfNode>();
+ func_call->base = self_node;
+
+ while (true) {
+
+ int cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_PARENTHESIS_CLOSE) {
+ break;
+ }
+ str_ofs = cofs; //revert
+ //parse an expression
+ ENode *expr = _parse_expression();
+ if (!expr)
+ return NULL;
+
+ func_call->arguments.push_back(expr);
+
+ cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_COMMA) {
+ //all good
+ } else if (tk.type == TK_PARENTHESIS_CLOSE) {
+ str_ofs = cofs;
+ } else {
+ _set_error("Expected ',' or ')'");
+ }
+ }
+
+ expr = func_call;
+ } else {
+ //named indexing
+ str_ofs = cofs;
+
+ int input_index = -1;
+ for (int i = 0; i < input_names.size(); i++) {
+ if (input_names[i] == identifier) {
+ input_index = i;
+ break;
+ }
+ }
+
+ if (input_index != -1) {
+ InputNode *input = alloc_node<InputNode>();
+ input->index = input_index;
+ expr = input;
+ } else {
+
+ NamedIndexNode *index = alloc_node<NamedIndexNode>();
+ SelfNode *self_node = alloc_node<SelfNode>();
+ index->base = self_node;
+ index->name = identifier;
+ expr = index;
+ }
+ }
+ } break;
+ case TK_INPUT: {
+
+ InputNode *input = alloc_node<InputNode>();
+ input->index = tk.value;
+ expr = input;
+ } break;
+ case TK_SELF: {
+
+ SelfNode *self = alloc_node<SelfNode>();
+ expr = self;
+ } break;
+ case TK_CONSTANT: {
+ ConstantNode *constant = alloc_node<ConstantNode>();
+ constant->value = tk.value;
+ expr = constant;
+ } break;
+ case TK_BASIC_TYPE: {
+ //constructor..
+
+ Variant::Type bt = Variant::Type(int(tk.value));
+ _get_token(tk);
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '('");
+ return NULL;
+ }
+
+ ConstructorNode *constructor = alloc_node<ConstructorNode>();
+ constructor->data_type = bt;
+
+ while (true) {
+
+ int cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_PARENTHESIS_CLOSE) {
+ break;
+ }
+ str_ofs = cofs; //revert
+ //parse an expression
+ ENode *expr = _parse_expression();
+ if (!expr)
+ return NULL;
+
+ constructor->arguments.push_back(expr);
+
+ cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_COMMA) {
+ //all good
+ } else if (tk.type == TK_PARENTHESIS_CLOSE) {
+ str_ofs = cofs;
+ } else {
+ _set_error("Expected ',' or ')'");
+ }
+ }
+
+ expr = constructor;
+
+ } break;
+ case TK_BUILTIN_FUNC: {
+ //builtin function
+
+ _get_token(tk);
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '('");
+ return NULL;
+ }
+
+ BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>();
+ bifunc->func = BuiltinFunc(int(tk.value));
+
+ while (true) {
+
+ int cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_PARENTHESIS_CLOSE) {
+ break;
+ }
+ str_ofs = cofs; //revert
+ //parse an expression
+ ENode *expr = _parse_expression();
+ if (!expr)
+ return NULL;
+
+ bifunc->arguments.push_back(expr);
+
+ cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_COMMA) {
+ //all good
+ } else if (tk.type == TK_PARENTHESIS_CLOSE) {
+ str_ofs = cofs;
+ } else {
+ _set_error("Expected ',' or ')'");
+ }
+ }
+
+ int expected_args = get_func_argument_count(bifunc->func);
+ if (bifunc->arguments.size() != expected_args) {
+ _set_error("Builtin func '" + get_func_name(bifunc->func) + "' expects " + itos(expected_args) + " arguments.");
+ }
+
+ expr = bifunc;
+
+ } break;
+ case TK_OP_SUB: {
+
+ ExpressionNode e;
+ e.is_op = true;
+ e.op = Variant::OP_NEGATE;
+ expression.push_back(e);
+ continue;
+ } break;
+ case TK_OP_NOT: {
+
+ ExpressionNode e;
+ e.is_op = true;
+ e.op = Variant::OP_NOT;
+ expression.push_back(e);
+ continue;
+ } break;
+
+ default: {
+ _set_error("Expected expression.");
+ return NULL;
+ } break;
+ }
+
+ //before going to operators, must check indexing!
+
+ while (true) {
+ int cofs2 = str_ofs;
+ _get_token(tk);
+ if (error_set)
+ return NULL;
+
+ bool done = false;
+
+ switch (tk.type) {
+ case TK_BRACKET_OPEN: {
+ //value indexing
+
+ IndexNode *index = alloc_node<IndexNode>();
+ index->base = expr;
+
+ ENode *what = _parse_expression();
+ if (!what)
+ return NULL;
+
+ index->index = what;
+
+ _get_token(tk);
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']' at end of index.");
+ return NULL;
+ }
+ expr = index;
+
+ } break;
+ case TK_PERIOD: {
+ //named indexing or function call
+ _get_token(tk);
+ if (tk.type != TK_IDENTIFIER) {
+ _set_error("Expected identifier after '.'");
+ return NULL;
+ }
+
+ StringName identifier = tk.value;
+
+ int cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_PARENTHESIS_OPEN) {
+ //function call
+ CallNode *func_call = alloc_node<CallNode>();
+ func_call->method = identifier;
+ func_call->base = expr;
+
+ while (true) {
+
+ int cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_PARENTHESIS_CLOSE) {
+ break;
+ }
+ str_ofs = cofs; //revert
+ //parse an expression
+ ENode *expr = _parse_expression();
+ if (!expr)
+ return NULL;
+
+ func_call->arguments.push_back(expr);
+
+ cofs = str_ofs;
+ _get_token(tk);
+ if (tk.type == TK_COMMA) {
+ //all good
+ } else if (tk.type == TK_PARENTHESIS_CLOSE) {
+ str_ofs = cofs;
+ } else {
+ _set_error("Expected ',' or ')'");
+ }
+ }
+
+ expr = func_call;
+ } else {
+ //named indexing
+ str_ofs = cofs;
+
+ NamedIndexNode *index = alloc_node<NamedIndexNode>();
+ index->base = expr;
+ index->name = identifier;
+ expr = index;
+ }
+
+ } break;
+ default: {
+ str_ofs = cofs2;
+ done = true;
+ } break;
+ }
+
+ if (done)
+ break;
+ }
+
+ //push expression
+ {
+ ExpressionNode e;
+ e.is_op = false;
+ e.node = expr;
+ expression.push_back(e);
+ }
+
+ //ok finally look for an operator
+
+ int cofs = str_ofs;
+ _get_token(tk);
+ if (error_set)
+ return NULL;
+
+ Variant::Operator op = Variant::OP_MAX;
+
+ switch (tk.type) {
+ case TK_OP_IN: op = Variant::OP_IN; break;
+ case TK_OP_EQUAL: op = Variant::OP_EQUAL; break;
+ case TK_OP_NOT_EQUAL: op = Variant::OP_NOT_EQUAL; break;
+ case TK_OP_LESS: op = Variant::OP_LESS; break;
+ case TK_OP_LESS_EQUAL: op = Variant::OP_LESS_EQUAL; break;
+ case TK_OP_GREATER: op = Variant::OP_GREATER; break;
+ case TK_OP_GREATER_EQUAL: op = Variant::OP_GREATER_EQUAL; break;
+ case TK_OP_AND: op = Variant::OP_AND; break;
+ case TK_OP_OR: op = Variant::OP_OR; break;
+ case TK_OP_NOT: op = Variant::OP_NOT; break;
+ case TK_OP_ADD: op = Variant::OP_ADD; break;
+ case TK_OP_SUB: op = Variant::OP_SUBTRACT; break;
+ case TK_OP_MUL: op = Variant::OP_MULTIPLY; break;
+ case TK_OP_DIV: op = Variant::OP_DIVIDE; break;
+ case TK_OP_MOD: op = Variant::OP_MODULE; break;
+ case TK_OP_SHIFT_LEFT: op = Variant::OP_SHIFT_LEFT; break;
+ case TK_OP_SHIFT_RIGHT: op = Variant::OP_SHIFT_RIGHT; break;
+ case TK_OP_BIT_AND: op = Variant::OP_BIT_AND; break;
+ case TK_OP_BIT_OR: op = Variant::OP_BIT_OR; break;
+ case TK_OP_BIT_XOR: op = Variant::OP_BIT_XOR; break;
+ case TK_OP_BIT_INVERT: op = Variant::OP_BIT_NEGATE; break;
+ default: {};
+ }
+
+ if (op == Variant::OP_MAX) { //stop appending stuff
+ str_ofs = cofs;
+ break;
+ }
+
+ //push operator and go on
+ {
+ ExpressionNode e;
+ e.is_op = true;
+ e.op = op;
+ expression.push_back(e);
+ }
+ }
+
+ /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */
+
+ while (expression.size() > 1) {
+
+ int next_op = -1;
+ int min_priority = 0xFFFFF;
+ bool is_unary = false;
+
+ for (int i = 0; i < expression.size(); i++) {
+
+ if (!expression[i].is_op) {
+
+ continue;
+ }
+
+ int priority;
+
+ bool unary = false;
+
+ switch (expression[i].op) {
+
+ case Variant::OP_BIT_NEGATE:
+ priority = 0;
+ unary = true;
+ break;
+ case Variant::OP_NEGATE:
+ priority = 1;
+ unary = true;
+ break;
+
+ case Variant::OP_MULTIPLY: priority = 2; break;
+ case Variant::OP_DIVIDE: priority = 2; break;
+ case Variant::OP_MODULE: priority = 2; break;
+
+ case Variant::OP_ADD: priority = 3; break;
+ case Variant::OP_SUBTRACT: priority = 3; break;
+
+ case Variant::OP_SHIFT_LEFT: priority = 4; break;
+ case Variant::OP_SHIFT_RIGHT: priority = 4; break;
+
+ case Variant::OP_BIT_AND: priority = 5; break;
+ case Variant::OP_BIT_XOR: priority = 6; break;
+ case Variant::OP_BIT_OR: priority = 7; break;
+
+ case Variant::OP_LESS: priority = 8; break;
+ case Variant::OP_LESS_EQUAL: priority = 8; break;
+ case Variant::OP_GREATER: priority = 8; break;
+ case Variant::OP_GREATER_EQUAL: priority = 8; break;
+
+ case Variant::OP_EQUAL: priority = 8; break;
+ case Variant::OP_NOT_EQUAL: priority = 8; break;
+
+ case Variant::OP_IN: priority = 10; break;
+
+ case Variant::OP_NOT:
+ priority = 11;
+ unary = true;
+ break;
+ case Variant::OP_AND: priority = 12; break;
+ case Variant::OP_OR: priority = 13; break;
+
+ default: {
+ _set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op));
+ return NULL;
+ }
+ }
+
+ if (priority < min_priority) {
+ // < is used for left to right (default)
+ // <= is used for right to left
+
+ next_op = i;
+ min_priority = priority;
+ is_unary = unary;
+ }
+ }
+
+ if (next_op == -1) {
+
+ _set_error("Yet another parser bug....");
+ ERR_FAIL_COND_V(next_op == -1, NULL);
+ }
+
+ // OK! create operator..
+ if (is_unary) {
+
+ int expr_pos = next_op;
+ while (expression[expr_pos].is_op) {
+
+ expr_pos++;
+ if (expr_pos == expression.size()) {
+ //can happen..
+ _set_error("Unexpected end of expression...");
+ return NULL;
+ }
+ }
+
+ //consecutively do unary opeators
+ for (int i = expr_pos - 1; i >= next_op; i--) {
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op = expression[i].op;
+ op->nodes[0] = expression[i + 1].node;
+ op->nodes[1] = NULL;
+ expression.write[i].is_op = false;
+ expression.write[i].node = op;
+ expression.remove(i + 1);
+ }
+
+ } else {
+
+ if (next_op < 1 || next_op >= (expression.size() - 1)) {
+ _set_error("Parser bug...");
+ ERR_FAIL_V(NULL);
+ }
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op = expression[next_op].op;
+
+ if (expression[next_op - 1].is_op) {
+
+ _set_error("Parser bug...");
+ ERR_FAIL_V(NULL);
+ }
+
+ if (expression[next_op + 1].is_op) {
+ // this is not invalid and can really appear
+ // but it becomes invalid anyway because no binary op
+ // can be followed by a unary op in a valid combination,
+ // due to how precedence works, unaries will always disappear first
+
+ _set_error("Unexpected two consecutive operators.");
+ return NULL;
+ }
+
+ op->nodes[0] = expression[next_op - 1].node; //expression goes as left
+ op->nodes[1] = expression[next_op + 1].node; //next expression goes as right
+
+ //replace all 3 nodes by this operator and make it an expression
+ expression.write[next_op - 1].node = op;
+ expression.remove(next_op);
+ expression.remove(next_op);
+ }
+ }
+
+ return expression[0].node;
+}
+
+bool Expression::_compile_expression() {
+
+ if (!expression_dirty)
+ return error_set;
+
+ if (nodes) {
+ memdelete(nodes);
+ nodes = NULL;
+ root = NULL;
+ }
+
+ error_str = String();
+ error_set = false;
+ str_ofs = 0;
+
+ root = _parse_expression();
+
+ if (error_set) {
+ root = NULL;
+ if (nodes) {
+ memdelete(nodes);
+ }
+ nodes = NULL;
+ return true;
+ }
+
+ expression_dirty = false;
+ return false;
+}
+
+bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str) {
+
+ switch (p_node->type) {
+ case Expression::ENode::TYPE_INPUT: {
+
+ const Expression::InputNode *in = static_cast<const Expression::InputNode *>(p_node);
+ if (in->index < 0 || in->index >= p_inputs.size()) {
+ r_error_str = vformat(RTR("Invalid input %i (not passed) in expression"), in->index);
+ return true;
+ }
+ r_ret = p_inputs[in->index];
+ } break;
+ case Expression::ENode::TYPE_CONSTANT: {
+
+ const Expression::ConstantNode *c = static_cast<const Expression::ConstantNode *>(p_node);
+ r_ret = c->value;
+
+ } break;
+ case Expression::ENode::TYPE_SELF: {
+
+ if (!p_instance) {
+ r_error_str = RTR("self can't be used because instance is null (not passed)");
+ return true;
+ }
+ r_ret = p_instance;
+ } break;
+ case Expression::ENode::TYPE_OPERATOR: {
+
+ const Expression::OperatorNode *op = static_cast<const Expression::OperatorNode *>(p_node);
+
+ Variant a;
+ bool ret = _execute(p_inputs, p_instance, op->nodes[0], a, r_error_str);
+ if (ret)
+ return true;
+
+ Variant b;
+
+ if (op->nodes[1]) {
+ bool ret = _execute(p_inputs, p_instance, op->nodes[1], b, r_error_str);
+ if (ret)
+ return true;
+ }
+
+ bool valid = true;
+ Variant::evaluate(op->op, a, b, r_ret, valid);
+ if (!valid) {
+ r_error_str = vformat(RTR("Invalid operands to operator %s, %s and %s."), Variant::get_operator_name(op->op), Variant::get_type_name(a.get_type()), Variant::get_type_name(b.get_type()));
+ return true;
+ }
+
+ } break;
+ case Expression::ENode::TYPE_INDEX: {
+
+ const Expression::IndexNode *index = static_cast<const Expression::IndexNode *>(p_node);
+
+ Variant base;
+ bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str);
+ if (ret)
+ return true;
+
+ Variant idx;
+
+ ret = _execute(p_inputs, p_instance, index->index, idx, r_error_str);
+ if (ret)
+ return true;
+
+ bool valid;
+ r_ret = base.get(idx, &valid);
+ if (!valid) {
+ r_error_str = vformat(RTR("Invalid index of type %s for base type %s"), Variant::get_type_name(idx.get_type()), Variant::get_type_name(base.get_type()));
+ return true;
+ }
+
+ } break;
+ case Expression::ENode::TYPE_NAMED_INDEX: {
+
+ const Expression::NamedIndexNode *index = static_cast<const Expression::NamedIndexNode *>(p_node);
+
+ Variant base;
+ bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str);
+ if (ret)
+ return true;
+
+ bool valid;
+ r_ret = base.get_named(index->name, &valid);
+ if (!valid) {
+ r_error_str = vformat(RTR("Invalid named index '%s' for base type "), String(index->name), Variant::get_type_name(base.get_type()));
+ return true;
+ }
+
+ } break;
+ case Expression::ENode::TYPE_ARRAY: {
+ const Expression::ArrayNode *array = static_cast<const Expression::ArrayNode *>(p_node);
+
+ Array arr;
+ arr.resize(array->array.size());
+ for (int i = 0; i < array->array.size(); i++) {
+
+ Variant value;
+ bool ret = _execute(p_inputs, p_instance, array->array[i], value, r_error_str);
+
+ if (ret)
+ return true;
+ arr[i] = value;
+ }
+
+ r_ret = arr;
+
+ } break;
+ case Expression::ENode::TYPE_DICTIONARY: {
+ const Expression::DictionaryNode *dictionary = static_cast<const Expression::DictionaryNode *>(p_node);
+
+ Dictionary d;
+ for (int i = 0; i < dictionary->dict.size(); i += 2) {
+
+ Variant key;
+ bool ret = _execute(p_inputs, p_instance, dictionary->dict[i + 0], key, r_error_str);
+
+ if (ret)
+ return true;
+
+ Variant value;
+ ret = _execute(p_inputs, p_instance, dictionary->dict[i + 1], value, r_error_str);
+ if (ret)
+ return true;
+
+ d[key] = value;
+ }
+
+ r_ret = d;
+ } break;
+ case Expression::ENode::TYPE_CONSTRUCTOR: {
+
+ const Expression::ConstructorNode *constructor = static_cast<const Expression::ConstructorNode *>(p_node);
+
+ Vector<Variant> arr;
+ Vector<const Variant *> argp;
+ arr.resize(constructor->arguments.size());
+ argp.resize(constructor->arguments.size());
+
+ for (int i = 0; i < constructor->arguments.size(); i++) {
+
+ Variant value;
+ bool ret = _execute(p_inputs, p_instance, constructor->arguments[i], value, r_error_str);
+
+ if (ret)
+ return true;
+ arr.write[i] = value;
+ argp.write[i] = &arr[i];
+ }
+
+ Variant::CallError ce;
+ r_ret = Variant::construct(constructor->data_type, (const Variant **)argp.ptr(), argp.size(), ce);
+
+ if (ce.error != Variant::CallError::CALL_OK) {
+ r_error_str = vformat(RTR("Invalid arguments to construct '%s'"), Variant::get_type_name(constructor->data_type));
+ return true;
+ }
+
+ } break;
+ case Expression::ENode::TYPE_BUILTIN_FUNC: {
+
+ const Expression::BuiltinFuncNode *bifunc = static_cast<const Expression::BuiltinFuncNode *>(p_node);
+
+ Vector<Variant> arr;
+ Vector<const Variant *> argp;
+ arr.resize(bifunc->arguments.size());
+ argp.resize(bifunc->arguments.size());
+
+ for (int i = 0; i < bifunc->arguments.size(); i++) {
+
+ Variant value;
+ bool ret = _execute(p_inputs, p_instance, bifunc->arguments[i], value, r_error_str);
+ if (ret)
+ return true;
+ arr.write[i] = value;
+ argp.write[i] = &arr[i];
+ }
+
+ Variant::CallError ce;
+ exec_func(bifunc->func, (const Variant **)argp.ptr(), &r_ret, ce, r_error_str);
+
+ if (ce.error != Variant::CallError::CALL_OK) {
+ r_error_str = "Builtin Call Failed. " + r_error_str;
+ return true;
+ }
+
+ } break;
+ case Expression::ENode::TYPE_CALL: {
+
+ const Expression::CallNode *call = static_cast<const Expression::CallNode *>(p_node);
+
+ Variant base;
+ bool ret = _execute(p_inputs, p_instance, call->base, base, r_error_str);
+
+ if (ret)
+ return true;
+
+ Vector<Variant> arr;
+ Vector<const Variant *> argp;
+ arr.resize(call->arguments.size());
+ argp.resize(call->arguments.size());
+
+ for (int i = 0; i < call->arguments.size(); i++) {
+
+ Variant value;
+ bool ret = _execute(p_inputs, p_instance, call->arguments[i], value, r_error_str);
+
+ if (ret)
+ return true;
+ arr.write[i] = value;
+ argp.write[i] = &arr[i];
+ }
+
+ Variant::CallError ce;
+ r_ret = base.call(call->method, (const Variant **)argp.ptr(), argp.size(), ce);
+
+ if (ce.error != Variant::CallError::CALL_OK) {
+ r_error_str = vformat(RTR("On call to '%s':"), String(call->method));
+ return true;
+ }
+
+ } break;
+ }
+ return false;
+}
+
+Error Expression::parse(const String &p_expression, const Vector<String> &p_input_names) {
+
+ if (nodes) {
+ memdelete(nodes);
+ nodes = NULL;
+ root = NULL;
+ }
+
+ error_str = String();
+ error_set = false;
+ str_ofs = 0;
+ input_names = p_input_names;
+
+ expression = p_expression;
+ root = _parse_expression();
+
+ if (error_set) {
+ root = NULL;
+ if (nodes) {
+ memdelete(nodes);
+ }
+ nodes = NULL;
+ return ERR_INVALID_PARAMETER;
+ }
+
+ return OK;
+}
+
+Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) {
+
+ execution_error = false;
+ Variant output;
+ String error_txt;
+ bool err = _execute(p_inputs, p_base, root, output, error_txt);
+ if (err) {
+ execution_error = true;
+ error_str = error_txt;
+ if (p_show_error) {
+ ERR_EXPLAIN(error_str);
+ ERR_FAIL_V(Variant());
+ }
+ }
+
+ return output;
+}
+
+bool Expression::has_execute_failed() const {
+ return execution_error;
+}
+
+String Expression::get_error_text() const {
+ return error_str;
+}
+
+void Expression::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("parse", "expression", "input_names"), &Expression::parse, DEFVAL(Vector<String>()));
+ ClassDB::bind_method(D_METHOD("execute", "inputs", "base_instance", "show_error"), &Expression::execute, DEFVAL(Array()), DEFVAL(Variant()), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("has_execute_failed"), &Expression::has_execute_failed);
+ ClassDB::bind_method(D_METHOD("get_error_text"), &Expression::get_error_text);
+}
+
+Expression::Expression() {
+ output_type = Variant::NIL;
+ error_set = true;
+ root = NULL;
+ nodes = NULL;
+ sequenced = false;
+ execution_error = false;
+}
+
+Expression::~Expression() {
+
+ if (nodes) {
+ memdelete(nodes);
+ }
+}
diff --git a/core/math/expression.h b/core/math/expression.h
new file mode 100644
index 0000000000..7a7639cf0b
--- /dev/null
+++ b/core/math/expression.h
@@ -0,0 +1,325 @@
+#ifndef EXPRESSION_H
+#define EXPRESSION_H
+
+#include "core/reference.h"
+
+class Expression : public Reference {
+ GDCLASS(Expression, Reference)
+public:
+ enum BuiltinFunc {
+ MATH_SIN,
+ MATH_COS,
+ MATH_TAN,
+ MATH_SINH,
+ MATH_COSH,
+ MATH_TANH,
+ MATH_ASIN,
+ MATH_ACOS,
+ MATH_ATAN,
+ MATH_ATAN2,
+ MATH_SQRT,
+ MATH_FMOD,
+ MATH_FPOSMOD,
+ MATH_FLOOR,
+ MATH_CEIL,
+ MATH_ROUND,
+ MATH_ABS,
+ MATH_SIGN,
+ MATH_POW,
+ MATH_LOG,
+ MATH_EXP,
+ MATH_ISNAN,
+ MATH_ISINF,
+ MATH_EASE,
+ MATH_DECIMALS,
+ MATH_STEPIFY,
+ MATH_LERP,
+ MATH_INVERSE_LERP,
+ MATH_RANGE_LERP,
+ MATH_DECTIME,
+ MATH_RANDOMIZE,
+ MATH_RAND,
+ MATH_RANDF,
+ MATH_RANDOM,
+ MATH_SEED,
+ MATH_RANDSEED,
+ MATH_DEG2RAD,
+ MATH_RAD2DEG,
+ MATH_LINEAR2DB,
+ MATH_DB2LINEAR,
+ MATH_POLAR2CARTESIAN,
+ MATH_CARTESIAN2POLAR,
+ MATH_WRAP,
+ MATH_WRAPF,
+ LOGIC_MAX,
+ LOGIC_MIN,
+ LOGIC_CLAMP,
+ LOGIC_NEAREST_PO2,
+ OBJ_WEAKREF,
+ FUNC_FUNCREF,
+ TYPE_CONVERT,
+ TYPE_OF,
+ TYPE_EXISTS,
+ TEXT_CHAR,
+ TEXT_STR,
+ TEXT_PRINT,
+ TEXT_PRINTERR,
+ TEXT_PRINTRAW,
+ VAR_TO_STR,
+ STR_TO_VAR,
+ VAR_TO_BYTES,
+ BYTES_TO_VAR,
+ COLORN,
+ FUNC_MAX
+ };
+
+ static int get_func_argument_count(BuiltinFunc p_func);
+ static String get_func_name(BuiltinFunc p_func);
+ static void exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Variant::CallError &r_error, String &r_error_str);
+ static BuiltinFunc find_function(const String &p_string);
+
+private:
+ static const char *func_name[FUNC_MAX];
+
+ struct Input {
+
+ Variant::Type type;
+ String name;
+
+ Input() { type = Variant::NIL; }
+ };
+
+ Vector<Input> inputs;
+ Variant::Type output_type;
+
+ String expression;
+
+ bool sequenced;
+ int str_ofs;
+ bool expression_dirty;
+
+ bool _compile_expression();
+
+ enum TokenType {
+ TK_CURLY_BRACKET_OPEN,
+ TK_CURLY_BRACKET_CLOSE,
+ TK_BRACKET_OPEN,
+ TK_BRACKET_CLOSE,
+ TK_PARENTHESIS_OPEN,
+ TK_PARENTHESIS_CLOSE,
+ TK_IDENTIFIER,
+ TK_BUILTIN_FUNC,
+ TK_SELF,
+ TK_CONSTANT,
+ TK_BASIC_TYPE,
+ TK_COLON,
+ TK_COMMA,
+ TK_PERIOD,
+ TK_OP_IN,
+ TK_OP_EQUAL,
+ TK_OP_NOT_EQUAL,
+ TK_OP_LESS,
+ TK_OP_LESS_EQUAL,
+ TK_OP_GREATER,
+ TK_OP_GREATER_EQUAL,
+ TK_OP_AND,
+ TK_OP_OR,
+ TK_OP_NOT,
+ TK_OP_ADD,
+ TK_OP_SUB,
+ TK_OP_MUL,
+ TK_OP_DIV,
+ TK_OP_MOD,
+ TK_OP_SHIFT_LEFT,
+ TK_OP_SHIFT_RIGHT,
+ TK_OP_BIT_AND,
+ TK_OP_BIT_OR,
+ TK_OP_BIT_XOR,
+ TK_OP_BIT_INVERT,
+ TK_INPUT,
+ TK_EOF,
+ TK_ERROR,
+ TK_MAX
+ };
+
+ static const char *token_name[TK_MAX];
+ struct Token {
+
+ TokenType type;
+ Variant value;
+ };
+
+ void _set_error(const String &p_err) {
+ if (error_set)
+ return;
+ error_str = p_err;
+ error_set = true;
+ }
+
+ Error _get_token(Token &r_token);
+
+ String error_str;
+ bool error_set;
+
+ struct ENode {
+
+ enum Type {
+ TYPE_INPUT,
+ TYPE_CONSTANT,
+ TYPE_SELF,
+ TYPE_OPERATOR,
+ TYPE_INDEX,
+ TYPE_NAMED_INDEX,
+ TYPE_ARRAY,
+ TYPE_DICTIONARY,
+ TYPE_CONSTRUCTOR,
+ TYPE_BUILTIN_FUNC,
+ TYPE_CALL
+ };
+
+ ENode *next;
+
+ Type type;
+
+ ENode() { next = NULL; }
+ virtual ~ENode() {
+ if (next) {
+ memdelete(next);
+ }
+ }
+ };
+
+ struct ExpressionNode {
+
+ bool is_op;
+ union {
+ Variant::Operator op;
+ ENode *node;
+ };
+ };
+
+ ENode *_parse_expression();
+
+ struct InputNode : public ENode {
+
+ int index;
+ InputNode() {
+ type = TYPE_INPUT;
+ }
+ };
+
+ struct ConstantNode : public ENode {
+
+ Variant value;
+ ConstantNode() {
+ type = TYPE_CONSTANT;
+ }
+ };
+
+ struct OperatorNode : public ENode {
+
+ Variant::Operator op;
+
+ ENode *nodes[2];
+
+ OperatorNode() {
+ type = TYPE_OPERATOR;
+ }
+ };
+
+ struct SelfNode : public ENode {
+
+ SelfNode() {
+ type = TYPE_SELF;
+ }
+ };
+
+ struct IndexNode : public ENode {
+ ENode *base;
+ ENode *index;
+
+ IndexNode() {
+ type = TYPE_INDEX;
+ }
+ };
+
+ struct NamedIndexNode : public ENode {
+ ENode *base;
+ StringName name;
+
+ NamedIndexNode() {
+ type = TYPE_NAMED_INDEX;
+ }
+ };
+
+ struct ConstructorNode : public ENode {
+ Variant::Type data_type;
+ Vector<ENode *> arguments;
+
+ ConstructorNode() {
+ type = TYPE_CONSTRUCTOR;
+ }
+ };
+
+ struct CallNode : public ENode {
+ ENode *base;
+ StringName method;
+ Vector<ENode *> arguments;
+
+ CallNode() {
+ type = TYPE_CALL;
+ }
+ };
+
+ struct ArrayNode : public ENode {
+ Vector<ENode *> array;
+ ArrayNode() {
+ type = TYPE_ARRAY;
+ }
+ };
+
+ struct DictionaryNode : public ENode {
+ Vector<ENode *> dict;
+ DictionaryNode() {
+ type = TYPE_DICTIONARY;
+ }
+ };
+
+ struct BuiltinFuncNode : public ENode {
+ BuiltinFunc func;
+ Vector<ENode *> arguments;
+ BuiltinFuncNode() {
+ type = TYPE_BUILTIN_FUNC;
+ }
+ };
+
+ template <class T>
+ T *alloc_node() {
+ T *node = memnew(T);
+ node->next = nodes;
+ nodes = node;
+ return node;
+ }
+
+ ENode *root;
+ ENode *nodes;
+
+ Vector<String> input_names;
+
+ bool execution_error;
+ bool _execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str);
+
+protected:
+ static void _bind_methods();
+
+public:
+ Error parse(const String &p_expression, const Vector<String> &p_input_names = Vector<String>());
+ Variant execute(Array p_inputs, Object *p_base = NULL, bool p_show_error = true);
+ bool has_execute_failed() const;
+ String get_error_text() const;
+
+ Expression();
+ ~Expression();
+};
+
+#endif // EXPRESSION_H
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index 3eac4428da..59f07c03e7 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -270,7 +270,6 @@ String FileAccess::get_token() const {
c = get_8();
}
- token += '0';
return String::utf8(token.get_data());
}
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 0e7e63dbd8..859015f44b 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -54,6 +54,7 @@
#include "io/tcp_server.h"
#include "io/translation_loader_po.h"
#include "math/a_star.h"
+#include "math/expression.h"
#include "math/triangle_mesh.h"
#include "os/input.h"
#include "os/main_loop.h"
@@ -216,6 +217,7 @@ void register_core_singletons() {
ClassDB::register_virtual_class<Input>();
ClassDB::register_class<InputMap>();
ClassDB::register_class<_JSON>();
+ ClassDB::register_class<Expression>();
Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton()));
diff --git a/core/script_language.h b/core/script_language.h
index 4e81b9b626..71d550d404 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -207,13 +207,20 @@ public:
virtual void finish() = 0;
/* EDITOR FUNCTIONS */
+ struct Warning {
+ int line;
+ int code;
+ String string_code;
+ String message;
+ };
+
virtual void get_reserved_words(List<String> *p_words) const = 0;
virtual void get_comment_delimiters(List<String> *p_delimiters) const = 0;
virtual void get_string_delimiters(List<String> *p_delimiters) const = 0;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0;
virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {}
virtual bool is_using_templates() { return false; }
- virtual bool 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 = NULL, Set<int> *r_safe_lines = NULL) const = 0;
+ virtual bool 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 = NULL, List<Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const = 0;
virtual String validate_path(const String &p_path) const { return ""; }
virtual Script *create_script() const = 0;
virtual bool has_named_classes() const = 0;
diff --git a/core/sort.h b/core/sort.h
index a6780309d8..97983829e1 100644
--- a/core/sort.h
+++ b/core/sort.h
@@ -36,13 +36,25 @@
@author ,,, <red@lunatea>
*/
+#define ERR_BAD_COMPARE(cond) \
+ if (unlikely(cond)) { \
+ ERR_PRINT("bad comparison function; sorting will be broken"); \
+ break; \
+ }
+
template <class T>
struct _DefaultComparator {
- inline bool operator()(const T &a, const T &b) const { return (a < b); }
+ _FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); }
};
-template <class T, class Comparator = _DefaultComparator<T> >
+#ifdef DEBUG_ENABLED
+#define SORT_ARRAY_VALIDATE_ENABLED true
+#else
+#define SORT_ARRAY_VALIDATE_ENABLED false
+#endif
+
+template <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
class SortArray {
enum {
@@ -164,12 +176,23 @@ public:
inline int partitioner(int p_first, int p_last, T p_pivot, T *p_array) const {
+ const int unmodified_first = p_first;
+ const int unmodified_last = p_last;
+
while (true) {
- while (compare(p_array[p_first], p_pivot))
+ while (compare(p_array[p_first], p_pivot)) {
+ if (Validate) {
+ ERR_BAD_COMPARE(p_first == unmodified_last - 1)
+ }
p_first++;
+ }
p_last--;
- while (compare(p_pivot, p_array[p_last]))
+ while (compare(p_pivot, p_array[p_last])) {
+ if (Validate) {
+ ERR_BAD_COMPARE(p_last == unmodified_first)
+ }
p_last--;
+ }
if (!(p_first < p_last))
return p_first;
@@ -238,6 +261,9 @@ public:
int next = p_last - 1;
while (compare(p_value, p_array[next])) {
+ if (Validate) {
+ ERR_BAD_COMPARE(next == 0)
+ }
p_array[p_last] = p_array[next];
p_last = next;
next--;
diff --git a/core/variant.h b/core/variant.h
index 4b245d25e6..b48a0b3e73 100644
--- a/core/variant.h
+++ b/core/variant.h
@@ -398,9 +398,9 @@ public:
void static_assign(const Variant &p_variant);
static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list);
- static void get_numeric_constants_for_type(Variant::Type p_type, List<StringName> *p_constants);
- static bool has_numeric_constant(Variant::Type p_type, const StringName &p_value);
- static int get_numeric_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = NULL);
+ static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants);
+ static bool has_constant(Variant::Type p_type, const StringName &p_value);
+ static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = NULL);
typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud);
typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value);
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index 20a2929dc0..19308ff683 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -30,6 +30,7 @@
#include "variant.h"
+#include "core/color_names.inc"
#include "core_string_names.h"
#include "io/compression.h"
#include "object.h"
@@ -991,6 +992,7 @@ struct _VariantCall {
#ifdef DEBUG_ENABLED
List<StringName> value_ordered;
#endif
+ Map<StringName, Variant> variant_value;
};
static ConstantData *constant_data;
@@ -1002,6 +1004,11 @@ struct _VariantCall {
constant_data[p_type].value_ordered.push_back(p_constant_name);
#endif
}
+
+ static void add_variant_constant(int p_type, StringName p_constant_name, const Variant &p_constant_value) {
+
+ constant_data[p_type].variant_value[p_constant_name] = p_constant_value;
+ }
};
_VariantCall::TypeFunc *_VariantCall::type_funcs = NULL;
@@ -1354,7 +1361,7 @@ void Variant::get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_lis
}
}
-void Variant::get_numeric_constants_for_type(Variant::Type p_type, List<StringName> *p_constants) {
+void Variant::get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants) {
ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
@@ -1370,16 +1377,21 @@ void Variant::get_numeric_constants_for_type(Variant::Type p_type, List<StringNa
p_constants->push_back(E->key());
#endif
}
+
+ for (Map<StringName, Variant>::Element *E = cd.variant_value.front(); E; E = E->next()) {
+
+ p_constants->push_back(E->key());
+ }
}
-bool Variant::has_numeric_constant(Variant::Type p_type, const StringName &p_value) {
+bool Variant::has_constant(Variant::Type p_type, const StringName &p_value) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
_VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
- return cd.value.has(p_value);
+ return cd.value.has(p_value) || cd.variant_value.has(p_value);
}
-int Variant::get_numeric_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid) {
+Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid) {
if (r_valid)
*r_valid = false;
@@ -1389,7 +1401,14 @@ int Variant::get_numeric_constant_value(Variant::Type p_type, const StringName &
Map<StringName, int>::Element *E = cd.value.find(p_value);
if (!E) {
- return -1;
+ Map<StringName, Variant>::Element *E = cd.variant_value.find(p_value);
+ if (E) {
+ if (r_valid)
+ *r_valid = true;
+ return E->get();
+ } else {
+ return -1;
+ }
}
if (r_valid)
*r_valid = true;
@@ -1858,9 +1877,62 @@ void register_variant_methods() {
/* REGISTER CONSTANTS */
+ _populate_named_colors();
+ for (Map<String, Color>::Element *color = _named_colors.front(); color; color = color->next()) {
+ _VariantCall::add_variant_constant(Variant::COLOR, color->key(), color->value());
+ }
+
_VariantCall::add_constant(Variant::VECTOR3, "AXIS_X", Vector3::AXIS_X);
_VariantCall::add_constant(Variant::VECTOR3, "AXIS_Y", Vector3::AXIS_Y);
_VariantCall::add_constant(Variant::VECTOR3, "AXIS_Z", Vector3::AXIS_Z);
+
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "ZERO", Vector3(0, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "INF", Vector3(Math_INF, Math_INF, Math_INF));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "LEFT", Vector3(-1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "RIGHT", Vector3(1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "UP", Vector3(0, 1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "DOWN", Vector3(0, -1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "FORWARD", Vector3(0, 0, -1));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "BACK", Vector3(0, 0, 1));
+
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "INF", Vector2(Math_INF, Math_INF));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "LEFT", Vector2(-1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "RIGHT", Vector2(1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "UP", Vector2(0, -1));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "DOWN", Vector2(0, 1));
+
+ _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D(1, 0, 0, 1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0));
+
+ Transform identity_transform, transform_x, transform_y, transform_z;
+ identity_transform.set(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
+ _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);
+ _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);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Z", transform_z);
+
+ _VariantCall::add_variant_constant(Variant::PLANE, "X", Plane(Vector3(1, 0, 0), 0));
+ _VariantCall::add_variant_constant(Variant::PLANE, "Y", Plane(Vector3(0, 1, 0), 0));
+ _VariantCall::add_variant_constant(Variant::PLANE, "Z", Plane(Vector3(0, 0, 1), 0));
+
+ _VariantCall::add_variant_constant(Variant::QUAT, "IDENTITY", Quat(0, 0, 0, 1));
+
+ CharType black_circle[2] = { 0x25CF, 0 };
+ _VariantCall::add_variant_constant(Variant::STRING, "BLACK_CIRCLE", String(black_circle));
+ CharType white_circle[2] = { 0x25CB, 0 };
+ _VariantCall::add_variant_constant(Variant::STRING, "WHITE_CIRCLE", String(white_circle));
+ CharType black_diamond[2] = { 0x25C6, 0 };
+ _VariantCall::add_variant_constant(Variant::STRING, "BLACK_DIAMOND", String(black_diamond));
+ CharType white_diamond[2] = { 0x25C7, 0 };
+ _VariantCall::add_variant_constant(Variant::STRING, "WHITE_DIAMOND", String(white_diamond));
+
+ _VariantCall::add_variant_constant(Variant::NODE_PATH, "CURRENT", String("."));
+ _VariantCall::add_variant_constant(Variant::NODE_PATH, "PARENT", String(".."));
}
void unregister_variant_methods() {
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index 3d74bd7ab0..c675bbe994 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
A color is represented as red, green and blue (r,g,b) components. Additionally, "a" represents the alpha component, often used for transparency. Values are in floating point and usually range from 0 to 1. Some methods (such as set_modulate(color)) may accept values &gt; 1.
- You can also create a color from standardised color names with [method @GDScript.ColorN].
+ You can also create a color from standardised color names with Color.ColorN (e.g. Color.green) or [method @GDScript.ColorN].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index f5a19ede0c..c85bee9b84 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -384,20 +384,28 @@
Call a group only once even if the call is executed many times.
</constant>
<constant name="STRETCH_MODE_DISABLED" value="0" enum="StretchMode">
+ No stretching.
</constant>
<constant name="STRETCH_MODE_2D" value="1" enum="StretchMode">
+ Render stretching in higher resolution (interpolated).
</constant>
<constant name="STRETCH_MODE_VIEWPORT" value="2" enum="StretchMode">
+ Keep the specified display resolution. No interpolation. Content may appear pixelated.
</constant>
<constant name="STRETCH_ASPECT_IGNORE" value="0" enum="StretchAspect">
+ Fill the window with the content stretched to cover excessive space. Content may appear elongated.
</constant>
<constant name="STRETCH_ASPECT_KEEP" value="1" enum="StretchAspect">
+ Retain the same aspect ratio by padding with black bars in either axes. No expansion of content.
</constant>
<constant name="STRETCH_ASPECT_KEEP_WIDTH" value="2" enum="StretchAspect">
+ Expand vertically. Left/right black bars may appear if the window is too wide.
</constant>
<constant name="STRETCH_ASPECT_KEEP_HEIGHT" value="3" enum="StretchAspect">
+ Expand horizontally. Top/bottom black bars may appear if the window is too tall.
</constant>
<constant name="STRETCH_ASPECT_EXPAND" value="4" enum="StretchAspect">
+ Expand in both directions, retaining the same aspect ratio. No black bars.
</constant>
</constants>
</class>
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index e045d4cd39..e39ec915fc 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -154,7 +154,8 @@ public:
ERR_FAIL_COND_V(!texture, RID());
return texture_owner.make_rid(texture);
}
- void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) {
+
+ void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VisualServer::TextureType p_type = VS::TEXTURE_TYPE_2D, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) {
DummyTexture *t = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!t);
t->width = p_width;
@@ -164,7 +165,7 @@ public:
t->image = Ref<Image>(memnew(Image));
t->image->create(p_width, p_height, false, p_format);
}
- void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) {
+ void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_level) {
DummyTexture *t = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!t);
t->width = p_image->get_width();
@@ -173,7 +174,7 @@ public:
t->image->create(t->width, t->height, false, t->format, p_image->get_data());
}
- void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side) {
+ void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_level) {
DummyTexture *t = texture_owner.get(p_texture);
ERR_FAIL_COND(!t);
@@ -186,7 +187,7 @@ public:
t->image->blit_rect(p_image, Rect2(src_x, src_y, src_w, src_h), Vector2(dst_x, dst_y));
}
- Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const {
+ Ref<Image> texture_get_data(RID p_texture, int p_level) const {
DummyTexture *t = texture_owner.getornull(p_texture);
ERR_FAIL_COND_V(!t, Ref<Image>());
return t->image;
@@ -206,10 +207,13 @@ public:
ERR_FAIL_COND_V(!t, Image::FORMAT_RGB8);
return t->format;
}
+
+ VisualServer::TextureType texture_get_type(RID p_texture) const { return VS::TEXTURE_TYPE_2D; }
uint32_t texture_get_texid(RID p_texture) const { return 0; }
uint32_t texture_get_width(RID p_texture) const { return 0; }
uint32_t texture_get_height(RID p_texture) const { return 0; }
- void texture_set_size_override(RID p_texture, int p_width, int p_height) {}
+ uint32_t texture_get_depth(RID p_texture) const { return 0; }
+ void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) {}
void texture_set_path(RID p_texture, const String &p_path) {
DummyTexture *t = texture_owner.getornull(p_texture);
diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp
index 256d37186d..3d388c031a 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.cpp
+++ b/drivers/gles2/rasterizer_canvas_gles2.cpp
@@ -349,7 +349,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
if (state.canvas_shader.bind()) {
_set_uniforms();
- state.canvas_shader.use_material((void *)p_material, 2);
+ state.canvas_shader.use_material((void *)p_material);
}
_bind_canvas_texture(RID(), RID());
@@ -393,7 +393,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
if (state.canvas_shader.bind()) {
_set_uniforms();
- state.canvas_shader.use_material((void *)p_material, 2);
+ state.canvas_shader.use_material((void *)p_material);
}
RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map);
@@ -476,7 +476,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true);
if (state.canvas_shader.bind()) {
_set_uniforms();
- state.canvas_shader.use_material((void *)p_material, 2);
+ state.canvas_shader.use_material((void *)p_material);
}
glDisableVertexAttribArray(VS::ARRAY_COLOR);
@@ -642,7 +642,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
if (state.canvas_shader.bind()) {
_set_uniforms();
- state.canvas_shader.use_material((void *)p_material, 2);
+ state.canvas_shader.use_material((void *)p_material);
}
static const int num_points = 32;
@@ -673,7 +673,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
if (state.canvas_shader.bind()) {
_set_uniforms();
- state.canvas_shader.use_material((void *)p_material, 2);
+ state.canvas_shader.use_material((void *)p_material);
}
RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map);
@@ -694,7 +694,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
if (state.canvas_shader.bind()) {
_set_uniforms();
- state.canvas_shader.use_material((void *)p_material, 2);
+ state.canvas_shader.use_material((void *)p_material);
}
_bind_canvas_texture(RID(), RID());
@@ -727,7 +727,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
if (state.canvas_shader.bind()) {
_set_uniforms();
- state.canvas_shader.use_material((void *)p_material, 2);
+ state.canvas_shader.use_material((void *)p_material);
}
ERR_CONTINUE(primitive->points.size() < 1);
@@ -926,7 +926,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
state.canvas_shader.set_custom_shader(0);
state.canvas_shader.bind();
}
- state.canvas_shader.use_material((void *)material_ptr, 2);
+ state.canvas_shader.use_material((void *)material_ptr);
shader_cache = shader_ptr;
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index 335ad28670..a1a0b9e2c6 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -317,7 +317,7 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c
canvas->canvas_begin();
RID texture = storage->texture_create();
- storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), VS::TEXTURE_FLAG_FILTER);
+ storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
storage->texture_set_data(texture, p_image);
Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height());
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 00a79db347..5f31bfe209 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -35,6 +35,8 @@
#include "rasterizer_canvas_gles2.h"
#include "servers/visual/visual_server_raster.h"
+#include "vmap.h"
+
#ifndef GLES_OVER_GL
#define glClearDepth glClearDepthf
#endif
@@ -827,7 +829,7 @@ static const GLenum gl_primitive[] = {
GL_TRIANGLE_FAN
};
-void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_use_radiance_map, bool p_reverse_cull, bool p_shadow_atlas, bool p_skeleton_tex, Size2i p_skeleton_tex_size) {
+void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, Size2i p_skeleton_tex_size) {
// material parameters
@@ -864,25 +866,11 @@ void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m
ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptrw();
- int num_default_tex = p_use_radiance_map ? 1 : 0;
-
- if (p_material->shader->spatial.uses_screen_texture) {
- num_default_tex = MIN(num_default_tex, 2);
- }
-
- if (p_shadow_atlas) {
- num_default_tex = MIN(num_default_tex, 3);
- }
-
- if (p_skeleton_tex) {
- num_default_tex = MIN(num_default_tex, 4);
-
- state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TEXTURE_SIZE, p_skeleton_tex_size);
- }
+ state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TEXTURE_SIZE, p_skeleton_tex_size);
for (int i = 0; i < tc; i++) {
- glActiveTexture(GL_TEXTURE0 + num_default_tex + i);
+ glActiveTexture(GL_TEXTURE0 + i);
RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(textures[i].second);
@@ -911,7 +899,7 @@ void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m
glBindTexture(t->target, t->tex_id);
}
- state.scene_shader.use_material((void *)p_material, num_default_tex);
+ state.scene_shader.use_material((void *)p_material);
}
void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton) {
@@ -1279,7 +1267,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) {
}
}
-void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const RID *p_light_cull_result, int p_light_cull_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows) {
+void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const RID *p_directional_lights, int p_directional_light_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add) {
ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
@@ -1289,6 +1277,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
bool use_radiance_map = false;
+ VMap<RID, Vector<RenderList::Element *> > lit_objects;
+
for (int i = 0; i < p_element_count; i++) {
RenderList::Element *e = p_elements[i];
@@ -1297,7 +1287,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton);
if (p_base_env) {
- glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2);
glBindTexture(GL_TEXTURE_CUBE_MAP, p_base_env);
use_radiance_map = true;
}
@@ -1315,7 +1305,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
_setup_geometry(e, skeleton);
- _setup_material(material, use_radiance_map, p_reverse_cull, false, skeleton ? (skeleton->tex_id != 0) : 0, Size2i(skeleton ? skeleton->size * 3 : 0, 0));
+ _setup_material(material, p_reverse_cull, Size2i(skeleton ? skeleton->size * 3 : 0, 0));
if (use_radiance_map) {
state.scene_shader.set_uniform(SceneShaderGLES2::RADIANCE_INVERSE_XFORM, p_view_transform);
@@ -1404,66 +1394,88 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
_render_geometry(e);
- // render lights
-
if (material->shader->spatial.unshaded)
continue;
if (p_shadow)
continue;
- state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, true);
+ for (int light = 0; light < e->instance->light_instances.size(); light++) {
- state.scene_shader.bind();
+ RID light_instance = e->instance->light_instances[light];
- glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ lit_objects[light_instance].push_back(e);
+ }
+ }
- {
- bool has_shadow_atlas = shadow_atlas != NULL;
- _setup_material(material, false, p_reverse_cull, has_shadow_atlas, skeleton ? (skeleton->tex_id != 0) : 0, Size2i(skeleton ? skeleton->size * 3 : 0, 0));
+ if (p_shadow) {
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false);
+ return;
+ }
- if (has_shadow_atlas) {
- glActiveTexture(GL_TEXTURE3);
- glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
- }
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, true);
- state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse());
- state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform);
- state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection);
- state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse());
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]);
+ for (int lo = 0; lo < lit_objects.size(); lo++) {
- state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size);
- state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror?
- state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform);
- }
+ RID key = lit_objects.getk(lo);
- for (int j = 0; j < e->instance->light_instances.size(); j++) {
- RID light_rid = e->instance->light_instances[j];
- LightInstance *light = light_instance_owner.get(light_rid);
+ LightInstance *light = light_instance_owner.getornull(key);
+ RasterizerStorageGLES2::Light *light_ptr = light->light_ptr;
- switch (light->light_ptr->type) {
- case VS::LIGHT_DIRECTIONAL: {
- continue;
- } break;
+ const Vector<RenderList::Element *> &list = lit_objects.getv(lo);
+
+ for (int i = 0; i < list.size(); i++) {
+
+ RenderList::Element *e = list[i];
+ RasterizerStorageGLES2::Material *material = e->material;
+
+ RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton);
+
+ {
+ _setup_geometry(e, skeleton);
+ _setup_material(material, p_reverse_cull, Size2i(skeleton ? skeleton->size * 3 : 0, 0));
+ if (shadow_atlas != NULL) {
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4);
+ glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
+ }
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse());
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform);
+ state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection);
+ state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse());
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]);
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size);
+ state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror?
+ state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform);
+ }
+
+ switch (light_ptr->type) {
case VS::LIGHT_OMNI: {
+
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)1);
Vector3 position = p_view_transform.inverse().xform(light->transform.origin);
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position);
- float range = light->light_ptr->param[VS::LIGHT_PARAM_RANGE];
+ float range = light_ptr->param[VS::LIGHT_PARAM_RANGE];
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range);
Color attenuation = Color(0.0, 0.0, 0.0, 0.0);
- attenuation.a = light->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION];
+ attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION];
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation);
- if (light->light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) {
+ if (light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) {
uint32_t key = shadow_atlas->shadow_owners[light->self];
@@ -1516,10 +1528,10 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized();
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction);
Color attenuation = Color(0.0, 0.0, 0.0, 0.0);
- attenuation.a = light->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION];
- float range = light->light_ptr->param[VS::LIGHT_PARAM_RANGE];
- float spot_attenuation = light->light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION];
- float angle = light->light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE];
+ attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION];
+ float range = light_ptr->param[VS::LIGHT_PARAM_RANGE];
+ float spot_attenuation = light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION];
+ float angle = light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE];
angle = Math::cos(Math::deg2rad(angle));
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation);
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ATTENUATION, spot_attenuation);
@@ -1576,9 +1588,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
} break;
- default: {
- print_line("wat.");
- } break;
+ default: break;
}
float energy = light->light_ptr->param[VS::LIGHT_PARAM_ENERGY];
@@ -1590,62 +1600,57 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
_render_geometry(e);
}
+ }
- for (int j = 0; j < p_light_cull_count; j++) {
- RID light_rid = p_light_cull_result[j];
-
- LightInstance *light = light_instance_owner.getornull(light_rid);
+ for (int dl = 0; dl < p_directional_light_count; dl++) {
+ RID light_rid = p_directional_lights[dl];
+ LightInstance *light = light_instance_owner.getornull(light_rid);
+ RasterizerStorageGLES2::Light *light_ptr = light->light_ptr;
- RasterizerStorageGLES2::Light *light_ptr = light->light_ptr;
+ switch (light_ptr->directional_shadow_mode) {
+ case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: {
+ } break;
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: {
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true);
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits);
+ } break;
- switch (light_ptr->type) {
- case VS::LIGHT_DIRECTIONAL: {
-
- switch (light_ptr->directional_shadow_mode) {
- case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: {
- } break;
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: {
- state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true);
- state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits);
- } break;
-
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: {
- state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true);
- state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits);
- } break;
- default:
- break;
- }
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: {
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true);
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits);
+ } break;
+ default:
+ break;
+ }
- {
- _setup_material(material, false, p_reverse_cull, false, skeleton ? (skeleton->tex_id != 0) : 0, Size2i(skeleton ? skeleton->size * 3 : 0, 0));
+ for (int i = 0; i < p_element_count; i++) {
- if (directional_shadow.depth) {
- glActiveTexture(GL_TEXTURE3);
- glBindTexture(GL_TEXTURE_2D, directional_shadow.depth);
- }
+ RenderList::Element *e = p_elements[i];
+ RasterizerStorageGLES2::Material *material = e->material;
+ RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton);
- state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse());
- state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform);
- state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection);
- state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse());
+ {
+ _setup_material(material, p_reverse_cull, Size2i(skeleton ? skeleton->size * 3 : 0, 0));
- state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]);
+ if (directional_shadow.depth) {
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); // TODO move into base pass
+ glBindTexture(GL_TEXTURE_2D, directional_shadow.depth);
+ }
- state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size);
- state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror?
- state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform);
- }
- state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)0);
- Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized();
- state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction);
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse());
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform);
+ state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection);
+ state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse());
- } break;
+ state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]);
- default: {
- continue;
- } break;
+ state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size);
+ state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror?
+ state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform);
}
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)0);
+ Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized();
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction);
float energy = light_ptr->param[VS::LIGHT_PARAM_ENERGY];
float specular = light_ptr->param[VS::LIGHT_PARAM_SPECULAR];
@@ -1753,10 +1758,10 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
_render_geometry(e);
}
-
- state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, false);
}
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, false);
+
state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false);
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false);
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false);
@@ -1911,9 +1916,21 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
}
}
+ Vector<RID> directional_lights;
+
+ for (int i = 0; i < p_light_cull_count; i++) {
+ RID light_rid = p_light_cull_result[i];
+
+ LightInstance *light = light_instance_owner.getornull(light_rid);
+
+ if (light->light_ptr->type == VS::LIGHT_DIRECTIONAL) {
+ directional_lights.push_back(light_rid);
+ }
+ }
+
// render opaque things first
render_list.sort_by_key(false);
- _render_render_list(render_list.elements, render_list.element_count, p_light_cull_result, p_light_cull_count, p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, false, false, false, false);
+ _render_render_list(render_list.elements, render_list.element_count, directional_lights.ptr(), directional_lights.size(), p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, false, false, false);
// alpha pass
@@ -1921,7 +1938,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
render_list.sort_by_key(true);
- _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_light_cull_result, p_light_cull_count, p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, true, false, false, false);
+ _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, directional_lights.ptr(), directional_lights.size(), p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, true, false, false);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
@@ -2136,7 +2153,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, true);
- _render_render_list(render_list.elements, render_list.element_count, NULL, 0, light_transform, light_projection, RID(), NULL, 0, bias, normal_bias, false, false, true, false, false);
+ _render_render_list(render_list.elements, render_list.element_count, NULL, 0, light_transform, light_projection, RID(), NULL, 0, bias, normal_bias, false, false, true, false);
state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, false);
diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h
index 0ce7e9ae97..f47d1f1d4e 100644
--- a/drivers/gles2/rasterizer_scene_gles2.h
+++ b/drivers/gles2/rasterizer_scene_gles2.h
@@ -545,11 +545,23 @@ public:
void _add_geometry_with_material(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, RasterizerStorageGLES2::Material *p_material, bool p_depth_pass, bool p_shadow_pass);
void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass);
- void _render_render_list(RenderList::Element **p_elements, int p_element_count, const RID *p_light_cull_result, int p_light_cull_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows);
+ void _render_render_list(RenderList::Element **p_elements, int p_element_count,
+ const RID *p_directional_lights, int p_directional_light_count,
+ const Transform &p_view_transform,
+ const CameraMatrix &p_projection,
+ RID p_shadow_atlas,
+ Environment *p_env,
+ GLuint p_base_env,
+ float p_shadow_bias,
+ float p_shadow_normal_bias,
+ bool p_reverse_cull,
+ bool p_alpha_pass,
+ bool p_shadow,
+ bool p_directional_add);
void _draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy);
- void _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_use_radiance_map, bool p_reverse_cull, bool p_shadow_atlas = false, bool p_skeleton_tex = false, Size2i p_skeleton_tex_size = Size2i(0, 0));
+ void _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, Size2i p_skeleton_tex_size = Size2i(0, 0));
void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton);
void _render_geometry(RenderList::Element *p_element);
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index 468659ed80..8c4325ccde 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -346,7 +346,7 @@ RID RasterizerStorageGLES2::texture_create() {
return texture_owner.make_rid(texture);
}
-void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags) {
+void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VisualServer::TextureType p_type, uint32_t p_flags) {
GLenum format;
GLenum internal_format;
GLenum type;
@@ -365,7 +365,24 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
texture->format = p_format;
texture->flags = p_flags;
texture->stored_cube_sides = 0;
- texture->target = (p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
+ texture->type = p_type;
+
+ switch (p_type) {
+ case VS::TEXTURE_TYPE_2D: {
+ texture->target = GL_TEXTURE_2D;
+ texture->images.resize(1);
+ } break;
+ case VS::TEXTURE_TYPE_CUBEMAP: {
+ texture->target = GL_TEXTURE_CUBE_MAP;
+ texture->images.resize(6);
+ } break;
+ case VS::TEXTURE_TYPE_2D_ARRAY: {
+ texture->images.resize(p_depth_3d);
+ } break;
+ case VS::TEXTURE_TYPE_3D: {
+ texture->images.resize(p_depth_3d);
+ } break;
+ }
_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, format, internal_format, type, compressed);
@@ -391,7 +408,7 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
texture->active = true;
}
-void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side) {
+void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) {
Texture *texture = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!texture);
@@ -406,7 +423,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
bool compressed = false;
if (config.keep_original_textures && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
- texture->images[p_cube_side] = p_image;
+ texture->images.write[p_layer] = p_image;
}
Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, format, internal_format, type, compressed);
@@ -425,7 +442,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
}
};
- GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_cube_side] : GL_TEXTURE_2D;
+ GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D;
texture->data_size = img->get_data().size();
PoolVector<uint8_t>::Read read = img->get_data().read();
@@ -527,9 +544,9 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
// printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem);
- texture->stored_cube_sides |= (1 << p_cube_side);
+ texture->stored_cube_sides |= (1 << p_layer);
- if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (!(texture->flags & VS::TEXTURE_FLAG_CUBEMAP) || texture->stored_cube_sides == (1 << 6) - 1)) {
+ if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != VS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) {
//generate mipmaps if they were requested and the image does not contain them
glGenerateMipmap(texture->target);
}
@@ -537,12 +554,12 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
texture->mipmaps = mipmaps;
}
-void RasterizerStorageGLES2::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side) {
+void RasterizerStorageGLES2::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer) {
// TODO
ERR_PRINT("Not implemented (ask Karroffel to do it :p)");
}
-Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side) const {
+Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) const {
Texture *texture = texture_owner.getornull(p_texture);
@@ -550,8 +567,8 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, VS::CubeMapSi
ERR_FAIL_COND_V(!texture->active, Ref<Image>());
ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref<Image>());
- if (!texture->images[p_cube_side].is_null()) {
- return texture->images[p_cube_side];
+ if (texture->type == VS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && p_layer >= 0 && !texture->images[p_layer].is_null()) {
+ return texture->images[p_layer];
}
#ifdef GLES_OVER_GL
@@ -577,9 +594,13 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, VS::CubeMapSi
ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->format, i - 1);
}
- glPixelStorei(GL_PACK_ALIGNMENT, 1);
-
- glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &wb[ofs]);
+ if (texture->compressed) {
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
+ glGetCompressedTexImage(texture->target, i, &wb[ofs]);
+ } else {
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &wb[ofs]);
+ }
}
wb = PoolVector<uint8_t>::Write();
@@ -605,8 +626,6 @@ void RasterizerStorageGLES2::texture_set_flags(RID p_texture, uint32_t p_flags)
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
- uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP;
- texture->flags = p_flags | cube; // can't remove a cube from being a cube
if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) {
@@ -663,6 +682,14 @@ Image::Format RasterizerStorageGLES2::texture_get_format(RID p_texture) const {
return texture->format;
}
+VisualServer::TextureType RasterizerStorageGLES2::texture_get_type(RID p_texture) const {
+ Texture *texture = texture_owner.getornull(p_texture);
+
+ ERR_FAIL_COND_V(!texture, VS::TEXTURE_TYPE_2D);
+
+ return texture->type;
+}
+
uint32_t RasterizerStorageGLES2::texture_get_texid(RID p_texture) const {
Texture *texture = texture_owner.getornull(p_texture);
@@ -687,7 +714,15 @@ uint32_t RasterizerStorageGLES2::texture_get_height(RID p_texture) const {
return texture->height;
}
-void RasterizerStorageGLES2::texture_set_size_override(RID p_texture, int p_width, int p_height) {
+uint32_t RasterizerStorageGLES2::texture_get_depth(RID p_texture) const {
+ Texture *texture = texture_owner.getornull(p_texture);
+
+ ERR_FAIL_COND_V(!texture, 0);
+
+ return texture->depth;
+}
+
+void RasterizerStorageGLES2::texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth) {
Texture *texture = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!texture);
@@ -726,8 +761,9 @@ void RasterizerStorageGLES2::texture_debug_usage(List<VS::TextureInfo> *r_info)
VS::TextureInfo tinfo;
tinfo.path = t->path;
tinfo.format = t->format;
- tinfo.size.x = t->alloc_width;
- tinfo.size.y = t->alloc_height;
+ tinfo.width = t->alloc_width;
+ tinfo.height = t->alloc_height;
+ tinfo.depth = 0;
tinfo.bytes = t->total_data_size;
r_info->push_back(tinfo);
}
@@ -3929,7 +3965,7 @@ void RasterizerStorageGLES2::initialize() {
frame.clear_request = false;
// config.keep_original_textures = false;
- glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units);
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size);
shaders.copy.init();
diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h
index fe5d4af952..8bc3369dbb 100644
--- a/drivers/gles2/rasterizer_storage_gles2.h
+++ b/drivers/gles2/rasterizer_storage_gles2.h
@@ -231,9 +231,10 @@ public:
String path;
uint32_t flags;
- int width, height;
+ int width, height, depth;
int alloc_width, alloc_height;
Image::Format format;
+ VS::TextureType type;
GLenum target;
GLenum gl_format_cache;
@@ -257,7 +258,7 @@ public:
RenderTarget *render_target;
- Ref<Image> images[6];
+ Vector<Ref<Image> > images;
bool redraw_if_visible;
@@ -327,17 +328,19 @@ public:
Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed);
virtual RID texture_create();
- virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);
- virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT);
- virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT);
- virtual Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const;
+ virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);
+ virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
+ virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer = 0);
+ virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const;
virtual void texture_set_flags(RID p_texture, uint32_t p_flags);
virtual uint32_t texture_get_flags(RID p_texture) const;
virtual Image::Format texture_get_format(RID p_texture) const;
+ virtual VS::TextureType texture_get_type(RID p_texture) const;
virtual uint32_t texture_get_texid(RID p_texture) const;
virtual uint32_t texture_get_width(RID p_texture) const;
virtual uint32_t texture_get_height(RID p_texture) const;
- virtual void texture_set_size_override(RID p_texture, int p_width, int p_height);
+ virtual uint32_t texture_get_depth(RID p_texture) const;
+ virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth);
virtual void texture_set_path(RID p_texture, const String &p_path);
virtual String texture_get_path(RID p_texture) const;
diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp
index 6c7f767733..5ac2af6e5c 100644
--- a/drivers/gles2/shader_compiler_gles2.cpp
+++ b/drivers/gles2/shader_compiler_gles2.cpp
@@ -704,6 +704,10 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
}
code += ";\n";
} else if (cf_node->flow_op == SL::FLOW_OP_DISCARD) {
+ if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) {
+ *p_actions.usage_flag_pointers["DISCARD"] = true;
+ used_flag_pointers.insert("DISCARD");
+ }
code += "discard;";
} else if (cf_node->flow_op == SL::FLOW_OP_CONTINUE) {
code += "continue;";
diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp
index 146575973f..e9b58cb272 100644
--- a/drivers/gles2/shader_gles2.cpp
+++ b/drivers/gles2/shader_gles2.cpp
@@ -527,8 +527,13 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
for (int i = 0; i < texunit_pair_count; i++) {
GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name);
- if (loc >= 0)
- glUniform1i(loc, texunit_pairs[i].index);
+ if (loc >= 0) {
+ if (texunit_pairs[i].index < 0) {
+ glUniform1i(loc, max_image_units + texunit_pairs[i].index);
+ } else {
+ glUniform1i(loc, texunit_pairs[i].index);
+ }
+ }
}
if (cc) {
@@ -643,6 +648,8 @@ void ShaderGLES2::setup(
}
}
}
+
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units);
}
void ShaderGLES2::finish() {
@@ -717,7 +724,7 @@ void ShaderGLES2::free_custom_shader(uint32_t p_code_id) {
custom_code_map.erase(p_code_id);
}
-void ShaderGLES2::use_material(void *p_material, int p_num_predef_textures) {
+void ShaderGLES2::use_material(void *p_material) {
RasterizerStorageGLES2::Material *material = (RasterizerStorageGLES2::Material *)p_material;
if (!material) {
@@ -906,20 +913,58 @@ void ShaderGLES2::use_material(void *p_material, int p_num_predef_textures) {
case ShaderLanguage::TYPE_MAT2: {
Transform2D val = V->get();
- // TODO
+ if (value.second.size() < 4) {
+ value.second.resize(4);
+ }
+
+ value.second.write[0].real = val.elements[0][0];
+ value.second.write[1].real = val.elements[0][1];
+ value.second.write[2].real = val.elements[1][0];
+ value.second.write[3].real = val.elements[1][1];
} break;
case ShaderLanguage::TYPE_MAT3: {
Basis val = V->get();
- // TODO
+ if (value.second.size() < 9) {
+ value.second.resize(9);
+ }
+
+ value.second.write[0].real = val.elements[0][0];
+ value.second.write[1].real = val.elements[0][1];
+ value.second.write[2].real = val.elements[0][2];
+ value.second.write[3].real = val.elements[1][0];
+ value.second.write[4].real = val.elements[1][1];
+ value.second.write[5].real = val.elements[1][2];
+ value.second.write[6].real = val.elements[2][0];
+ value.second.write[7].real = val.elements[2][1];
+ value.second.write[8].real = val.elements[2][2];
} break;
case ShaderLanguage::TYPE_MAT4: {
Transform val = V->get();
- // TODO
+ if (value.second.size() < 16) {
+ value.second.resize(16);
+ }
+
+ value.second.write[0].real = val.basis.elements[0][0];
+ value.second.write[1].real = val.basis.elements[0][1];
+ value.second.write[2].real = val.basis.elements[0][2];
+ value.second.write[3].real = 0;
+ value.second.write[4].real = val.basis.elements[1][0];
+ value.second.write[5].real = val.basis.elements[1][1];
+ value.second.write[6].real = val.basis.elements[1][2];
+ value.second.write[7].real = 0;
+ value.second.write[8].real = val.basis.elements[2][0];
+ value.second.write[9].real = val.basis.elements[2][1];
+ value.second.write[10].real = val.basis.elements[2][2];
+ value.second.write[11].real = 0;
+ value.second.write[12].real = val.origin[0];
+ value.second.write[13].real = val.origin[1];
+ value.second.write[14].real = val.origin[2];
+ value.second.write[15].real = 1;
} break;
case ShaderLanguage::TYPE_SAMPLER2D: {
@@ -1034,7 +1079,7 @@ void ShaderGLES2::use_material(void *p_material, int p_num_predef_textures) {
Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > value;
value.first = ShaderLanguage::TYPE_INT;
value.second.resize(1);
- value.second.write[0].sint = p_num_predef_textures + i;
+ value.second.write[0].sint = i;
// GLint location = get_uniform_location(textures[i].first);
diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h
index 49e45eea9f..cb515c199c 100644
--- a/drivers/gles2/shader_gles2.h
+++ b/drivers/gles2/shader_gles2.h
@@ -465,7 +465,7 @@ public:
// this void* is actually a RasterizerStorageGLES2::Material, but C++ doesn't
// like forward declared nested classes.
- void use_material(void *p_material, int p_num_predef_textures);
+ void use_material(void *p_material);
uint32_t get_version() const { return new_conditional_version.version; }
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index e08e9d1117..9251e21080 100644
--- a/drivers/gles2/shaders/scene.glsl
+++ b/drivers/gles2/shaders/scene.glsl
@@ -48,7 +48,7 @@ attribute highp vec4 bone_transform_row_2; // attrib:11
attribute vec4 bone_ids; // attrib:6
attribute highp vec4 bone_weights; // attrib:7
-uniform highp sampler2D bone_transforms; // texunit:4
+uniform highp sampler2D bone_transforms; // texunit:-1
uniform ivec2 skeleton_texture_size;
#endif
@@ -181,7 +181,7 @@ void main() {
#else
// look up transform from the "pose texture"
{
-
+
for (int i = 0; i < 4; i++) {
ivec2 tex_ofs = ivec2(int(bone_ids[i]) * 3, 0);
@@ -252,7 +252,7 @@ VERTEX_SHADER_CODE
float z_ofs = light_bias;
z_ofs += (1.0 - abs(normal_interp.z)) * light_normal_bias;
-
+
vertex_interp.z -= z_ofs;
#endif
@@ -294,17 +294,17 @@ uniform highp float time;
uniform vec2 screen_pixel_size;
#endif
-uniform highp sampler2D depth_buffer; //texunit:1
+uniform highp sampler2D depth_buffer; //texunit:-5
#if defined(SCREEN_TEXTURE_USED)
-uniform highp sampler2D screen_texture; //texunit:2
+uniform highp sampler2D screen_texture; //texunit:-6
#endif
#ifdef USE_RADIANCE_MAP
#define RADIANCE_MAX_LOD 6.0
-uniform samplerCube radiance_map; // texunit:0
+uniform samplerCube radiance_map; // texunit:-2
uniform mat4 radiance_inverse_xform;
@@ -345,7 +345,7 @@ uniform float light_spot_angle;
// shadows
-uniform highp sampler2D light_shadow_atlas; //texunit:3
+uniform highp sampler2D light_shadow_atlas; //texunit:-4
uniform float light_has_shadow;
uniform mat4 light_shadow_matrix;
@@ -353,7 +353,7 @@ uniform vec4 light_clamp;
// directional shadow
-uniform highp sampler2D light_directional_shadow; // texunit:3
+uniform highp sampler2D light_directional_shadow; // texunit:-4
uniform vec4 light_split_offsets;
uniform mat4 light_shadow_matrix1;
@@ -439,11 +439,10 @@ void light_compute(vec3 N,
{
// calculate specular reflection
- vec3 R = normalize(-reflect(L,N));
- float cRdotV = max(dot(R, V), 0.0);
- float blob_intensity = pow(cRdotV, (1.0 - roughness) * 256.0);
- specular_light += light_color * attenuation * blob_intensity * specular_blob_intensity;
-
+ vec3 R = normalize(-reflect(L,N));
+ float cRdotV = max(dot(R, V), 0.0);
+ float blob_intensity = pow(cRdotV, (1.0 - roughness) * 256.0);
+ specular_light += light_color * attenuation * blob_intensity * specular_blob_intensity;
}
}
@@ -460,7 +459,7 @@ float sample_shadow(highp sampler2D shadow,
vec4 clamp_rect)
{
// vec4 depth_value = texture2D(shadow, pos);
-
+
// return depth_value.z;
return texture2DProj(shadow, vec4(pos, depth, 1.0)).r;
// return (depth_value.x + depth_value.y + depth_value.z + depth_value.w) / 4.0;
@@ -469,22 +468,22 @@ float sample_shadow(highp sampler2D shadow,
#endif
-void main()
+void main()
{
highp vec3 vertex = vertex_interp;
- vec3 albedo = vec3(0.8, 0.8, 0.8);
+ vec3 albedo = vec3(1.0);
vec3 transmission = vec3(0.0);
float metallic = 0.0;
float specular = 0.5;
- vec3 emission = vec3(0.0, 0.0, 0.0);
+ vec3 emission = vec3(0.0);
float roughness = 1.0;
float rim = 0.0;
float rim_tint = 0.0;
float clearcoat = 0.0;
float clearcoat_gloss = 0.0;
- float anisotropy = 1.0;
- vec2 anisotropy_flow = vec2(1.0,0.0);
+ float anisotropy = 0.0;
+ vec2 anisotropy_flow = vec2(1.0, 0.0);
float alpha = 1.0;
float side = 1.0;
@@ -536,7 +535,7 @@ FRAGMENT_SHADER_CODE
normal = normalize(normal);
vec3 N = normal;
-
+
vec3 specular_light = vec3(0.0, 0.0, 0.0);
vec3 diffuse_light = vec3(0.0, 0.0, 0.0);
@@ -551,7 +550,7 @@ FRAGMENT_SHADER_CODE
discard;
}
#endif
-
+
//
// Lighting
//
@@ -621,11 +620,11 @@ FRAGMENT_SHADER_CODE
vec3 light_vec = -light_direction;
vec3 attenuation = vec3(1.0, 1.0, 1.0);
-
+
float depth_z = -vertex.z;
-
+
if (light_has_shadow > 0.5) {
-
+
#ifdef LIGHT_USE_PSSM4
if (depth_z < light_split_offsets.w) {
#elif defined(LIGHT_USE_PSSM2)
@@ -633,36 +632,36 @@ FRAGMENT_SHADER_CODE
#else
if (depth_z < light_split_offsets.x) {
#endif
-
+
vec3 pssm_coord;
float pssm_fade = 0.0;
-
+
#ifdef LIGHT_USE_PSSM_BLEND
float pssm_blend;
vec3 pssm_coord2;
bool use_blend = true;
#endif
-
+
#ifdef LIGHT_USE_PSSM4
if (depth_z < light_split_offsets.y) {
if (depth_z < light_split_offsets.x) {
highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0));
pssm_coord = splane.xyz / splane.w;
-
+
#ifdef LIGHT_USE_PSSM_BLEND
splane = (light_shadow_matrix2 * vec4(vertex, 1.0));
pssm_coord2 = splane.xyz / splane.w;
-
+
pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
#endif
} else {
highp vec4 splane = (light_shadow_matrix2 * vec4(vertex, 1.0));
pssm_coord = splane.xyz / splane.w;
-
+
#ifdef LIGHT_USE_PSSM_BLEND
splane = (light_shadow_matrix3 * vec4(vertex, 1.0));
pssm_coord2 = splane.xyz / splane.w;
-
+
pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z);
#endif
}
@@ -689,15 +688,15 @@ FRAGMENT_SHADER_CODE
#endif
}
}
-
+
#endif // LIGHT_USE_PSSM4
-
+
#ifdef LIGHT_USE_PSSM2
if (depth_z < light_split_offsets.x) {
-
+
highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0));
pssm_coord = splane.xyz / splane.w;
-
+
#ifdef LIGHT_USE_PSSM_BLEND
splane = (light_shadow_matrix2 * vec4(vertex, 1.0));
pssm_coord2 = splane.xyz / splane.w;
@@ -711,29 +710,29 @@ FRAGMENT_SHADER_CODE
use_blend = false;
#endif
}
-
+
#endif // LIGHT_USE_PSSM2
-
+
#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2)
{
highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0));
pssm_coord = splane.xyz / splane.w;
}
#endif
-
+
float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), pssm_coord.xy, pssm_coord.z, light_clamp);
-
+
#ifdef LIGHT_USE_PSSM_BLEND
if (use_blend) {
shadow = mix(shadow, sample_shadow(light_shadow_atlas, vec2(0.0), pssm_coord2.xy, pssm_coord2.z, light_clamp), pssm_blend);
}
#endif
-
+
attenuation *= shadow;
-
-
+
+
}
-
+
}
light_compute(normal,
@@ -758,19 +757,19 @@ FRAGMENT_SHADER_CODE
} else if (light_type == LIGHT_TYPE_SPOT) {
vec3 light_att = vec3(1.0);
-
+
if (light_has_shadow > 0.5) {
highp vec4 splane = (light_shadow_matrix * vec4(vertex, 1.0));
splane.xyz /= splane.w;
-
+
float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), splane.xy, splane.z, light_clamp);
-
+
if (shadow > splane.z) {
} else {
light_att = vec3(0.0);
}
-
-
+
+
}
vec3 light_rel_vec = light_position - vertex;
@@ -788,7 +787,7 @@ FRAGMENT_SHADER_CODE
spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation);
light_att *= vec3(spot_attenuation);
-
+
light_compute(normal,
normalize(light_rel_vec),
eye_position,
@@ -808,7 +807,6 @@ FRAGMENT_SHADER_CODE
anisotropy,
diffuse_light,
specular_light);
-
}
gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha);
@@ -837,9 +835,9 @@ FRAGMENT_SHADER_CODE
}
ambient_light *= ambient_energy;
-
+
specular_light += env_reflection_light;
-
+
ambient_light *= albedo;
#if defined(ENABLE_AO)
@@ -848,12 +846,12 @@ FRAGMENT_SHADER_CODE
specular_light *= ao_light_affect;
diffuse_light *= ao_light_affect;
#endif
-
+
diffuse_light *= 1.0 - metallic;
ambient_light *= 1.0 - metallic;
-
+
// environment BRDF approximation
-
+
// TODO shadeless
{
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 0053b6311f..cb17695c5f 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -290,7 +290,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
canvas->canvas_begin();
RID texture = storage->texture_create();
- storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), VS::TEXTURE_FLAG_FILTER);
+ storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
storage->texture_set_data(texture, p_image);
Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height());
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index d01ba2ddcc..eebdbe9493 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1190,6 +1190,7 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m
int tc = p_material->textures.size();
RID *textures = p_material->textures.ptrw();
ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptrw();
+ const ShaderLanguage::DataType *texture_types = p_material->shader->texture_types.ptr();
state.current_main_tex = 0;
@@ -1198,39 +1199,17 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m
glActiveTexture(GL_TEXTURE0 + i);
GLenum target;
- GLuint tex;
+ GLuint tex = 0;
- RasterizerStorageGLES3::Texture *t = storage->texture_owner.getornull(textures[i]);
+ RasterizerStorageGLES3::Texture *t = storage->texture_owner.getptr(textures[i]);
- if (!t) {
- //check hints
- target = GL_TEXTURE_2D;
-
- switch (texture_hints[i]) {
- case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO:
- case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: {
- tex = storage->resources.black_tex;
- } break;
- case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
- tex = storage->resources.aniso_tex;
- } break;
- case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: {
- tex = storage->resources.normal_tex;
-
- } break;
- default: {
- tex = storage->resources.white_tex;
- } break;
- }
-
- } else {
+ if (t) {
if (t->redraw_if_visible) { //must check before proxy because this is often used with proxies
VisualServerRaster::redraw_request();
}
t = t->get_ptr(); //resolve for proxies
-
#ifdef TOOLS_ENABLED
if (t->detect_3d) {
t->detect_3d(t->detect_3d_ud);
@@ -1247,6 +1226,59 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m
target = t->target;
tex = t->tex_id;
+ } else {
+
+ switch (texture_types[i]) {
+ case ShaderLanguage::TYPE_ISAMPLER2D:
+ case ShaderLanguage::TYPE_USAMPLER2D:
+ case ShaderLanguage::TYPE_SAMPLER2D: {
+ target = GL_TEXTURE_2D;
+
+ switch (texture_hints[i]) {
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO:
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: {
+ tex = storage->resources.black_tex;
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
+ tex = storage->resources.aniso_tex;
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: {
+ tex = storage->resources.normal_tex;
+
+ } break;
+ default: {
+ tex = storage->resources.white_tex;
+ } break;
+ }
+
+ } break;
+
+ case ShaderLanguage::TYPE_SAMPLERCUBE: {
+ // TODO
+ } break;
+
+ case ShaderLanguage::TYPE_ISAMPLER3D:
+ case ShaderLanguage::TYPE_USAMPLER3D:
+ case ShaderLanguage::TYPE_SAMPLER3D: {
+
+ target = GL_TEXTURE_3D;
+
+ switch (texture_hints[i]) {
+
+ // TODO
+ default: {
+ tex = storage->resources.white_tex_3d;
+ } break;
+ }
+
+ } break;
+
+ case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_USAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_SAMPLER2DARRAY: {
+ // TODO
+ } break;
+ }
}
glBindTexture(target, tex);
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index c1c1b2a009..a5c81d6c4d 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -595,7 +595,7 @@ RID RasterizerStorageGLES3::texture_create() {
return texture_owner.make_rid(texture);
}
-void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags) {
+void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VisualServer::TextureType p_type, uint32_t p_flags) {
GLenum format;
GLenum internal_format;
@@ -612,15 +612,37 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_
ERR_FAIL_COND(!texture);
texture->width = p_width;
texture->height = p_height;
+ texture->depth = p_depth_3d;
texture->format = p_format;
texture->flags = p_flags;
texture->stored_cube_sides = 0;
- texture->target = (p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
+
+ texture->type = p_type;
+
+ switch (p_type) {
+ case VS::TEXTURE_TYPE_2D: {
+ texture->target = GL_TEXTURE_2D;
+ texture->images.resize(1);
+ } break;
+ case VS::TEXTURE_TYPE_CUBEMAP: {
+ texture->target = GL_TEXTURE_CUBE_MAP;
+ texture->images.resize(6);
+ } break;
+ case VS::TEXTURE_TYPE_2D_ARRAY: {
+ texture->target = GL_TEXTURE_2D_ARRAY;
+ texture->images.resize(p_depth_3d);
+ } break;
+ case VS::TEXTURE_TYPE_3D: {
+ texture->target = GL_TEXTURE_3D;
+ texture->images.resize(p_depth_3d);
+ } break;
+ }
_get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, format, internal_format, type, compressed, srgb);
texture->alloc_width = texture->width;
texture->alloc_height = texture->height;
+ texture->alloc_depth = texture->depth;
texture->gl_format_cache = format;
texture->gl_type_cache = type;
@@ -633,7 +655,34 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
- if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+ if (p_type == VS::TEXTURE_TYPE_3D || p_type == VS::TEXTURE_TYPE_2D_ARRAY) {
+
+ int width = p_width;
+ int height = p_height;
+ int depth = p_depth_3d;
+
+ int mipmaps = 0;
+
+ while (width != 1 && height != 1) {
+ glTexImage3D(texture->target, 0, internal_format, width, height, depth, 0, format, type, NULL);
+
+ width = MAX(1, width / 2);
+ height = MAX(1, height / 2);
+
+ if (p_type == VS::TEXTURE_TYPE_3D) {
+ depth = MAX(1, depth / 2);
+ }
+
+ mipmaps++;
+
+ if (!(p_flags & VS::TEXTURE_FLAG_MIPMAPS))
+ break;
+ }
+
+ glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1);
+
+ } else if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
//prealloc if video
glTexImage2D(texture->target, 0, internal_format, p_width, p_height, 0, format, type, NULL);
}
@@ -641,7 +690,7 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_
texture->active = true;
}
-void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side) {
+void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) {
Texture *texture = texture_owner.get(p_texture);
@@ -658,7 +707,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
bool srgb;
if (config.keep_original_textures && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
- texture->images[p_cube_side] = p_image;
+ texture->images.write[p_layer] = p_image;
}
Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, format, internal_format, type, compressed, srgb);
@@ -677,7 +726,23 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
}
};
- GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_cube_side] : GL_TEXTURE_2D;
+ GLenum blit_target;
+
+ switch (texture->type) {
+ case VS::TEXTURE_TYPE_2D: {
+ blit_target = GL_TEXTURE_2D;
+ } break;
+ case VS::TEXTURE_TYPE_CUBEMAP: {
+ ERR_FAIL_INDEX(p_layer, 6);
+ blit_target = _cube_side_enum[p_layer];
+ } break;
+ case VS::TEXTURE_TYPE_2D_ARRAY: {
+ blit_target = GL_TEXTURE_2D_ARRAY;
+ } break;
+ case VS::TEXTURE_TYPE_3D: {
+ blit_target = GL_TEXTURE_3D;
+ } break;
+ }
texture->data_size = img->get_data().size();
PoolVector<uint8_t>::Read read = img->get_data().read();
@@ -785,20 +850,36 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
//print_line("mipmap: "+itos(i)+" size: "+itos(size)+" w: "+itos(mm_w)+", h: "+itos(mm_h));
- if (texture->compressed) {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) {
+
+ if (texture->compressed) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- int bw = w;
- int bh = h;
+ int bw = w;
+ int bh = h;
- glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]);
+ glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]);
+ } else {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+ glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]);
+ } else {
+ glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+ }
+ }
} else {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
- glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]);
+ if (texture->compressed) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ int bw = w;
+ int bh = h;
+
+ glCompressedTexSubImage3D(blit_target, i, 0, 0, p_layer, bw, bh, 1, internal_format, size, &read[ofs]);
} else {
- glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glTexSubImage3D(blit_target, i, 0, 0, p_layer, w, h, 1, format, type, &read[ofs]);
}
}
tsize += size;
@@ -813,14 +894,17 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
//printf("texture: %i x %i - size: %i - total: %i\n",texture->width,texture->height,tsize,_rinfo.texture_mem);
- texture->stored_cube_sides |= (1 << p_cube_side);
+ texture->stored_cube_sides |= (1 << p_layer);
- if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (!(texture->flags & VS::TEXTURE_FLAG_CUBEMAP) || texture->stored_cube_sides == (1 << 6) - 1)) {
+ if ((texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) && (texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != VS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) {
//generate mipmaps if they were requested and the image does not contain them
glGenerateMipmap(texture->target);
} else if (mipmaps > 1) {
glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1);
+ } else {
+ glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, 0);
}
texture->mipmaps = mipmaps;
@@ -831,7 +915,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
// Uploads pixel data to a sub-region of a texture, for the specified mipmap.
// The texture pixels must have been allocated before, because most features seen in texture_set_data() make no sense in a partial update.
// TODO If we want this to be usable without pre-filling pixels with a full image, we have to call glTexImage2D() with null data.
-void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side) {
+void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer) {
Texture *texture = texture_owner.get(p_texture);
@@ -859,7 +943,23 @@ void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<I
Ref<Image> img = _get_gl_image_and_format(p_sub_img, p_sub_img->get_format(), texture->flags, format, internal_format, type, compressed, srgb);
- GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_cube_side] : GL_TEXTURE_2D;
+ GLenum blit_target;
+
+ switch (texture->type) {
+ case VS::TEXTURE_TYPE_2D: {
+ blit_target = GL_TEXTURE_2D;
+ } break;
+ case VS::TEXTURE_TYPE_CUBEMAP: {
+ ERR_FAIL_INDEX(p_layer, 6);
+ blit_target = _cube_side_enum[p_layer];
+ } break;
+ case VS::TEXTURE_TYPE_2D_ARRAY: {
+ blit_target = GL_TEXTURE_2D_ARRAY;
+ } break;
+ case VS::TEXTURE_TYPE_3D: {
+ blit_target = GL_TEXTURE_3D;
+ } break;
+ }
PoolVector<uint8_t>::Read read = img->get_data().read();
@@ -869,18 +969,38 @@ void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<I
int src_data_size = img->get_data().size();
int src_ofs = 0;
- if (texture->compressed) {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- glCompressedTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, internal_format, src_data_size, &read[src_ofs]);
+ if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) {
+ if (texture->compressed) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glCompressedTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, internal_format, src_data_size, &read[src_ofs]);
+ } else {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ // `format` has to match the internal_format used when the texture was created
+ glTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, format, type, &read[src_ofs]);
+ }
} else {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- // `format` has to match the internal_format used when the texture was created
- glTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, format, type, &read[src_ofs]);
+ if (texture->compressed) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glCompressedTexSubImage3D(blit_target, p_dst_mip, dst_x, dst_y, p_layer, src_w, src_h, 1, format, src_data_size, &read[src_ofs]);
+ } else {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ // `format` has to match the internal_format used when the texture was created
+ glTexSubImage3D(blit_target, p_dst_mip, dst_x, dst_y, p_layer, src_w, src_h, 1, format, type, &read[src_ofs]);
+ }
+ }
+
+ if (texture->flags & VS::TEXTURE_FLAG_FILTER) {
+
+ glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering
+
+ } else {
+
+ glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering
}
}
-Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side) const {
+Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) const {
Texture *texture = texture_owner.get(p_texture);
@@ -888,8 +1008,8 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSi
ERR_FAIL_COND_V(!texture->active, Ref<Image>());
ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref<Image>());
- if (!texture->images[p_cube_side].is_null()) {
- return texture->images[p_cube_side];
+ if (texture->type == VS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && !texture->images[p_layer].is_null()) {
+ return texture->images[p_layer];
}
#ifdef GLES_OVER_GL
@@ -977,10 +1097,10 @@ void RasterizerStorageGLES3::texture_set_flags(RID p_texture, uint32_t p_flags)
bool had_mipmaps = texture->flags & VS::TEXTURE_FLAG_MIPMAPS;
+ texture->flags = p_flags;
+
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
- uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP;
- texture->flags = p_flags | cube; // can't remove a cube from being a cube
if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) {
@@ -1058,6 +1178,14 @@ Image::Format RasterizerStorageGLES3::texture_get_format(RID p_texture) const {
return texture->format;
}
+
+VisualServer::TextureType RasterizerStorageGLES3::texture_get_type(RID p_texture) const {
+ Texture *texture = texture_owner.get(p_texture);
+
+ ERR_FAIL_COND_V(!texture, VS::TEXTURE_TYPE_2D);
+
+ return texture->type;
+}
uint32_t RasterizerStorageGLES3::texture_get_texid(RID p_texture) const {
Texture *texture = texture_owner.get(p_texture);
@@ -1083,7 +1211,16 @@ uint32_t RasterizerStorageGLES3::texture_get_height(RID p_texture) const {
return texture->height;
}
-void RasterizerStorageGLES3::texture_set_size_override(RID p_texture, int p_width, int p_height) {
+uint32_t RasterizerStorageGLES3::texture_get_depth(RID p_texture) const {
+
+ Texture *texture = texture_owner.get(p_texture);
+
+ ERR_FAIL_COND_V(!texture, 0);
+
+ return texture->depth;
+}
+
+void RasterizerStorageGLES3::texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth) {
Texture *texture = texture_owner.get(p_texture);
@@ -1123,8 +1260,9 @@ void RasterizerStorageGLES3::texture_debug_usage(List<VS::TextureInfo> *r_info)
VS::TextureInfo tinfo;
tinfo.path = t->path;
tinfo.format = t->format;
- tinfo.size.x = t->alloc_width;
- tinfo.size.y = t->alloc_height;
+ tinfo.width = t->alloc_width;
+ tinfo.height = t->alloc_height;
+ tinfo.depth = 0;
tinfo.bytes = t->total_data_size;
r_info->push_back(tinfo);
}
@@ -1169,7 +1307,7 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_
Texture *texture = texture_owner.get(p_source);
ERR_FAIL_COND_V(!texture, RID());
- ERR_FAIL_COND_V(!(texture->flags & VS::TEXTURE_FLAG_CUBEMAP), RID());
+ ERR_FAIL_COND_V(texture->type != VS::TEXTURE_TYPE_CUBEMAP, RID());
bool use_float = config.hdr_supported;
@@ -1285,7 +1423,8 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_
Texture *ctex = memnew(Texture);
- ctex->flags = VS::TEXTURE_FLAG_CUBEMAP | VS::TEXTURE_FLAG_MIPMAPS | VS::TEXTURE_FLAG_FILTER;
+ ctex->type = VS::TEXTURE_TYPE_CUBEMAP;
+ ctex->flags = VS::TEXTURE_FLAG_MIPMAPS | VS::TEXTURE_FLAG_FILTER;
ctex->width = p_resolution;
ctex->height = p_resolution;
ctex->alloc_width = p_resolution;
@@ -1765,6 +1904,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const {
p_shader->ubo_offsets = gen_code.uniform_offsets;
p_shader->texture_count = gen_code.texture_uniforms.size();
p_shader->texture_hints = gen_code.texture_hints;
+ p_shader->texture_types = gen_code.texture_types;
p_shader->uses_vertex_time = gen_code.uses_vertex_time;
p_shader->uses_fragment_time = gen_code.uses_fragment_time;
@@ -1875,6 +2015,13 @@ void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyIn
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
pi.hint_string = "Texture";
} break;
+ case ShaderLanguage::TYPE_SAMPLER3D:
+ case ShaderLanguage::TYPE_ISAMPLER3D:
+ case ShaderLanguage::TYPE_USAMPLER3D: {
+ pi.type = Variant::OBJECT;
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "Texture3D";
+ } break;
case ShaderLanguage::TYPE_SAMPLERCUBE: {
pi.type = Variant::OBJECT;
@@ -2649,6 +2796,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) {
//set up the texture array, for easy access when it needs to be drawn
if (material->shader && material->shader->texture_count) {
+ material->texture_is_3d.resize(material->shader->texture_count);
material->textures.resize(material->shader->texture_count);
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) {
@@ -2658,6 +2806,16 @@ void RasterizerStorageGLES3::_update_material(Material *material) {
RID texture;
+ switch (E->get().type) {
+ case ShaderLanguage::TYPE_SAMPLER3D:
+ case ShaderLanguage::TYPE_SAMPLER2DARRAY: {
+ material->texture_is_3d.write[E->get().texture_order] = true;
+ } break;
+ default: {
+ material->texture_is_3d.write[E->get().texture_order] = false;
+ } break;
+ }
+
Map<StringName, Variant>::Element *V = material->params.find(E->key());
if (V) {
texture = V->get();
@@ -2675,6 +2833,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) {
} else {
material->textures.clear();
+ material->texture_is_3d.clear();
}
}
@@ -6999,6 +7158,7 @@ bool RasterizerStorageGLES3::free(RID p_rid) {
info.texture_mem -= texture->total_data_size;
texture_owner.free(p_rid);
memdelete(texture);
+
} else if (sky_owner.owns(p_rid)) {
// delete the sky
Sky *sky = sky_owner.get(p_rid);
@@ -7408,6 +7568,15 @@ void RasterizerStorageGLES3::initialize() {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, anisotexdata);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
+
+ glGenTextures(1, &resources.white_tex_3d);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_3D, resources.white_tex_3d);
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 2, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata);
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0);
}
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units);
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index d9c770d1b7..f55c8026ea 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -123,6 +123,8 @@ public:
GLuint normal_tex;
GLuint aniso_tex;
+ GLuint white_tex_3d;
+
GLuint quadie;
GLuint quadie_array;
@@ -248,9 +250,10 @@ public:
String path;
uint32_t flags;
- int width, height;
- int alloc_width, alloc_height;
+ int width, height, depth;
+ int alloc_width, alloc_height, alloc_depth;
Image::Format format;
+ VS::TextureType type;
GLenum target;
GLenum gl_format_cache;
@@ -274,7 +277,7 @@ public:
RenderTarget *render_target;
- Ref<Image> images[6];
+ Vector<Ref<Image> > images;
VisualServer::TextureDetectCallback detect_3d;
void *detect_3d_ud;
@@ -340,17 +343,19 @@ public:
Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &srgb);
virtual RID texture_create();
- virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);
- virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT);
- virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT);
- virtual Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const;
+ virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);
+ virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
+ virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer = 0);
+ virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const;
virtual void texture_set_flags(RID p_texture, uint32_t p_flags);
virtual uint32_t texture_get_flags(RID p_texture) const;
virtual Image::Format texture_get_format(RID p_texture) const;
+ virtual VS::TextureType texture_get_type(RID p_texture) const;
virtual uint32_t texture_get_texid(RID p_texture) const;
virtual uint32_t texture_get_width(RID p_texture) const;
virtual uint32_t texture_get_height(RID p_texture) const;
- virtual void texture_set_size_override(RID p_texture, int p_width, int p_height);
+ virtual uint32_t texture_get_depth(RID p_texture) const;
+ virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth);
virtual void texture_set_path(RID p_texture, const String &p_path);
virtual String texture_get_path(RID p_texture) const;
@@ -410,6 +415,7 @@ public:
Map<StringName, RID> default_textures;
+ Vector<ShaderLanguage::DataType> texture_types;
Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints;
bool valid;
@@ -532,6 +538,7 @@ public:
Map<StringName, Variant> params;
SelfList<Material> list;
SelfList<Material> dirty_list;
+ Vector<bool> texture_is_3d;
Vector<RID> textures;
float line_width;
int render_priority;
diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp
index 4ff8c72e13..0c353d42bb 100644
--- a/drivers/gles3/shader_compiler_gles3.cpp
+++ b/drivers/gles3/shader_compiler_gles3.cpp
@@ -341,6 +341,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
r_gen_code.texture_uniforms.resize(max_texture_uniforms);
r_gen_code.texture_hints.resize(max_texture_uniforms);
+ r_gen_code.texture_types.resize(max_texture_uniforms);
Vector<int> uniform_sizes;
Vector<int> uniform_alignments;
@@ -367,6 +368,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
r_gen_code.fragment_global += ucode;
r_gen_code.texture_uniforms.write[E->get().texture_order] = _mkid(E->key());
r_gen_code.texture_hints.write[E->get().texture_order] = E->get().hint;
+ r_gen_code.texture_types.write[E->get().texture_order] = E->get().type;
} else {
if (!uses_uniforms) {
@@ -700,6 +702,11 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
}
} else if (cfnode->flow_op == SL::FLOW_OP_DISCARD) {
+ if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) {
+ *p_actions.usage_flag_pointers["DISCARD"] = true;
+ used_flag_pointers.insert("DISCARD");
+ }
+
code = "discard;";
} else if (cfnode->flow_op == SL::FLOW_OP_CONTINUE) {
diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h
index bf776ee062..7a32057741 100644
--- a/drivers/gles3/shader_compiler_gles3.h
+++ b/drivers/gles3/shader_compiler_gles3.h
@@ -52,6 +52,7 @@ public:
Vector<CharString> defines;
Vector<StringName> texture_uniforms;
+ Vector<ShaderLanguage::DataType> texture_types;
Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints;
Vector<uint32_t> uniform_offsets;
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 6fd85cc1dd..dee8bcbc58 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -339,7 +339,7 @@ void main() {
#endif
#endif
- float roughness=0.0;
+ float roughness = 1.0;
//defines that make writing custom shaders easier
#define projection_matrix local_projection
@@ -1608,18 +1608,18 @@ void main() {
//lay out everything, whathever is unused is optimized away anyway
highp vec3 vertex = vertex_interp;
- vec3 albedo = vec3(0.8,0.8,0.8);
+ vec3 albedo = vec3(1.0);
vec3 transmission = vec3(0.0);
float metallic = 0.0;
float specular = 0.5;
- vec3 emission = vec3(0.0,0.0,0.0);
+ vec3 emission = vec3(0.0);
float roughness = 1.0;
float rim = 0.0;
float rim_tint = 0.0;
- float clearcoat=0.0;
- float clearcoat_gloss=0.0;
- float anisotropy = 1.0;
- vec2 anisotropy_flow = vec2(1.0,0.0);
+ float clearcoat = 0.0;
+ float clearcoat_gloss = 0.0;
+ float anisotropy = 0.0;
+ vec2 anisotropy_flow = vec2(1.0, 0.0);
#if defined(ENABLE_AO)
float ao=1.0;
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 4ce8556add..29275947a4 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1246,6 +1246,29 @@ CodeTextEditor::CodeTextEditor() {
status_bar->add_child(memnew(Label)); //to keep the height if the other labels are not visible
+ warning_label = memnew(Label);
+ status_bar->add_child(warning_label);
+ warning_label->set_align(Label::ALIGN_RIGHT);
+ warning_label->set_valign(Label::VALIGN_CENTER);
+ warning_label->set_v_size_flags(SIZE_FILL);
+ warning_label->set_default_cursor_shape(CURSOR_POINTING_HAND);
+ warning_label->set_mouse_filter(MOUSE_FILTER_STOP);
+ warning_label->set_text(TTR("Warnings:"));
+ warning_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
+
+ warning_count_label = memnew(Label);
+ status_bar->add_child(warning_count_label);
+ warning_count_label->set_valign(Label::VALIGN_CENTER);
+ warning_count_label->set_v_size_flags(SIZE_FILL);
+ warning_count_label->set_autowrap(true); // workaround to prevent resizing the label on each change, do not touch
+ warning_count_label->set_clip_text(true); // workaround to prevent resizing the label on each change, do not touch
+ warning_count_label->set_custom_minimum_size(Size2(40, 1) * EDSCALE);
+ warning_count_label->set_align(Label::ALIGN_RIGHT);
+ warning_count_label->set_default_cursor_shape(CURSOR_POINTING_HAND);
+ warning_count_label->set_mouse_filter(MOUSE_FILTER_STOP);
+ warning_count_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
+ warning_count_label->set_text("0");
+
Label *zoom_txt = memnew(Label);
status_bar->add_child(zoom_txt);
zoom_txt->set_align(Label::ALIGN_RIGHT);
diff --git a/editor/code_editor.h b/editor/code_editor.h
index 903f61d87d..ee47eff9a8 100644
--- a/editor/code_editor.h
+++ b/editor/code_editor.h
@@ -142,6 +142,8 @@ class CodeTextEditor : public VBoxContainer {
TextEdit *text_editor;
FindReplaceBar *find_replace_bar;
HBoxContainer *status_bar;
+ Label *warning_label;
+ Label *warning_count_label;
Label *line_nb;
Label *col_nb;
@@ -214,6 +216,8 @@ public:
void update_line_and_column() { _line_col_changed(); }
TextEdit *get_text_edit() { return text_editor; }
FindReplaceBar *get_find_replace_bar() { return find_replace_bar; }
+ Label *get_warning_label() const { return warning_label; }
+ Label *get_warning_count_label() const { return warning_count_label; }
virtual void apply_code() {}
void set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func, void *p_ud);
diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp
index 2803762973..91a29f5717 100644
--- a/editor/doc/doc_data.cpp
+++ b/editor/doc/doc_data.cpp
@@ -535,13 +535,14 @@ void DocData::generate(bool p_basic_types) {
}
List<StringName> constants;
- Variant::get_numeric_constants_for_type(Variant::Type(i), &constants);
+ Variant::get_constants_for_type(Variant::Type(i), &constants);
for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
ConstantDoc constant;
constant.name = E->get();
- constant.value = itos(Variant::get_numeric_constant_value(Variant::Type(i), E->get()));
+ Variant value = Variant::get_constant_value(Variant::Type(i), E->get());
+ constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string();
c.constants.push_back(constant);
}
}
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index 4b09db0a9e..e4602f0f94 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -113,7 +113,7 @@ ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<St
EditorAbout::EditorAbout() {
set_title(TTR("Thanks from the Godot community!"));
- get_ok()->set_text(TTR("Thanks!"));
+ get_ok()->set_text(TTR("OK"));
set_hide_on_ok(true);
set_resizable(true);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 727383b960..b7a5f67870 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -1214,6 +1214,18 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
constant_line[constants[i].name] = class_desc->get_line_count() - 2;
class_desc->push_font(doc_code_font);
+
+ if (constants[i].value.begins_with("Color(") && constants[i].value.ends_with(")")) {
+ String stripped = constants[i].value.replace(" ", "").replace("Color(", "").replace(")", "");
+ Vector<float> color = stripped.split_floats(",");
+ if (color.size() >= 3) {
+ class_desc->push_color(Color(color[0], color[1], color[2]));
+ static const CharType prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
+ class_desc->add_text(String(prefix));
+ class_desc->pop();
+ }
+ }
+
class_desc->push_color(headline_color);
_add_text(constants[i].name);
class_desc->pop();
@@ -1223,6 +1235,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->push_color(value_color);
_add_text(constants[i].value);
class_desc->pop();
+
class_desc->pop();
if (constants[i].description != "") {
class_desc->push_font(doc_font);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 488980db07..99a2b2aa67 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -43,6 +43,9 @@
Size2 EditorProperty::get_minimum_size() const {
Size2 ms;
+ Ref<Font> font = get_font("font", "Tree");
+ ms.height = font->get_height();
+
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@@ -70,12 +73,10 @@ Size2 EditorProperty::get_minimum_size() const {
ms.width += check->get_width() + get_constant("hseparator", "Tree");
}
- if (bottom_editor != NULL) {
- Ref<Font> font = get_font("font", "Tree");
- ms.height += font->get_height();
+ if (bottom_editor != NULL && bottom_editor->is_visible()) {
ms.height += get_constant("vseparation", "Tree");
Size2 bems = bottom_editor->get_combined_minimum_size();
- bems.width += get_constant("item_margin", "Tree");
+ //bems.width += get_constant("item_margin", "Tree");
ms.height += bems.height;
ms.width = MAX(ms.width, bems.width);
}
@@ -98,6 +99,7 @@ void EditorProperty::_notification(int p_what) {
int child_room = size.width * (1.0 - split_ratio);
Ref<Font> font = get_font("font", "Tree");
int height = font->get_height();
+ bool no_children = true;
//compute room needed
for (int i = 0; i < get_child_count(); i++) {
@@ -113,11 +115,16 @@ void EditorProperty::_notification(int p_what) {
Size2 minsize = c->get_combined_minimum_size();
child_room = MAX(child_room, minsize.width);
height = MAX(height, minsize.height);
+ no_children = false;
}
- text_size = MAX(0, size.width - child_room + 4 * EDSCALE);
-
- rect = Rect2(text_size, 0, size.width - text_size, height);
+ if (no_children) {
+ text_size = size.width;
+ rect = Rect2(size.width - 1, 0, 1, height);
+ } else {
+ text_size = MAX(0, size.width - (child_room + 4 * EDSCALE));
+ rect = Rect2(size.width - child_room, 0, child_room, height);
+ }
if (bottom_editor) {
@@ -178,7 +185,7 @@ void EditorProperty::_notification(int p_what) {
draw_style_box(sb, Rect2(Vector2(), size));
}
- if (right_child_rect != Rect2()) {
+ if (draw_top_bg && right_child_rect != Rect2()) {
draw_rect(right_child_rect, dark_color);
}
if (bottom_child_rect != Rect2()) {
@@ -189,7 +196,7 @@ void EditorProperty::_notification(int p_what) {
if (draw_red) {
color = get_color("error_color", "Editor");
} else {
- color = get_color("font_color", "Tree");
+ color = get_color("property_color", "Editor");
}
if (label.find(".") != -1) {
color.a = 0.5; //this should be un-hacked honestly, as it's used for editor overrides
@@ -787,6 +794,8 @@ void EditorProperty::_bind_methods() {
EditorProperty::EditorProperty() {
+ draw_top_bg = true;
+ object = NULL;
split_ratio = 0.5;
selectable = true;
text_size = 0;
@@ -1613,32 +1622,10 @@ void EditorInspector::update_tree() {
for (List<EditorInspectorPlugin::AddedEditor>::Element *F = editors.front(); F; F = F->next()) {
EditorProperty *ep = Object::cast_to<EditorProperty>(F->get().property_editor);
- current_vbox->add_child(F->get().property_editor);
if (ep) {
-
+ //set all this before the control gets the ENTER_TREE notification
ep->object = object;
- ep->connect("property_changed", this, "_property_changed");
- if (p.usage & PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED) {
- ep->connect("property_changed", this, "_property_changed_update_all", varray(), CONNECT_DEFERRED);
- }
- ep->connect("property_keyed", this, "_property_keyed");
- ep->connect("property_keyed_with_value", this, "_property_keyed_with_value");
- ep->connect("property_checked", this, "_property_checked");
- ep->connect("selected", this, "_property_selected");
- ep->connect("multiple_properties_changed", this, "_multiple_properties_changed");
- ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED);
- ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED);
- if (doc_hint != String()) {
- ep->set_tooltip(property_prefix + p.name + "::" + doc_hint);
- } else {
- ep->set_tooltip(property_prefix + p.name);
- }
- ep->set_draw_red(draw_red);
- ep->set_use_folding(use_folding);
- ep->set_checkable(checkable);
- ep->set_checked(checked);
- ep->set_keying(keying);
if (F->get().properties.size()) {
@@ -1664,8 +1651,35 @@ void EditorInspector::update_tree() {
editor_property_map[prop].push_back(ep);
}
}
+ ep->set_draw_red(draw_red);
+ ep->set_use_folding(use_folding);
+ ep->set_checkable(checkable);
+ ep->set_checked(checked);
+ ep->set_keying(keying);
ep->set_read_only(read_only);
+ }
+
+ current_vbox->add_child(F->get().property_editor);
+
+ if (ep) {
+
+ ep->connect("property_changed", this, "_property_changed");
+ if (p.usage & PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED) {
+ ep->connect("property_changed", this, "_property_changed_update_all", varray(), CONNECT_DEFERRED);
+ }
+ ep->connect("property_keyed", this, "_property_keyed");
+ ep->connect("property_keyed_with_value", this, "_property_keyed_with_value");
+ ep->connect("property_checked", this, "_property_checked");
+ ep->connect("selected", this, "_property_selected");
+ ep->connect("multiple_properties_changed", this, "_multiple_properties_changed");
+ ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED);
+ ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED);
+ if (doc_hint != String()) {
+ ep->set_tooltip(property_prefix + p.name + "::" + doc_hint);
+ } else {
+ ep->set_tooltip(property_prefix + p.name);
+ }
ep->update_property();
ep->update_reload_status();
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 454622d662..ebe2124a40 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -68,6 +68,7 @@ private:
bool can_revert;
bool use_folding;
+ bool draw_top_bg;
bool _might_be_in_instance();
bool _is_property_different(const Variant &p_current, const Variant &p_orig, int p_usage);
@@ -149,6 +150,8 @@ public:
String get_tooltip_text() const;
+ void set_draw_top_bg(bool p_draw) { draw_top_bg = p_draw; }
+
EditorProperty();
};
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 15e40bfba1..81b7a66361 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -63,6 +63,7 @@
#include "editor/import/resource_importer_bitmask.h"
#include "editor/import/resource_importer_csv_translation.h"
#include "editor/import/resource_importer_image.h"
+#include "editor/import/resource_importer_layered_texture.h"
#include "editor/import/resource_importer_obj.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/import/resource_importer_texture.h"
@@ -600,7 +601,7 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St
Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS);
if (err != OK) {
- show_accept(TTR("Error saving resource!"), TTR("I see..."));
+ show_accept(TTR("Error saving resource!"), TTR("OK"));
return;
}
@@ -690,15 +691,15 @@ void EditorNode::_dialog_display_save_error(String p_file, Error p_error) {
case ERR_FILE_CANT_WRITE: {
- show_accept(TTR("Can't open file for writing:") + " " + p_file.get_extension(), TTR("I see..."));
+ show_accept(TTR("Can't open file for writing:") + " " + p_file.get_extension(), TTR("OK"));
} break;
case ERR_FILE_UNRECOGNIZED: {
- show_accept(TTR("Requested file format unknown:") + " " + p_file.get_extension(), TTR("I see..."));
+ show_accept(TTR("Requested file format unknown:") + " " + p_file.get_extension(), TTR("OK"));
} break;
default: {
- show_accept(TTR("Error while saving."), TTR("I see..."));
+ show_accept(TTR("Error while saving."), TTR("OK"));
} break;
}
}
@@ -712,23 +713,23 @@ void EditorNode::_dialog_display_load_error(String p_file, Error p_error) {
case ERR_CANT_OPEN: {
- show_accept(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_file.get_file()), TTR("I see..."));
+ show_accept(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_file.get_file()), TTR("OK"));
} break;
case ERR_PARSE_ERROR: {
- show_accept(vformat(TTR("Error while parsing '%s'."), p_file.get_file()), TTR("I see..."));
+ show_accept(vformat(TTR("Error while parsing '%s'."), p_file.get_file()), TTR("OK"));
} break;
case ERR_FILE_CORRUPT: {
- show_accept(vformat(TTR("Unexpected end of file '%s'."), p_file.get_file()), TTR("I see..."));
+ show_accept(vformat(TTR("Unexpected end of file '%s'."), p_file.get_file()), TTR("OK"));
} break;
case ERR_FILE_NOT_FOUND: {
- show_accept(vformat(TTR("Missing '%s' or its dependencies."), p_file.get_file()), TTR("I see..."));
+ show_accept(vformat(TTR("Missing '%s' or its dependencies."), p_file.get_file()), TTR("OK"));
} break;
default: {
- show_accept(vformat(TTR("Error while loading '%s'."), p_file.get_file()), TTR("I see..."));
+ show_accept(vformat(TTR("Error while loading '%s'."), p_file.get_file()), TTR("OK"));
} break;
}
}
@@ -990,7 +991,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
if (!scene) {
- show_accept(TTR("This operation can't be done without a tree root."), TTR("I see..."));
+ show_accept(TTR("This operation can't be done without a tree root."), TTR("OK"));
return;
}
@@ -1018,7 +1019,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
if (err != OK) {
- show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("I see..."));
+ show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("OK"));
return;
}
@@ -1026,7 +1027,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
// (hacky but needed for the tree to update properly)
Node *dummy_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
if (!dummy_scene) {
- show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("I see..."));
+ show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("OK"));
return;
}
memdelete(dummy_scene);
@@ -1188,7 +1189,7 @@ void EditorNode::_dialog_action(String p_file) {
ml = ResourceLoader::load(p_file, "MeshLibrary");
if (ml.is_null()) {
- show_accept(TTR("Can't load MeshLibrary for merging!"), TTR("I see..."));
+ show_accept(TTR("Can't load MeshLibrary for merging!"), TTR("OK"));
return;
}
}
@@ -1201,7 +1202,7 @@ void EditorNode::_dialog_action(String p_file) {
Error err = ResourceSaver::save(p_file, ml);
if (err) {
- show_accept(TTR("Error saving MeshLibrary!"), TTR("I see..."));
+ show_accept(TTR("Error saving MeshLibrary!"), TTR("OK"));
return;
}
@@ -1213,7 +1214,7 @@ void EditorNode::_dialog_action(String p_file) {
tileset = ResourceLoader::load(p_file, "TileSet");
if (tileset.is_null()) {
- show_accept(TTR("Can't load TileSet for merging!"), TTR("I see..."));
+ show_accept(TTR("Can't load TileSet for merging!"), TTR("OK"));
return;
}
@@ -1226,7 +1227,7 @@ void EditorNode::_dialog_action(String p_file) {
Error err = ResourceSaver::save(p_file, tileset);
if (err) {
- show_accept("Error saving TileSet!", "I see...");
+ show_accept(TTR("Error saving TileSet!"), TTR("OK"));
return;
}
} break;
@@ -1580,7 +1581,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
Node *scene = editor_data.get_edited_scene_root();
if (!scene) {
- show_accept(TTR("There is no defined scene to run."), TTR("I see..."));
+ show_accept(TTR("There is no defined scene to run."), TTR("OK"));
return;
}
@@ -1634,7 +1635,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
if (scene->get_filename() == "") {
- show_accept(TTR("Current scene was never saved, please save it prior to running."), TTR("I see..."));
+ show_accept(TTR("Current scene was never saved, please save it prior to running."), TTR("OK"));
return;
}
@@ -1665,7 +1666,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
if (error != OK) {
- show_accept(TTR("Could not start subprocess!"), TTR("I see..."));
+ show_accept(TTR("Could not start subprocess!"), TTR("OK"));
return;
}
@@ -1788,7 +1789,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (!scene) {
- show_accept(TTR("This operation can't be done without a tree root."), TTR("I see..."));
+ show_accept(TTR("This operation can't be done without a tree root."), TTR("OK"));
break;
}
@@ -1851,7 +1852,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (!editor_data.get_edited_scene_root()) {
- show_accept(TTR("This operation can't be done without a scene."), TTR("I see..."));
+ show_accept(TTR("This operation can't be done without a scene."), TTR("OK"));
break;
}
@@ -1871,7 +1872,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
//Make sure that the scene has a root before trying to convert to tileset
if (!editor_data.get_edited_scene_root()) {
- show_accept(TTR("This operation can't be done without a root node."), TTR("I see..."));
+ show_accept(TTR("This operation can't be done without a root node."), TTR("OK"));
break;
}
@@ -1892,7 +1893,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (!editor_data.get_edited_scene_root()) {
- show_accept(TTR("This operation can't be done without a selected node."), TTR("I see..."));
+ show_accept(TTR("This operation can't be done without a selected node."), TTR("OK"));
break;
}
@@ -2169,7 +2170,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
OS::get_singleton()->set_low_processor_usage_mode(false);
EditorSettings::get_singleton()->set_project_metadata("editor_options", "update_always", true);
- show_accept(TTR("This option is deprecated. Situations where refresh must be forced are now considered a bug. Please report."), TTR("I see..."));
+ show_accept(TTR("This option is deprecated. Situations where refresh must be forced are now considered a bug. Please report."), TTR("OK"));
} break;
case SETTINGS_UPDATE_CHANGES: {
@@ -2783,7 +2784,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
if (!lpath.begins_with("res://")) {
- show_accept(TTR("Error loading scene, it must be inside the project path. Use 'Import' to open the scene, then save it inside the project path."), TTR("Ugh"));
+ show_accept(TTR("Error loading scene, it must be inside the project path. Use 'Import' to open the scene, then save it inside the project path."), TTR("OK"));
opening_prev = false;
return ERR_FILE_NOT_FOUND;
}
@@ -4666,6 +4667,16 @@ EditorNode::EditorNode() {
import_texture.instance();
ResourceFormatImporter::get_singleton()->add_importer(import_texture);
+ Ref<ResourceImporterLayeredTexture> import_3d;
+ import_3d.instance();
+ import_3d->set_3d(true);
+ ResourceFormatImporter::get_singleton()->add_importer(import_3d);
+
+ Ref<ResourceImporterLayeredTexture> import_array;
+ import_array.instance();
+ import_array->set_3d(false);
+ ResourceFormatImporter::get_singleton()->add_importer(import_array);
+
Ref<ResourceImporterImage> import_image;
import_image.instance();
ResourceFormatImporter::get_singleton()->add_importer(import_image);
@@ -4762,6 +4773,8 @@ EditorNode::EditorNode() {
EDITOR_DEF_RST("interface/scene_tabs/show_thumbnail_on_hover", true);
EDITOR_DEF_RST("interface/inspector/capitalize_properties", true);
EDITOR_DEF_RST("interface/inspector/disable_folding", false);
+ EDITOR_DEF("interface/inspector/horizontal_vector2_editing", false);
+ EDITOR_DEF("interface/inspector/horizontal_vector3_editing", true);
EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true);
EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "SpatialMaterial");
EDITOR_DEF("run/auto_save/save_before_running", true);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 843267d673..a926401558 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -479,15 +479,6 @@ void EditorPlugin::notify_resource_saved(const Ref<Resource> &p_resource) {
emit_signal("resource_saved", p_resource);
}
-Ref<SpatialEditorGizmo> EditorPlugin::create_spatial_gizmo(Spatial *p_spatial) {
- //??
- if (get_script_instance() && get_script_instance()->has_method("create_spatial_gizmo")) {
- return get_script_instance()->call("create_spatial_gizmo", p_spatial);
- }
-
- return Ref<SpatialEditorGizmo>();
-}
-
bool EditorPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
if (get_script_instance() && get_script_instance()->has_method("forward_canvas_gui_input")) {
@@ -765,10 +756,6 @@ void EditorPlugin::_bind_methods() {
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_spatial_gui_input", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
- MethodInfo gizmo = MethodInfo(Variant::OBJECT, "create_spatial_gizmo", PropertyInfo(Variant::OBJECT, "for_spatial", PROPERTY_HINT_RESOURCE_TYPE, "Spatial"));
- gizmo.return_val.hint = PROPERTY_HINT_RESOURCE_TYPE;
- gizmo.return_val.hint_string = "EditorSpatialGizmo";
- ClassDB::add_virtual_method(get_class_static(), gizmo);
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_plugin_name"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::OBJECT, "get_plugin_icon"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "has_main_screen"));
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 72e21b2f7f..c417f487dc 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -51,7 +51,6 @@ class Camera;
class EditorSelection;
class EditorExport;
class EditorSettings;
-class SpatialEditorGizmo;
class EditorImportPlugin;
class EditorExportPlugin;
class EditorResourcePreview;
@@ -171,7 +170,6 @@ public:
void notify_scene_closed(const String &scene_filepath);
void notify_resource_saved(const Ref<Resource> &p_resource);
- virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial);
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
virtual void forward_draw_over_viewport(Control *p_overlay);
virtual void forward_force_draw_over_viewport(Control *p_overlay);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 79490f1c8e..83a3662f21 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -1069,18 +1069,35 @@ void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, boo
}
EditorPropertyVector2::EditorPropertyVector2() {
- VBoxContainer *vb = memnew(VBoxContainer);
- add_child(vb);
+ bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector2_editing");
+
+ BoxContainer *bc;
+
+ if (horizontal) {
+ bc = memnew(HBoxContainer);
+ add_child(bc);
+ set_bottom_editor(bc);
+ } else {
+ bc = memnew(VBoxContainer);
+ add_child(bc);
+ }
+
static const char *desc[2] = { "x", "y" };
for (int i = 0; i < 2; i++) {
spin[i] = memnew(EditorSpinSlider);
spin[i]->set_flat(true);
spin[i]->set_label(desc[i]);
- vb->add_child(spin[i]);
+ bc->add_child(spin[i]);
add_focusable(spin[i]);
spin[i]->connect("value_changed", this, "_value_changed");
+ if (horizontal) {
+ spin[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ }
+ }
+
+ if (!horizontal) {
+ set_label_reference(spin[0]); //show text and buttons around this
}
- set_label_reference(spin[0]); //show text and buttons around this
setting = false;
}
@@ -1195,19 +1212,35 @@ void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, boo
}
EditorPropertyVector3::EditorPropertyVector3() {
- VBoxContainer *vb = memnew(VBoxContainer);
- add_child(vb);
+ bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector3_editing");
+
+ BoxContainer *bc;
+
+ if (horizontal) {
+ bc = memnew(HBoxContainer);
+ add_child(bc);
+ set_bottom_editor(bc);
+ } else {
+ bc = memnew(VBoxContainer);
+ add_child(bc);
+ }
+
static const char *desc[3] = { "x", "y", "z" };
for (int i = 0; i < 3; i++) {
spin[i] = memnew(EditorSpinSlider);
- spin[i]->set_label(desc[i]);
spin[i]->set_flat(true);
-
- vb->add_child(spin[i]);
+ spin[i]->set_label(desc[i]);
+ bc->add_child(spin[i]);
add_focusable(spin[i]);
spin[i]->connect("value_changed", this, "_value_changed");
+ if (horizontal) {
+ spin[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ }
+ }
+
+ if (!horizontal) {
+ set_label_reference(spin[0]); //show text and buttons around this
}
- set_label_reference(spin[0]); //show text and buttons around this
setting = false;
}
///////////////////// PLANE /////////////////////////
@@ -1259,18 +1292,36 @@ void EditorPropertyPlane::setup(double p_min, double p_max, double p_step, bool
}
EditorPropertyPlane::EditorPropertyPlane() {
- VBoxContainer *vb = memnew(VBoxContainer);
- add_child(vb);
+
+ bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector3_editing");
+
+ BoxContainer *bc;
+
+ if (horizontal) {
+ bc = memnew(HBoxContainer);
+ add_child(bc);
+ set_bottom_editor(bc);
+ } else {
+ bc = memnew(VBoxContainer);
+ add_child(bc);
+ }
+
static const char *desc[4] = { "x", "y", "z", "d" };
for (int i = 0; i < 4; i++) {
spin[i] = memnew(EditorSpinSlider);
- spin[i]->set_label(desc[i]);
spin[i]->set_flat(true);
- vb->add_child(spin[i]);
+ spin[i]->set_label(desc[i]);
+ bc->add_child(spin[i]);
add_focusable(spin[i]);
spin[i]->connect("value_changed", this, "_value_changed");
+ if (horizontal) {
+ spin[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ }
+ }
+
+ if (!horizontal) {
+ set_label_reference(spin[0]); //show text and buttons around this
}
- set_label_reference(spin[0]); //show text and buttons around this
setting = false;
}
@@ -1323,19 +1374,35 @@ void EditorPropertyQuat::setup(double p_min, double p_max, double p_step, bool p
}
EditorPropertyQuat::EditorPropertyQuat() {
- VBoxContainer *vb = memnew(VBoxContainer);
- add_child(vb);
+ bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector3_editing");
+
+ BoxContainer *bc;
+
+ if (horizontal) {
+ bc = memnew(HBoxContainer);
+ add_child(bc);
+ set_bottom_editor(bc);
+ } else {
+ bc = memnew(VBoxContainer);
+ add_child(bc);
+ }
+
static const char *desc[4] = { "x", "y", "z", "w" };
for (int i = 0; i < 4; i++) {
spin[i] = memnew(EditorSpinSlider);
- spin[i]->set_label(desc[i]);
spin[i]->set_flat(true);
-
- vb->add_child(spin[i]);
+ spin[i]->set_label(desc[i]);
+ bc->add_child(spin[i]);
add_focusable(spin[i]);
spin[i]->connect("value_changed", this, "_value_changed");
+ if (horizontal) {
+ spin[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ }
+ }
+
+ if (!horizontal) {
+ set_label_reference(spin[0]); //show text and buttons around this
}
- set_label_reference(spin[0]); //show text and buttons around this
setting = false;
}
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 0e6d81d13b..b2c9f9865a 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -30,7 +30,13 @@
#include "editor_spin_slider.h"
#include "editor_scale.h"
+#include "math/expression.h"
#include "os/input.h"
+
+String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const {
+ return rtos(get_value());
+}
+
String EditorSpinSlider::get_text_value() const {
int zeros = Math::step_decimals(get_step());
return String::num(get_value(), zeros);
@@ -270,10 +276,12 @@ void EditorSpinSlider::_notification(int p_what) {
if (p_what == NOTIFICATION_FOCUS_ENTER) {
/* Sorry, I dont like this, it makes navigating the different fields with arrows more difficult.
* Just press enter to edit.
- * if (!Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && !value_input_just_closed) {
+ * if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && !value_input_just_closed) {
_focus_entered();
}*/
-
+ if ((Input::get_singleton()->is_action_pressed("ui_focus_next") || Input::get_singleton()->is_action_pressed("ui_focus_prev")) && !value_input_just_closed) {
+ _focus_entered();
+ }
value_input_just_closed = false;
}
}
@@ -307,6 +315,21 @@ String EditorSpinSlider::get_label() const {
return label;
}
+void EditorSpinSlider::_evaluate_input_text() {
+ String text = value_input->get_text();
+ Ref<Expression> expr;
+ expr.instance();
+ Error err = expr->parse(text);
+ if (err != OK) {
+ return;
+ }
+
+ Variant v = expr->execute(Array(), NULL, false);
+ if (v.get_type() == Variant::NIL)
+ return;
+ set_value(v);
+}
+
//text_entered signal
void EditorSpinSlider::_value_input_entered(const String &p_text) {
value_input_just_closed = true;
@@ -315,13 +338,13 @@ void EditorSpinSlider::_value_input_entered(const String &p_text) {
//modal_closed signal
void EditorSpinSlider::_value_input_closed() {
- set_value(value_input->get_text().to_double());
+ _evaluate_input_text();
value_input_just_closed = true;
}
//focus_exited signal
void EditorSpinSlider::_value_focus_exited() {
- set_value(value_input->get_text().to_double());
+ _evaluate_input_text();
// focus is not on the same element after the vlalue_input was exited
// -> focus is on next element
// -> TAB was pressed
diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h
index fb32534ef4..e48eb171b8 100644
--- a/editor/editor_spin_slider.h
+++ b/editor/editor_spin_slider.h
@@ -73,6 +73,8 @@ class EditorSpinSlider : public Range {
bool use_custom_label_color;
Color custom_label_color;
+ void _evaluate_input_text();
+
protected:
void _notification(int p_what);
void _gui_input(const Ref<InputEvent> &p_event);
@@ -82,6 +84,8 @@ protected:
void _focus_entered();
public:
+ String get_tooltip(const Point2 &p_pos) const;
+
String get_text_value() const;
void set_label(const String &p_label);
String get_label() const;
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 18cc52a5c6..0a22026591 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -367,6 +367,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Color success_color = accent_color.linear_interpolate(Color(0.2, 1, 0.2), 0.6) * 1.2;
Color warning_color = accent_color.linear_interpolate(Color(1, 1, 0), 0.7) * 1.2;
Color error_color = accent_color.linear_interpolate(Color(1, 0, 0), 0.8) * 1.7;
+ Color property_color = font_color.linear_interpolate(Color(0.5, 0.5, 0.5), 0.5);
+
if (!dark_theme) {
// yellow on white themes is a P.I.T.A.
warning_color = accent_color.linear_interpolate(Color(1, 0.8, 0), 0.9);
@@ -377,6 +379,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("success_color", "Editor", success_color);
theme->set_color("warning_color", "Editor", warning_color);
theme->set_color("error_color", "Editor", error_color);
+ theme->set_color("property_color", "Editor", property_color);
// 2d grid color
const Color grid_minor_color = mono_color * Color(1.0, 1.0, 1.0, 0.07);
diff --git a/editor/icons/icon_add_atlas_tile.svg b/editor/icons/icon_add_atlas_tile.svg
new file mode 100644
index 0000000000..912a0ce2c9
--- /dev/null
+++ b/editor/icons/icon_add_atlas_tile.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m7 1v6h-6v2h6v6h2v-6h6v-2h-6v-6h-2z" fill="#c9cfd4"/>
+</svg>
diff --git a/editor/icons/icon_add_autotile.svg b/editor/icons/icon_add_autotile.svg
new file mode 100644
index 0000000000..2cc34d53b1
--- /dev/null
+++ b/editor/icons/icon_add_autotile.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m7 1v6h-6v2h6v6h2v-6h6v-2h-6v-6h-2z" fill="#4490fc"/>
+</svg>
diff --git a/editor/icons/icon_add_single_tile.svg b/editor/icons/icon_add_single_tile.svg
new file mode 100644
index 0000000000..01af8e0649
--- /dev/null
+++ b/editor/icons/icon_add_single_tile.svg
@@ -0,0 +1,3 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m7 1v6h-6v2h6v6h2v-6h6v-2h-6v-6h-2z" fill="#fce844"/>
+</svg>
diff --git a/editor/icons/icon_information_sign.svg b/editor/icons/icon_information_sign.svg
new file mode 100644
index 0000000000..95002b6948
--- /dev/null
+++ b/editor/icons/icon_information_sign.svg
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ version="1.1"
+ viewBox="0 0 16 16"
+ id="svg8"
+ sodipodi:docname="icon_information_sign.svg"
+ inkscape:version="0.92.3 (2405546, 2018-03-11)">
+ <metadata
+ id="metadata14">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs12" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1047"
+ inkscape:window-height="603"
+ id="namedview10"
+ showgrid="false"
+ inkscape:zoom="14.521571"
+ inkscape:cx="12.730205"
+ inkscape:cy="8.6526495"
+ inkscape:window-x="654"
+ inkscape:window-y="156"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg8" />
+ <path
+ style="fill:#ffb65d;fill-opacity:1;fill-rule:evenodd;stroke-width:0.57024062"
+ inkscape:connector-curvature="0"
+ id="path2"
+ d="m 4.5291945,14.892249 h 6.8428865 l 3.421444,-3.421444 V 4.6279186 L 11.372081,1.2064749 H 4.5291945 L 1.1077509,4.6279186 v 6.8428864 z" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke-width:0.57024062"
+ id="rect829"
+ width="2.6243541"
+ height="6.5062103"
+ x="6.6998501"
+ y="6.3477535" />
+ <ellipse
+ style="fill:#ffffff;fill-opacity:1;stroke-width:0.57024062"
+ id="path831"
+ cx="8.0393629"
+ cy="4.2154655"
+ rx="1.3941878"
+ ry="1.3668507" />
+</svg>
diff --git a/editor/icons/icon_texture_3_d.svg b/editor/icons/icon_texture_3_d.svg
new file mode 100644
index 0000000000..dafdc8c68d
--- /dev/null
+++ b/editor/icons/icon_texture_3_d.svg
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ version="1.1"
+ viewBox="0 0 16 16"
+ id="svg6"
+ sodipodi:docname="icon_texture_3_d.svg"
+ inkscape:version="0.92.3 (2405546, 2018-03-11)">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1853"
+ inkscape:window-height="1016"
+ id="namedview8"
+ showgrid="false"
+ inkscape:zoom="29.5"
+ inkscape:cx="15.226978"
+ inkscape:cy="9.4909723"
+ inkscape:window-x="67"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg6" />
+ <g
+ id="g830"
+ transform="translate(0.35954582,-0.28763666)">
+ <path
+ d="M 2,1 C 1.4477153,1 1,1.4477153 1,2 v 12 c 0,0.552285 0.4477153,1 1,1 h 12 c 0.552285,0 1,-0.447715 1,-1 V 2 C 15,1.4477153 14.552285,1 14,1 Z m 1,2 h 10 v 8 H 3 Z"
+ id="path2"
+ inkscape:connector-curvature="0"
+ style="fill:#e0e0e0;fill-opacity:0.99607999"
+ sodipodi:nodetypes="sssssssssccccc" />
+ </g>
+ <g
+ aria-label="3D"
+ transform="scale(0.9167105,1.0908569)"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.12847996px;line-height:1.25;font-family:Ubuntu;-inkscape-font-specification:'Ubuntu Bold';letter-spacing:0px;word-spacing:0px;fill:#e0e0e0;fill-opacity:0.99607843;stroke:none;stroke-width:0.20321201"
+ id="text834">
+ <path
+ d="m 5.8175194,8.9717502 q -0.2194689,0 -0.4633233,-0.032514 Q 5.1103417,8.9148508 4.8827442,8.86608 4.6551468,8.8173091 4.4681918,8.7604097 4.2812367,8.7035104 4.1755665,8.6547395 L 4.4112924,7.646808 q 0.2113405,0.089413 0.5364797,0.1950835 0.3332677,0.097542 0.8209765,0.097542 0.5608651,0 0.8209764,-0.2113404 0.2601114,-0.2113405 0.2601114,-0.5689936 0,-0.219469 -0.097542,-0.3657816 Q 6.6628814,6.6388764 6.5003118,6.5494632 6.3377422,6.4519214 6.1101447,6.4194075 5.8906758,6.3787651 5.6386929,6.3787651 H 5.167241 V 5.4033475 h 0.5364797 q 0.1788266,0 0.3413962,-0.032514 0.1706981,-0.032514 0.3007537,-0.1056703 0.1300557,-0.081285 0.203212,-0.2113404 0.081285,-0.1381842 0.081285,-0.3413962 0,-0.1544411 -0.065028,-0.2682398 Q 6.5003118,4.3303881 6.3946415,4.2572318 6.2970998,4.1840755 6.1589156,4.1515616 6.0288599,4.1109192 5.8906758,4.1109192 q -0.3495247,0 -0.6502784,0.1056702 Q 4.9477721,4.3222597 4.7039177,4.4767008 L 4.2731082,3.5906965 Q 4.4031639,3.5094117 4.573862,3.4199984 4.7526886,3.3305851 4.964029,3.2574288 5.1753695,3.1842725 5.4110954,3.1355016 q 0.2438544,-0.048771 0.5120943,-0.048771 0.4958373,0 0.8534904,0.1219272 0.3657816,0.1137987 0.6015075,0.3332677 0.2357259,0.2113405 0.3495246,0.5039657 0.1137987,0.2844968 0.1137987,0.625893 0,0.3332677 -0.186955,0.6502784 -0.186955,0.3088822 -0.5039657,0.4714518 0.4389379,0.1788266 0.6746638,0.5364797 0.2438544,0.3495246 0.2438544,0.8453619 0,0.3901671 -0.1300557,0.7234347 Q 7.808997,8.22393 7.5326287,8.4677844 7.2562604,8.7035104 6.825451,8.8416945 6.40277,8.9717502 5.8175194,8.9717502 Z"
+ style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.20321201"
+ id="path836" />
+ <path
+ d="m 10.502445,7.817506 q 0.08941,0.00813 0.203212,0.016257 0.121927,0 0.284497,0 0.951032,0 1.406227,-0.4795803 0.463323,-0.4795803 0.463323,-1.3249422 0,-0.8860044 -0.438938,-1.3411992 -0.438938,-0.4551949 -1.38997,-0.4551949 -0.130055,0 -0.26824,0.00813 -0.138184,0 -0.260111,0.016257 z M 14.16839,6.0292405 q 0,0.7315631 -0.227598,1.2761713 -0.227597,0.5446082 -0.650278,0.9022613 -0.414553,0.3576531 -1.01606,0.5364797 -0.601508,0.1788265 -1.349328,0.1788265 -0.341396,0 -0.796591,-0.032514 Q 9.6733402,8.86608 9.2344022,8.7766667 v -5.486724 q 0.438938,-0.081285 0.9103898,-0.1056702 0.47958,-0.032514 0.820976,-0.032514 0.723435,0 1.308686,0.1625696 0.593379,0.1625696 1.01606,0.5120943 0.422681,0.3495246 0.650278,0.8941328 0.227598,0.5446081 0.227598,1.3086853 z"
+ style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.20321201"
+ id="path838" />
+ </g>
+</svg>
diff --git a/editor/icons/icon_texture_array.svg b/editor/icons/icon_texture_array.svg
new file mode 100644
index 0000000000..8297fc0f5d
--- /dev/null
+++ b/editor/icons/icon_texture_array.svg
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ version="1.1"
+ viewBox="0 0 16 16"
+ id="svg6"
+ sodipodi:docname="icon_texture_array.svg"
+ inkscape:version="0.92.3 (2405546, 2018-03-11)">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1526"
+ inkscape:window-height="766"
+ id="namedview8"
+ showgrid="false"
+ inkscape:zoom="29.5"
+ inkscape:cx="8.3117238"
+ inkscape:cy="9.4909723"
+ inkscape:window-x="67"
+ inkscape:window-y="27"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg6" />
+ <g
+ id="g830"
+ transform="translate(0.35954582,-0.28763666)">
+ <path
+ d="M 2,1 C 1.4477153,1 1,1.4477153 1,2 v 12 c 0,0.552285 0.4477153,1 1,1 h 12 c 0.552285,0 1,-0.447715 1,-1 V 2 C 15,1.4477153 14.552285,1 14,1 Z m 1,2 h 10 v 8 H 3 Z"
+ id="path2"
+ inkscape:connector-curvature="0"
+ style="fill:#e0e0e0;fill-opacity:0.99607999"
+ sodipodi:nodetypes="sssssssssccccc" />
+ </g>
+ <g
+ aria-label="[]"
+ transform="matrix(1.6197742,0,0,0.750929,-3.7231532,1.8329569)"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.29580784px;line-height:1.25;font-family:Ubuntu;-inkscape-font-specification:'Ubuntu Bold';letter-spacing:0px;word-spacing:0px;fill:#e0e0e0;fill-opacity:0.99607843;stroke:none;stroke-width:0.2073952"
+ id="text834">
+ <path
+ d="M 4.7302951,2.4553483 H 6.978459 V 3.4425495 H 5.9082998 V 9.4984892 H 6.978459 V 10.48569 H 4.7302951 Z"
+ style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.2073952"
+ id="path862"
+ inkscape:connector-curvature="0" />
+ <path
+ d="M 10.138643,10.48569 H 7.8904794 V 9.4984892 H 8.9606386 V 3.4425495 H 7.8904794 V 2.4553483 h 2.2481636 z"
+ style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.2073952"
+ id="path864"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index 7cfaa9070f..906d902b4a 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -203,7 +203,6 @@ Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) {
GLTFNode *node = memnew(GLTFNode);
Dictionary n = nodes[i];
- print_line("node " + itos(i) + ": " + String(Variant(n)));
if (n.has("name")) {
node->name = n["name"];
}
@@ -1657,6 +1656,7 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node
if (n->mesh >= 0) {
ERR_FAIL_INDEX(n->mesh, state.meshes.size());
MeshInstance *mi = memnew(MeshInstance);
+ print_line("**creating mesh for: " + n->name);
GLTFMesh &mesh = state.meshes.write[n->mesh];
mi->set_mesh(mesh.mesh);
if (mesh.mesh->get_name() == "") {
@@ -1686,20 +1686,22 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node
node->set_name(n->name);
- p_parent->add_child(node);
- node->set_owner(p_owner);
- node->set_transform(n->xform);
-
n->godot_nodes.push_back(node);
if (n->skin >= 0 && Object::cast_to<MeshInstance>(node)) {
MeshInstance *mi = Object::cast_to<MeshInstance>(node);
- //move skeleton around and place it on node, as the node _is_ a skeleton.
+
Skeleton *s = skeletons[n->skin];
- state.paths_to_skeleton[mi] = s;
- //move it later, as skeleton may be moved around first
+ s->add_child(node); //According to spec, mesh should actually act as a child of the skeleton, as it inherits its transform
+ mi->set_skeleton_path(String(".."));
+
+ } else {
+ p_parent->add_child(node);
+ node->set_transform(n->xform);
}
+ node->set_owner(p_owner);
+
#if 0
for (int i = 0; i < n->skeleton_children.size(); i++) {
@@ -1729,6 +1731,10 @@ void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vecto
skeletons[i]->get_parent()->remove_child(skeletons[i]);
p_parent_node->add_child(skeletons[i]);
skeletons[i]->set_owner(owner);
+ //may have meshes as children, set owner in them too
+ for (int j = 0; j < skeletons[i]->get_child_count(); j++) {
+ skeletons[i]->get_child(j)->set_owner(owner);
+ }
}
}
@@ -1744,10 +1750,8 @@ void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vecto
const int parent = gltf_bone_node->parent;
const int parent_index = s->find_bone(state.nodes[parent]->name);
- s->add_bone(bone_name);
const int bone_index = s->find_bone(bone_name);
s->set_bone_parent(bone_index, parent_index);
- s->set_bone_rest(bone_index, state.skins[skin].bones[n->joints[i].bone].inverse_bind.affine_inverse());
n->godot_nodes.push_back(s);
n->joints.write[i].godot_bone_index = bone_index;
@@ -1979,8 +1983,9 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
if (node->joints.size()) {
Transform xform;
- xform.basis = Basis(rot);
- xform.basis.scale(scale);
+ //xform.basis = Basis(rot);
+ //xform.basis.scale(scale);
+ xform.basis.set_quat_scale(rot, scale);
xform.origin = pos;
Skeleton *skeleton = skeletons[node->joints[i].skin];
@@ -2061,6 +2066,10 @@ Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, int p_bake_f
if (name == "") {
name = _gen_unique_name(state, "Skeleton");
}
+ for (int j = 0; j < state.skins[i].bones.size(); j++) {
+ s->add_bone(state.nodes[state.skins[i].bones[j].node]->name);
+ s->set_bone_rest(j, state.skins[i].bones[j].inverse_bind.affine_inverse());
+ }
s->set_name(name);
root->add_child(s);
s->set_owner(root);
@@ -2074,12 +2083,6 @@ Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, int p_bake_f
}
}
- for (Map<Node *, Skeleton *>::Element *E = state.paths_to_skeleton.front(); E; E = E->next()) {
- MeshInstance *mi = Object::cast_to<MeshInstance>(E->key());
- ERR_CONTINUE(!mi);
- mi->set_skeleton_path(mi->get_path_to(E->get()));
- }
-
for (int i = 0; i < skeletons.size(); i++) {
skeletons[i]->localize_rests();
}
diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h
index e8f3bdff62..8258ec41fd 100644
--- a/editor/import/editor_scene_importer_gltf.h
+++ b/editor/import/editor_scene_importer_gltf.h
@@ -275,7 +275,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Vector<GLTFAnimation> animations;
Map<int, Vector<int> > skeleton_nodes;
- Map<Node *, Skeleton *> paths_to_skeleton;
//Map<int, Vector<int> > skin_users; //cache skin users
diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp
new file mode 100644
index 0000000000..2f958a6fdd
--- /dev/null
+++ b/editor/import/resource_importer_layered_texture.cpp
@@ -0,0 +1,274 @@
+#include "resource_importer_layered_texture.h"
+
+#include "resource_importer_texture.h"
+
+#include "editor/editor_file_system.h"
+#include "editor/editor_node.h"
+#include "io/config_file.h"
+#include "io/image_loader.h"
+#include "scene/resources/texture.h"
+
+String ResourceImporterLayeredTexture::get_importer_name() const {
+
+ return is_3d ? "texture_3d" : "texture_array";
+}
+
+String ResourceImporterLayeredTexture::get_visible_name() const {
+
+ return is_3d ? "Texture3D" : "TextureArray";
+}
+void ResourceImporterLayeredTexture::get_recognized_extensions(List<String> *p_extensions) const {
+
+ ImageLoader::get_recognized_extensions(p_extensions);
+}
+String ResourceImporterLayeredTexture::get_save_extension() const {
+ return is_3d ? "tex3d" : "texarr";
+}
+
+String ResourceImporterLayeredTexture::get_resource_type() const {
+
+ return is_3d ? "Texture3D" : "TextureArray";
+}
+
+bool ResourceImporterLayeredTexture::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
+
+ return true;
+}
+
+int ResourceImporterLayeredTexture::get_preset_count() const {
+ return 3;
+}
+String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const {
+
+ static const char *preset_names[] = {
+ "3D",
+ "2D",
+ "ColorCorrect"
+ };
+
+ return preset_names[p_idx];
+}
+
+void ResourceImporterLayeredTexture::get_import_options(List<ImportOption> *r_options, int p_preset) const {
+
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Video RAM,Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 1 : 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirrored"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/filter"), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/mipmaps"), p_preset == PRESET_COLOR_CORRECT ? 0 : 1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/srgb", PROPERTY_HINT_ENUM, "Disable,Enable"), p_preset == PRESET_3D ? 1 : 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/horizontal", PROPERTY_HINT_RANGE, "1,256,1"), p_preset == PRESET_COLOR_CORRECT ? 16 : 8));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/vertical", PROPERTY_HINT_RANGE, "1,256,1"), p_preset == PRESET_COLOR_CORRECT ? 1 : 8));
+}
+
+void ResourceImporterLayeredTexture::_save_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags) {
+
+ FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE);
+ f->store_8('G');
+ f->store_8('D');
+ if (is_3d) {
+ f->store_8('3');
+ } else {
+ f->store_8('A');
+ }
+ f->store_8('T'); //godot streamable texture
+
+ f->store_32(p_images[0]->get_width());
+ f->store_32(p_images[0]->get_height());
+ f->store_32(p_images.size()); //depth
+ f->store_32(p_texture_flags);
+ if (p_compress_mode != COMPRESS_VIDEO_RAM) {
+ //vram needs to do a first compression to tell what the format is, for the rest its ok
+ f->store_32(p_images[0]->get_format());
+ f->store_32(p_compress_mode); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed
+ }
+
+ if ((p_compress_mode == COMPRESS_LOSSLESS) && p_images[0]->get_format() > Image::FORMAT_RGBA8) {
+ p_compress_mode = COMPRESS_UNCOMPRESSED; //these can't go as lossy
+ }
+
+ for (int i = 0; i < p_images.size(); i++) {
+
+ switch (p_compress_mode) {
+ case COMPRESS_LOSSLESS: {
+
+ Ref<Image> image = p_images[i]->duplicate();
+ if (p_mipmaps) {
+ image->generate_mipmaps();
+ } else {
+ image->clear_mipmaps();
+ }
+
+ int mmc = image->get_mipmap_count() + 1;
+ f->store_32(mmc);
+
+ for (int i = 0; i < mmc; i++) {
+
+ if (i > 0) {
+ image->shrink_x2();
+ }
+
+ PoolVector<uint8_t> data = Image::lossless_packer(image);
+ int data_len = data.size();
+ f->store_32(data_len);
+
+ PoolVector<uint8_t>::Read r = data.read();
+ f->store_buffer(r.ptr(), data_len);
+ }
+
+ } break;
+ case COMPRESS_VIDEO_RAM: {
+
+ Ref<Image> image = p_images[i]->duplicate();
+ image->generate_mipmaps(false);
+
+ Image::CompressSource csource = Image::COMPRESS_SOURCE_LAYERED;
+ image->compress(p_vram_compression, csource, 0.7);
+
+ if (i == 0) {
+ //hack so we can properly tell the format
+ f->store_32(image->get_format());
+ f->store_32(p_compress_mode); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed
+ }
+
+ PoolVector<uint8_t> data = image->get_data();
+ int dl = data.size();
+
+ PoolVector<uint8_t>::Read r = data.read();
+ f->store_buffer(r.ptr(), dl);
+ } break;
+ case COMPRESS_UNCOMPRESSED: {
+
+ Ref<Image> image = p_images[i]->duplicate();
+
+ if (p_mipmaps) {
+ image->generate_mipmaps();
+ } else {
+ image->clear_mipmaps();
+ }
+
+ PoolVector<uint8_t> data = image->get_data();
+ int dl = data.size();
+
+ PoolVector<uint8_t>::Read r = data.read();
+
+ f->store_buffer(r.ptr(), dl);
+
+ } break;
+ }
+ }
+
+ memdelete(f);
+}
+
+Error ResourceImporterLayeredTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) {
+
+ int compress_mode = p_options["compress/mode"];
+ int repeat = p_options["flags/repeat"];
+ bool filter = p_options["flags/filter"];
+ bool mipmaps = p_options["flags/mipmaps"];
+ int srgb = p_options["flags/srgb"];
+ int hslices = p_options["slices/horizontal"];
+ int vslices = p_options["slices/vertical"];
+
+ Ref<Image> image;
+ image.instance();
+ Error err = ImageLoader::load_image(p_source_file, image, NULL, false, 1.0);
+ if (err != OK)
+ return err;
+
+ int tex_flags = 0;
+ if (repeat > 0)
+ tex_flags |= Texture::FLAG_REPEAT;
+ if (repeat == 2)
+ tex_flags |= Texture::FLAG_MIRRORED_REPEAT;
+ if (filter)
+ tex_flags |= Texture::FLAG_FILTER;
+ if (mipmaps || compress_mode == COMPRESS_VIDEO_RAM)
+ tex_flags |= Texture::FLAG_MIPMAPS;
+ if (srgb == 1)
+ tex_flags |= Texture::FLAG_CONVERT_TO_LINEAR;
+
+ Vector<Ref<Image> > slices;
+
+ int slice_w = image->get_width() / hslices;
+ int slice_h = image->get_height() / vslices;
+
+ //optimize
+ if (compress_mode == COMPRESS_VIDEO_RAM) {
+ //if using video ram, optimize
+ if (srgb) {
+ //remove alpha if not needed, so compression is more efficient
+ if (image->get_format() == Image::FORMAT_RGBA8 && !image->detect_alpha()) {
+ image->convert(Image::FORMAT_RGB8);
+ }
+ } else {
+ image->optimize_channels();
+ }
+ }
+
+ for (int i = 0; i < vslices; i++) {
+ for (int j = 0; j < hslices; j++) {
+ int x = slice_w * j;
+ int y = slice_h * i;
+ Ref<Image> slice = image->get_rect(Rect2(x, y, slice_w, slice_h));
+ ERR_CONTINUE(slice.is_null() || slice->empty());
+ if (slice->get_width() != slice_w || slice->get_height() != slice_h) {
+ slice->resize(slice_w, slice_h);
+ }
+ slices.push_back(slice);
+ }
+ }
+
+ String extension = get_save_extension();
+
+ if (compress_mode == COMPRESS_VIDEO_RAM) {
+ //must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc).
+ //Android, GLES 2.x
+
+ bool ok_on_pc = false;
+
+ if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc")) {
+
+ _save_tex(slices, p_save_path + ".s3tc." + extension, compress_mode, Image::COMPRESS_S3TC, mipmaps, tex_flags);
+ r_platform_variants->push_back("s3tc");
+ ok_on_pc = true;
+ }
+
+ if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) {
+
+ _save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, Image::COMPRESS_ETC2, mipmaps, tex_flags);
+ r_platform_variants->push_back("etc2");
+ }
+
+ if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) {
+ _save_tex(slices, p_save_path + ".etc." + extension, compress_mode, Image::COMPRESS_ETC, mipmaps, tex_flags);
+ r_platform_variants->push_back("etc");
+ }
+
+ if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) {
+
+ _save_tex(slices, p_save_path + ".pvrtc." + extension, compress_mode, Image::COMPRESS_PVRTC4, mipmaps, tex_flags);
+ r_platform_variants->push_back("pvrtc");
+ }
+
+ if (!ok_on_pc) {
+ EditorNode::add_io_error("Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correcly on PC.");
+ }
+ } else {
+ //import normally
+ _save_tex(slices, p_save_path + "." + extension, compress_mode, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags);
+ }
+
+ return OK;
+}
+
+ResourceImporterLayeredTexture *ResourceImporterLayeredTexture::singleton = NULL;
+
+ResourceImporterLayeredTexture::ResourceImporterLayeredTexture() {
+
+ singleton = this;
+ is_3d = true;
+}
+
+ResourceImporterLayeredTexture::~ResourceImporterLayeredTexture() {
+}
diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h
new file mode 100644
index 0000000000..ec73b2624d
--- /dev/null
+++ b/editor/import/resource_importer_layered_texture.h
@@ -0,0 +1,57 @@
+#ifndef RESOURCE_IMPORTER_LAYERED_TEXTURE_H
+#define RESOURCE_IMPORTER_LAYERED_TEXTURE_H
+
+#include "image.h"
+#include "io/resource_import.h"
+
+class StreamTexture;
+
+class ResourceImporterLayeredTexture : public ResourceImporter {
+ GDCLASS(ResourceImporterLayeredTexture, ResourceImporter)
+
+ bool is_3d;
+
+protected:
+ static void _texture_reimport_srgb(const Ref<StreamTexture> &p_tex);
+ static void _texture_reimport_3d(const Ref<StreamTexture> &p_tex);
+ static void _texture_reimport_normal(const Ref<StreamTexture> &p_tex);
+
+ static ResourceImporterLayeredTexture *singleton;
+
+public:
+ static ResourceImporterLayeredTexture *get_singleton() { return singleton; }
+ virtual String get_importer_name() const;
+ virtual String get_visible_name() const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual String get_save_extension() const;
+ virtual String get_resource_type() const;
+
+ enum Preset {
+ PRESET_3D,
+ PRESET_2D,
+ PRESET_COLOR_CORRECT,
+ };
+
+ enum CompressMode {
+ COMPRESS_LOSSLESS,
+ COMPRESS_VIDEO_RAM,
+ COMPRESS_UNCOMPRESSED
+ };
+
+ virtual int get_preset_count() const;
+ virtual String get_preset_name(int p_idx) const;
+
+ virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
+ virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
+
+ void _save_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags);
+
+ virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL);
+
+ void update_imports();
+
+ void set_3d(bool p_3d) { is_3d = p_3d; }
+ ResourceImporterLayeredTexture();
+ ~ResourceImporterLayeredTexture();
+};
+#endif // RESOURCE_IMPORTER_LAYERED_TEXTURE_H
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index 43baabe2f5..e65b743bfa 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -142,7 +142,7 @@ void InspectorDock::_resource_file_selected(String p_file) {
RES res = ResourceLoader::load(p_file);
if (res.is_null()) {
- warning_dialog->get_ok()->set_text("Ugh");
+ warning_dialog->get_ok()->set_text(TTR("OK"));
warning_dialog->set_text(TTR("Failed to load resource."));
return;
};
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index eed6b5a95c..3738c472e7 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4879,7 +4879,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
files_str += error_files[i].get_file().get_basename() + ",";
}
files_str = files_str.substr(0, files_str.length() - 1);
- accept->get_ok()->set_text(TTR("Ugh"));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str()));
accept->popup_centered_minsize();
}
diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp
index 72a8b55a52..618c70d1a1 100644
--- a/editor/plugins/path_editor_plugin.cpp
+++ b/editor/plugins/path_editor_plugin.cpp
@@ -215,6 +215,10 @@ void PathSpatialGizmo::redraw() {
clear();
+ Ref<SpatialMaterial> path_material = gizmo_plugin->get_material("path_material");
+ Ref<SpatialMaterial> path_thin_material = gizmo_plugin->get_material("path_thin_material");
+ Ref<SpatialMaterial> handles_material = gizmo_plugin->get_material("handles");
+
Ref<Curve3D> c = path->get_curve();
if (c.is_null())
return;
@@ -238,7 +242,7 @@ void PathSpatialGizmo::redraw() {
}
if (v3p.size() > 1) {
- add_lines(v3p, PathEditorPlugin::singleton->path_material);
+ add_lines(v3p, path_material);
add_collision_segments(v3p);
}
@@ -265,13 +269,13 @@ void PathSpatialGizmo::redraw() {
}
if (v3p.size() > 1) {
- add_lines(v3p, PathEditorPlugin::singleton->path_thin_material);
+ add_lines(v3p, path_thin_material);
}
if (handles.size()) {
- add_handles(handles);
+ add_handles(handles, handles_material);
}
if (sec_handles.size()) {
- add_handles(sec_handles, false, true);
+ add_handles(sec_handles, handles_material, false, true);
}
}
}
@@ -282,16 +286,6 @@ PathSpatialGizmo::PathSpatialGizmo(Path *p_path) {
set_spatial_node(p_path);
}
-Ref<SpatialEditorGizmo> PathEditorPlugin::create_spatial_gizmo(Spatial *p_spatial) {
-
- if (Object::cast_to<Path>(p_spatial)) {
-
- return memnew(PathSpatialGizmo(Object::cast_to<Path>(p_spatial)));
- }
-
- return Ref<SpatialEditorGizmo>();
-}
-
bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) {
if (!path)
@@ -567,21 +561,9 @@ PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) {
mirror_handle_angle = true;
mirror_handle_length = true;
- path_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
- path_material->set_albedo(Color(0.5, 0.5, 1.0, 0.8));
- path_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- path_material->set_line_width(3);
- path_material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
- path_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
-
- path_thin_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
- path_thin_material->set_albedo(Color(0.5, 0.5, 1.0, 0.4));
- path_thin_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- path_thin_material->set_line_width(1);
- path_thin_material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
- path_thin_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
-
- //SpatialEditor::get_singleton()->add_gizmo_plugin(this);
+ Ref<PathSpatialGizmoPlugin> gizmo_plugin;
+ gizmo_plugin.instance();
+ SpatialEditor::get_singleton()->register_gizmo_plugin(gizmo_plugin);
sep = memnew(VSeparator);
sep->hide();
@@ -630,18 +612,53 @@ PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) {
curve_edit->set_pressed(true);
/*
- collision_polygon_editor = memnew( PathEditor(p_node) );
- editor->get_viewport()->add_child(collision_polygon_editor);
+ collision_polygon_editor = memnew( PathEditor(p_node) );
+ editor->get_viewport()->add_child(collision_polygon_editor);
+ collision_polygon_editor->set_margin(MARGIN_LEFT,200);
+ collision_polygon_editor->set_margin(MARGIN_RIGHT,230);
+ collision_polygon_editor->set_margin(MARGIN_TOP,0);
+ collision_polygon_editor->set_margin(MARGIN_BOTTOM,10);
+ collision_polygon_editor->hide();
+ */
+}
- collision_polygon_editor->set_margin(MARGIN_LEFT,200);
- collision_polygon_editor->set_margin(MARGIN_RIGHT,230);
- collision_polygon_editor->set_margin(MARGIN_TOP,0);
- collision_polygon_editor->set_margin(MARGIN_BOTTOM,10);
+PathEditorPlugin::~PathEditorPlugin() {
+}
+
+Ref<EditorSpatialGizmo> PathSpatialGizmoPlugin::create_gizmo(Spatial *p_spatial) {
+ Ref<PathSpatialGizmo> ref;
+ Path *path = Object::cast_to<Path>(p_spatial);
+ if (path) ref = Ref<PathSpatialGizmo>(memnew(PathSpatialGizmo(path)));
- collision_polygon_editor->hide();
- */
+ return ref;
}
-PathEditorPlugin::~PathEditorPlugin() {
+String PathSpatialGizmoPlugin::get_name() const {
+ return "Path";
+}
+
+PathSpatialGizmoPlugin::PathSpatialGizmoPlugin() {
+
+ Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8));
+
+ Ref<SpatialMaterial> path_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+ path_color.a = 0.8;
+ path_material->set_albedo(path_color);
+ path_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ path_material->set_line_width(3);
+ path_material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+ path_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+
+ Ref<SpatialMaterial> path_thin_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+ path_color.a = 0.4;
+ path_thin_material->set_albedo(path_color);
+ path_thin_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ path_thin_material->set_line_width(1);
+ path_thin_material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+ path_thin_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+
+ add_material("path_material", path_material);
+ add_material("path_thin_material", path_thin_material);
+ create_handle_material("handles");
}
diff --git a/editor/plugins/path_editor_plugin.h b/editor/plugins/path_editor_plugin.h
index 52dfb78b61..61f309e794 100644
--- a/editor/plugins/path_editor_plugin.h
+++ b/editor/plugins/path_editor_plugin.h
@@ -49,10 +49,22 @@ public:
virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
- void redraw();
+ virtual void redraw();
PathSpatialGizmo(Path *p_path = NULL);
};
+class PathSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
+
+ GDCLASS(PathSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
+
+protected:
+ Ref<EditorSpatialGizmo> create_gizmo(Spatial *p_spatial);
+
+public:
+ String get_name() const;
+ PathSpatialGizmoPlugin();
+};
+
class PathEditorPlugin : public EditorPlugin {
GDCLASS(PathEditorPlugin, EditorPlugin);
@@ -88,12 +100,10 @@ public:
Path *get_edited_path() { return path; }
static PathEditorPlugin *singleton;
- Ref<SpatialMaterial> path_material;
- Ref<SpatialMaterial> path_thin_material;
virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
//virtual bool forward_gui_input(const InputEvent& p_event) { return collision_polygon_editor->forward_gui_input(p_event); }
- virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial);
+ //virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial);
virtual String get_name() const { return "Path"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 6cc8f91e38..af242e2d98 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -3097,7 +3097,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
error_dialog = memnew(AcceptDialog);
add_child(error_dialog);
- error_dialog->get_ok()->set_text(TTR("I see..."));
+ error_dialog->get_ok()->set_text(TTR("OK"));
debugger = memnew(ScriptEditorDebugger(editor));
debugger->connect("goto_script_line", this, "_goto_script_line");
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 0f48d42cf2..522ce52234 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -274,6 +274,23 @@ void ScriptTextEditor::_set_theme_for_script() {
}
}
+void ScriptTextEditor::_toggle_warning_pannel(const Ref<InputEvent> &p_event) {
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ warnings_panel->set_visible(!warnings_panel->is_visible());
+ }
+}
+
+void ScriptTextEditor::_warning_clicked(Variant p_line) {
+ if (p_line.get_type() == Variant::INT) {
+ code_editor->get_text_edit()->cursor_set_line(p_line.operator int64_t());
+ } else if (p_line.get_type() == Variant::DICTIONARY) {
+ Dictionary meta = p_line.operator Dictionary();
+ code_editor->get_text_edit()->insert_at("#warning-ignore:" + meta["code"].operator String(), meta["line"].operator int64_t() - 1);
+ _validate_script();
+ }
+}
+
void ScriptTextEditor::reload_text() {
ERR_FAIL_COND(script.is_null());
@@ -421,8 +438,9 @@ void ScriptTextEditor::_validate_script() {
String text = te->get_text();
List<String> fnc;
Set<int> safe_lines;
+ List<ScriptLanguage::Warning> warnings;
- if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc, &safe_lines)) {
+ if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc, &warnings, &safe_lines)) {
String error_text = "error(" + itos(line) + "," + itos(col) + "): " + errortxt;
code_editor->set_error(error_text);
} else {
@@ -442,6 +460,37 @@ void ScriptTextEditor::_validate_script() {
}
}
+ code_editor->get_warning_count_label()->set_text(itos(warnings.size()));
+ warnings_panel->clear();
+ warnings_panel->push_table(3);
+ for (List<ScriptLanguage::Warning>::Element *E = warnings.front(); E; E = E->next()) {
+ ScriptLanguage::Warning w = E->get();
+
+ warnings_panel->push_cell();
+ warnings_panel->push_meta(w.line - 1);
+ warnings_panel->push_color(warnings_panel->get_color("warning_color", "Editor"));
+ warnings_panel->add_text(TTR("Line") + " " + itos(w.line));
+ warnings_panel->add_text(" (" + w.string_code + "):");
+ warnings_panel->pop(); // Color
+ warnings_panel->pop(); // Meta goto
+ warnings_panel->pop(); // Cell
+
+ warnings_panel->push_cell();
+ warnings_panel->add_text(w.message);
+ warnings_panel->pop(); // Cell
+
+ Dictionary ignore_meta;
+ ignore_meta["line"] = w.line;
+ ignore_meta["code"] = w.string_code.to_lower();
+ warnings_panel->push_cell();
+ warnings_panel->push_meta(ignore_meta);
+ warnings_panel->add_text(TTR("(ignore)"));
+ warnings_panel->pop(); // Meta ignore
+ warnings_panel->pop(); // Cell
+ //warnings_panel->add_newline();
+ }
+ warnings_panel->pop(); // Table
+
line--;
bool highlight_safe = EDITOR_DEF("text_editor/highlighting/highlight_type_safe_lines", true);
bool last_is_safe = false;
@@ -1022,6 +1071,8 @@ void ScriptTextEditor::_bind_methods() {
ClassDB::bind_method("_goto_line", &ScriptTextEditor::_goto_line);
ClassDB::bind_method("_lookup_symbol", &ScriptTextEditor::_lookup_symbol);
ClassDB::bind_method("_text_edit_gui_input", &ScriptTextEditor::_text_edit_gui_input);
+ ClassDB::bind_method("_toggle_warning_pannel", &ScriptTextEditor::_toggle_warning_pannel);
+ ClassDB::bind_method("_warning_clicked", &ScriptTextEditor::_warning_clicked);
ClassDB::bind_method("_color_changed", &ScriptTextEditor::_color_changed);
ClassDB::bind_method("get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw);
@@ -1333,8 +1384,13 @@ ScriptTextEditor::ScriptTextEditor() {
theme_loaded = false;
+ VSplitContainer *editor_box = memnew(VSplitContainer);
+ add_child(editor_box);
+ editor_box->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ editor_box->set_v_size_flags(SIZE_EXPAND_FILL);
+
code_editor = memnew(CodeTextEditor);
- add_child(code_editor);
+ editor_box->add_child(code_editor);
code_editor->add_constant_override("separation", 0);
code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE);
code_editor->connect("validate_script", this, "_validate_script");
@@ -1342,7 +1398,20 @@ ScriptTextEditor::ScriptTextEditor() {
code_editor->set_code_complete_func(_code_complete_scripts, this);
code_editor->get_text_edit()->connect("breakpoint_toggled", this, "_breakpoint_toggled");
code_editor->get_text_edit()->connect("symbol_lookup", this, "_lookup_symbol");
- code_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ code_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+
+ warnings_panel = memnew(RichTextLabel);
+ editor_box->add_child(warnings_panel);
+ warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE));
+ warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL);
+ warnings_panel->set_meta_underline(true);
+ warnings_panel->set_selection_enabled(true);
+ warnings_panel->set_focus_mode(FOCUS_CLICK);
+ warnings_panel->hide();
+
+ code_editor->get_warning_label()->connect("gui_input", this, "_toggle_warning_pannel");
+ code_editor->get_warning_count_label()->connect("gui_input", this, "_toggle_warning_pannel");
+ warnings_panel->connect("meta_clicked", this, "_warning_clicked");
update_settings();
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 334d410dbe..837201a947 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -39,6 +39,7 @@ class ScriptTextEditor : public ScriptEditorBase {
GDCLASS(ScriptTextEditor, ScriptEditorBase);
CodeTextEditor *code_editor;
+ RichTextLabel *warnings_panel;
Ref<Script> script;
@@ -124,6 +125,8 @@ protected:
void _code_complete_script(const String &p_code, List<String> *r_options, bool &r_force);
void _load_theme_settings();
void _set_theme_for_script();
+ void _toggle_warning_pannel(const Ref<InputEvent> &p_event);
+ void _warning_clicked(Variant p_line);
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index eab1588a55..8871d8ac7e 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -184,49 +184,6 @@ Transform SpatialEditorViewport::to_camera_transform(const Cursor &p_cursor) con
return camera_transform;
}
-String SpatialEditorGizmo::get_handle_name(int p_idx) const {
-
- if (get_script_instance() && get_script_instance()->has_method("get_handle_name"))
- return get_script_instance()->call("get_handle_name", p_idx);
-
- return "";
-}
-
-Variant SpatialEditorGizmo::get_handle_value(int p_idx) const {
-
- if (get_script_instance() && get_script_instance()->has_method("get_handle_value"))
- return get_script_instance()->call("get_handle_value", p_idx);
-
- return Variant();
-}
-
-void SpatialEditorGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- if (get_script_instance() && get_script_instance()->has_method("set_handle"))
- get_script_instance()->call("set_handle", p_idx, p_camera, p_point);
-}
-
-void SpatialEditorGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
-
- if (get_script_instance() && get_script_instance()->has_method("commit_handle"))
- get_script_instance()->call("commit_handle", p_idx, p_restore, p_cancel);
-}
-
-bool SpatialEditorGizmo::intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum) {
-
- return false;
-}
-
-bool SpatialEditorGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) {
-
- return false;
-}
-
-SpatialEditorGizmo::SpatialEditorGizmo() {
-
- selected = false;
-}
-
int SpatialEditorViewport::get_selected_count() const {
Map<Node *, Object *> &selection = editor_selection->get_selection();
@@ -346,7 +303,7 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append,
Vector3 pos = _get_ray_pos(p_pos);
Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
- Set<Ref<SpatialEditorGizmo> > found_gizmos;
+ Set<Ref<EditorSpatialGizmo> > found_gizmos;
Node *edited_scene = get_tree()->get_edited_scene_root();
ObjectID closest = 0;
@@ -361,7 +318,7 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append,
if (!spat)
continue;
- Ref<SpatialEditorGizmo> seg = spat->get_gizmo();
+ Ref<EditorSpatialGizmo> seg = spat->get_gizmo();
if ((!seg.is_valid()) || found_gizmos.has(seg)) {
continue;
@@ -418,7 +375,7 @@ void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_incl
Vector3 pos = _get_ray_pos(p_pos);
Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
- Set<Ref<SpatialEditorGizmo> > found_gizmos;
+ Set<Ref<EditorSpatialGizmo> > found_gizmos;
r_includes_current = false;
@@ -429,7 +386,7 @@ void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_incl
if (!spat)
continue;
- Ref<SpatialEditorGizmo> seg = spat->get_gizmo();
+ Ref<EditorSpatialGizmo> seg = spat->get_gizmo();
if (!seg.is_valid())
continue;
@@ -559,7 +516,7 @@ void SpatialEditorViewport::_select_region() {
if (selected.find(root_sp) != -1) continue;
- Ref<SpatialEditorGizmo> seg = sp->get_gizmo();
+ Ref<EditorSpatialGizmo> seg = sp->get_gizmo();
if (!seg.is_valid())
continue;
@@ -963,7 +920,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (b->is_pressed() && _edit.gizmo.is_valid()) {
//restore
_edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, true);
- _edit.gizmo = Ref<SpatialEditorGizmo>();
+ _edit.gizmo = Ref<EditorSpatialGizmo>();
}
if (_edit.mode == TRANSFORM_NONE && b->is_pressed()) {
@@ -1079,7 +1036,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (can_select_gizmos && spatial_editor->get_selected()) {
- Ref<SpatialEditorGizmo> seg = spatial_editor->get_selected()->get_gizmo();
+ Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo();
if (seg.is_valid()) {
int handle = -1;
Vector3 point;
@@ -1158,7 +1115,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Spatial *spa = Object::cast_to<Spatial>(ObjectDB::get_instance(clicked));
if (spa) {
- Ref<SpatialEditorGizmo> seg = spa->get_gizmo();
+ Ref<EditorSpatialGizmo> seg = spa->get_gizmo();
if (seg.is_valid()) {
_edit.gizmo = seg;
@@ -1175,7 +1132,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (_edit.gizmo.is_valid()) {
_edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, false);
- _edit.gizmo = Ref<SpatialEditorGizmo>();
+ _edit.gizmo = Ref<EditorSpatialGizmo>();
break;
}
if (clicked) {
@@ -1233,7 +1190,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (spatial_editor->get_selected()) {
- Ref<SpatialEditorGizmo> seg = spatial_editor->get_selected()->get_gizmo();
+ Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo();
if (seg.is_valid()) {
int selected_handle = -1;
@@ -3099,7 +3056,7 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const
Vector3 world_pos = _get_ray_pos(p_pos);
Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(world_pos, world_ray, get_tree()->get_root()->get_world()->get_scenario());
- Set<Ref<SpatialEditorGizmo> > found_gizmos;
+ Set<Ref<EditorSpatialGizmo> > found_gizmos;
float closest_dist = MAX_DISTANCE;
@@ -3113,7 +3070,7 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const
if (!mesh_instance)
continue;
- Ref<SpatialEditorGizmo> seg = mesh_instance->get_gizmo();
+ Ref<EditorSpatialGizmo> seg = mesh_instance->get_gizmo();
if ((!seg.is_valid()) || found_gizmos.has(seg)) {
continue;
@@ -3308,7 +3265,7 @@ void SpatialEditorViewport::_perform_drop_data() {
files_str += error_files[i].get_file().get_basename() + ",";
}
files_str = files_str.substr(0, files_str.length() - 1);
- accept->get_ok()->set_text(TTR("Ugh"));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str()));
accept->popup_centered_minsize();
}
@@ -3397,7 +3354,7 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p
}
}
if (list.size() != 1) {
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation requires a single selected node."));
accept->popup_centered_minsize();
_remove_preview();
@@ -4048,6 +4005,16 @@ Dictionary SpatialEditor::get_state() const {
d["znear"] = get_znear();
d["zfar"] = get_zfar();
+ Dictionary gizmos_status;
+ for (int i = 0; i < gizmo_plugins.size(); i++) {
+ if (!gizmo_plugins[i]->can_be_hidden()) continue;
+ bool checked = gizmos_menu->get_popup()->is_item_checked(gizmos_menu->get_popup()->get_item_index(i));
+ String name = gizmo_plugins[i]->get_name();
+ gizmos_status[name] = checked;
+ }
+
+ d["gizmos_status"] = gizmos_status;
+
return d;
}
void SpatialEditor::set_state(const Dictionary &p_state) {
@@ -4121,6 +4088,24 @@ void SpatialEditor::set_state(const Dictionary &p_state) {
VisualServer::get_singleton()->instance_set_visible(origin_instance, use);
}
}
+
+ if (d.has("gizmos_status")) {
+ Dictionary gizmos_status = d["gizmos_status"];
+ List<Variant> keys;
+ gizmos_status.get_key_list(&keys);
+
+ for (int j = 0; j < gizmo_plugins.size(); ++j) {
+ if (!gizmo_plugins[j]->can_be_hidden()) continue;
+ bool checked = true;
+ for (uint32_t i = 0; i < keys.size(); i++) {
+ if (gizmo_plugins.write[j]->get_name() == keys[i]) {
+ checked = gizmos_status[keys[i]];
+ }
+ }
+ gizmos_menu->get_popup()->set_item_checked(gizmos_menu->get_popup()->get_item_index(j), checked);
+ gizmo_plugins.write[j]->set_hidden(!checked);
+ }
+ }
}
void SpatialEditor::edit(Spatial *p_spatial) {
@@ -4128,7 +4113,7 @@ void SpatialEditor::edit(Spatial *p_spatial) {
if (p_spatial != selected) {
if (selected) {
- Ref<SpatialEditorGizmo> seg = selected->get_gizmo();
+ Ref<EditorSpatialGizmo> seg = selected->get_gizmo();
if (seg.is_valid()) {
seg->set_selected(false);
selected->update_gizmo();
@@ -4140,7 +4125,7 @@ void SpatialEditor::edit(Spatial *p_spatial) {
if (selected) {
- Ref<SpatialEditorGizmo> seg = selected->get_gizmo();
+ Ref<EditorSpatialGizmo> seg = selected->get_gizmo();
if (seg.is_valid()) {
seg->set_selected(true);
selected->update_gizmo();
@@ -4214,6 +4199,15 @@ void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) {
}
}
+void SpatialEditor::_menu_gizmo_toggled(int p_option) {
+ bool is_checked = gizmos_menu->get_popup()->is_item_checked(gizmos_menu->get_popup()->get_item_index(p_option));
+
+ is_checked = !is_checked;
+ gizmo_plugins.write[p_option]->set_hidden(!is_checked);
+
+ gizmos_menu->get_popup()->set_item_checked(gizmos_menu->get_popup()->get_item_index(p_option), is_checked);
+}
+
void SpatialEditor::_menu_item_pressed(int p_option) {
switch (p_option) {
@@ -4725,6 +4719,27 @@ void SpatialEditor::_init_indicators() {
_generate_selection_box();
}
+struct _GizmoPluginComparator {
+
+ bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const {
+ return p_a->get_name() < p_b->get_name();
+ }
+};
+
+void SpatialEditor::_init_gizmos_menu() {
+ _register_all_gizmos();
+
+ PopupMenu *p = gizmos_menu->get_popup();
+
+ gizmo_plugins.sort_custom<_GizmoPluginComparator>();
+
+ for (int i = 0; i < gizmo_plugins.size(); ++i) {
+ if (!gizmo_plugins[i]->can_be_hidden()) continue;
+ String plugin_name = gizmo_plugins[i]->get_name();
+ p->add_check_item(TTR(plugin_name), i);
+ }
+}
+
void SpatialEditor::_init_grid() {
PoolVector<Color> grid_colors[3];
@@ -5018,14 +5033,13 @@ void SpatialEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- gizmos = memnew(SpatialEditorGizmos);
+ _init_gizmos_menu();
_init_indicators();
}
if (p_what == NOTIFICATION_EXIT_TREE) {
_finish_indicators();
- memdelete(gizmos);
}
if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
tool_button[SpatialEditor::TOOL_MODE_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons"));
@@ -5084,25 +5098,21 @@ void SpatialEditor::_request_gizmo(Object *p_obj) {
return;
if (editor->get_edited_scene() && (sp == editor->get_edited_scene() || (sp->get_owner() && editor->get_edited_scene()->is_a_parent_of(sp)))) {
- Ref<SpatialEditorGizmo> seg;
+ Ref<EditorSpatialGizmo> seg;
- for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_editor_plugin_count(); i++) {
+ for (int i = 0; i < gizmo_plugins.size(); ++i) {
+ seg = gizmo_plugins.write[i]->get_gizmo(sp);
- seg = EditorNode::get_singleton()->get_editor_data().get_editor_plugin(i)->create_spatial_gizmo(sp);
- if (seg.is_valid())
- break;
- }
+ if (seg.is_valid()) {
+ sp->set_gizmo(seg);
- if (!seg.is_valid()) {
- seg = gizmos->get_gizmo(sp);
- }
- if (seg.is_valid()) {
- sp->set_gizmo(seg);
- }
+ if (sp == selected) {
+ seg->set_selected(true);
+ selected->update_gizmo();
+ }
- if (seg.is_valid() && sp == selected) {
- seg->set_selected(true);
- selected->update_gizmo();
+ break;
+ }
}
}
}
@@ -5158,11 +5168,35 @@ void SpatialEditor::_node_removed(Node *p_node) {
selected = NULL;
}
+void SpatialEditor::_register_all_gizmos() {
+ register_gizmo_plugin(Ref<CameraSpatialGizmoPlugin>(memnew(CameraSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<LightSpatialGizmoPlugin>(memnew(LightSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<AudioStreamPlayer3DSpatialGizmoPlugin>(memnew(AudioStreamPlayer3DSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<MeshInstanceSpatialGizmoPlugin>(memnew(MeshInstanceSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<SoftBodySpatialGizmoPlugin>(memnew(SoftBodySpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<Sprite3DSpatialGizmoPlugin>(memnew(Sprite3DSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<Position3DSpatialGizmoPlugin>(memnew(Position3DSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<SkeletonSpatialGizmoPlugin>(memnew(SkeletonSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<RayCastSpatialGizmoPlugin>(memnew(RayCastSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<VehicleWheelSpatialGizmoPlugin>(memnew(VehicleWheelSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin)));
+ register_gizmo_plugin(Ref<ParticlesGizmoPlugin>(memnew(ParticlesGizmoPlugin)));
+ register_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin)));
+ register_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin)));
+ register_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin)));
+ register_gizmo_plugin(Ref<CollisionShapeSpatialGizmoPlugin>(memnew(CollisionShapeSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<NavigationMeshSpatialGizmoPlugin>(memnew(NavigationMeshSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<JointSpatialGizmoPlugin>(memnew(JointSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<PhysicalBoneSpatialGizmoPlugin>(memnew(PhysicalBoneSpatialGizmoPlugin)));
+}
+
void SpatialEditor::_bind_methods() {
ClassDB::bind_method("_unhandled_key_input", &SpatialEditor::_unhandled_key_input);
ClassDB::bind_method("_node_removed", &SpatialEditor::_node_removed);
ClassDB::bind_method("_menu_item_pressed", &SpatialEditor::_menu_item_pressed);
+ ClassDB::bind_method("_menu_gizmo_toggled", &SpatialEditor::_menu_gizmo_toggled);
ClassDB::bind_method("_menu_item_toggled", &SpatialEditor::_menu_item_toggled);
ClassDB::bind_method("_xform_dialog_action", &SpatialEditor::_xform_dialog_action);
ClassDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data);
@@ -5376,6 +5410,12 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
p->connect("id_pressed", this, "_menu_item_pressed");
+ gizmos_menu = memnew(MenuButton);
+ gizmos_menu->set_text(TTR("Gizmos"));
+ hbc_menu->add_child(gizmos_menu);
+ gizmos_menu->get_popup()->set_hide_on_checkable_item_selection(false);
+ gizmos_menu->get_popup()->connect("id_pressed", this, "_menu_gizmo_toggled");
+
/* REST OF MENU */
palette_split = memnew(HSplitContainer);
@@ -5583,6 +5623,10 @@ void SpatialEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) {
spatial_editor->snap_cursor_to_plane(p_plane);
}
+void SpatialEditor::register_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> ref) {
+ gizmo_plugins.push_back(ref);
+}
+
SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) {
editor = p_node;
@@ -5596,3 +5640,171 @@ SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) {
SpatialEditorPlugin::~SpatialEditorPlugin() {
}
+
+void EditorSpatialGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) {
+
+ Color instanced_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced");
+
+ Vector<Ref<SpatialMaterial> > mats;
+
+ for (int i = 0; i < 4; i++) {
+ bool selected = i % 2 == 1;
+ bool instanced = i < 2;
+
+ Ref<SpatialMaterial> material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+
+ Color color = instanced ? instanced_color : p_color;
+
+ if (!selected) {
+ color.a *= 0.3;
+ }
+
+ material->set_albedo(color);
+ material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+ material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+
+ if (p_use_vertex_color) {
+ material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+ }
+
+ if (p_billboard) {
+ material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
+ }
+
+ if (p_on_top && selected) {
+ material->set_on_top_of_alpha();
+ }
+
+ mats.push_back(material);
+ }
+
+ materials[p_name] = mats;
+}
+
+void EditorSpatialGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top, const Color &p_albedo) {
+
+ Color instanced_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced");
+
+ Vector<Ref<SpatialMaterial> > icons;
+
+ for (int i = 0; i < 4; i++) {
+ bool selected = i % 2 == 1;
+ bool instanced = i < 2;
+
+ Ref<SpatialMaterial> icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+
+ Color color = instanced ? instanced_color : p_albedo;
+
+ if (!selected) {
+ color.a *= 0.3;
+ }
+
+ icon->set_albedo(color);
+
+ icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+ icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+ icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
+ icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, p_texture);
+ icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true);
+ icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
+
+ if (p_on_top && selected) {
+ icon->set_on_top_of_alpha();
+ }
+
+ icons.push_back(icon);
+ }
+
+ materials[p_name] = icons;
+}
+
+void EditorSpatialGizmoPlugin::create_handle_material(const String &p_name, bool p_billboard) {
+ Ref<SpatialMaterial> handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+
+ handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+ handle_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+ handle_material->set_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true);
+ Ref<Texture> handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle", "EditorIcons");
+ handle_material->set_point_size(handle_t->get_width());
+ handle_material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, handle_t);
+ handle_material->set_albedo(Color(1, 1, 1));
+ handle_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ handle_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ handle_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+ handle_material->set_on_top_of_alpha();
+ if (p_billboard) {
+ handle_material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
+ handle_material->set_on_top_of_alpha();
+ }
+
+ materials[p_name] = Vector<Ref<SpatialMaterial> >();
+ materials[p_name].push_back(handle_material);
+}
+
+void EditorSpatialGizmoPlugin::add_material(const String &p_name, Ref<SpatialMaterial> p_material) {
+ materials[p_name] = Vector<Ref<SpatialMaterial> >();
+ materials[p_name].push_back(p_material);
+}
+
+Ref<SpatialMaterial> EditorSpatialGizmoPlugin::get_material(const String &p_name, EditorSpatialGizmo *p_gizmo) {
+ ERR_FAIL_COND_V(!materials.has(p_name), Ref<SpatialMaterial>());
+ ERR_FAIL_COND_V(materials[p_name].size() == 0, Ref<SpatialMaterial>());
+
+ if (p_gizmo == NULL) return materials[p_name][0];
+
+ int index = (p_gizmo->is_selected() ? 1 : 0) + (p_gizmo->is_editable() ? 2 : 0);
+ return materials[p_name][index];
+}
+
+Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::get_gizmo(Spatial *p_spatial) {
+
+ Ref<EditorSpatialGizmo> ref = create_gizmo(p_spatial);
+
+ if (ref.is_null()) return ref;
+
+ ref->set_plugin(this);
+ ref->set_spatial_node(p_spatial);
+ ref->set_hidden(hidden);
+
+ current_gizmos.push_back(ref.ptr());
+ return ref;
+}
+
+bool EditorSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return false;
+}
+
+Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::create_gizmo(Spatial *p_spatial) {
+
+ Ref<EditorSpatialGizmo> ref;
+ if (has_gizmo(p_spatial)) ref.instance();
+ return ref;
+}
+
+bool EditorSpatialGizmoPlugin::can_be_hidden() const {
+ return true;
+}
+
+bool EditorSpatialGizmoPlugin::is_selectable_when_hidden() const {
+ return false;
+}
+
+void EditorSpatialGizmoPlugin::set_hidden(bool p_hidden) {
+ hidden = p_hidden;
+ for (int i = 0; i < current_gizmos.size(); ++i) {
+ current_gizmos[i]->set_hidden(hidden);
+ }
+}
+
+void EditorSpatialGizmoPlugin::unregister_gizmo(EditorSpatialGizmo *p_gizmo) {
+ current_gizmos.erase(p_gizmo);
+}
+
+EditorSpatialGizmoPlugin::EditorSpatialGizmoPlugin() {
+ hidden = false;
+}
+
+EditorSpatialGizmoPlugin::~EditorSpatialGizmoPlugin() {
+}
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index bd449a28df..42e6a24bc5 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -43,11 +43,11 @@
class Camera;
class SpatialEditor;
-class SpatialEditorGizmos;
+class EditorSpatialGizmoPlugin;
-class SpatialEditorGizmo : public SpatialGizmo {
+class EditorSpatialGizmo : public SpatialGizmo {
- GDCLASS(SpatialEditorGizmo, SpatialGizmo);
+ GDCLASS(EditorSpatialGizmo, SpatialGizmo);
bool selected;
bool instanced;
@@ -56,15 +56,86 @@ public:
void set_selected(bool p_selected) { selected = p_selected; }
bool is_selected() const { return selected; }
+ struct Instance {
+
+ RID instance;
+ Ref<ArrayMesh> mesh;
+ RID skeleton;
+ bool billboard;
+ bool unscaled;
+ bool can_intersect;
+ bool extra_margin;
+ Instance() {
+
+ billboard = false;
+ unscaled = false;
+ can_intersect = false;
+ extra_margin = false;
+ }
+
+ void create_instance(Spatial *p_base, bool p_hidden = false);
+ };
+
+ Vector<Vector3> collision_segments;
+ Ref<TriangleMesh> collision_mesh;
+
+ struct Handle {
+ Vector3 pos;
+ bool billboard;
+ };
+
+ Vector<Vector3> handles;
+ Vector<Vector3> secondary_handles;
+ float selectable_icon_size = -1.0f;
+ bool billboard_handle;
+
+ bool valid;
+ bool hidden;
+ Spatial *base;
+ Vector<Instance> instances;
+ Spatial *spatial_node;
+ EditorSpatialGizmoPlugin *gizmo_plugin;
+
+ void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Spatial>(p_node)); }
+
+protected:
+ static void _bind_methods();
+
+public:
+ void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false);
+ void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID());
+ void add_collision_segments(const Vector<Vector3> &p_lines);
+ void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh);
+ void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1);
+ void add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, bool p_billboard = false, bool p_secondary = false);
+ void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3());
+
virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
+ virtual Variant get_handle_value(int p_idx);
virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
- virtual bool is_gizmo_handle_highlighted(int idx) const { return false; }
- virtual bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum);
- virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false);
- SpatialEditorGizmo();
+ void set_spatial_node(Spatial *p_node);
+ Spatial *get_spatial_node() const { return spatial_node; }
+ Vector3 get_handle_pos(int p_idx) const;
+ bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum);
+ bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false);
+
+ virtual void clear();
+ virtual void create();
+ virtual void transform();
+ virtual void redraw();
+ virtual void free();
+
+ //TODO remove (?)
+ virtual bool is_editable() const;
+ virtual bool can_draw() const;
+
+ void set_hidden(bool p_hidden);
+ void set_plugin(EditorSpatialGizmoPlugin *p_gizmo);
+
+ EditorSpatialGizmo();
+ ~EditorSpatialGizmo();
};
class SpatialEditorViewport : public Control {
@@ -233,7 +304,7 @@ private:
int edited_gizmo;
Point2 mouse_pos;
bool snap;
- Ref<SpatialEditorGizmo> gizmo;
+ Ref<EditorSpatialGizmo> gizmo;
int gizmo_handle;
Variant gizmo_initial_value;
Vector3 gizmo_initial_pos;
@@ -500,6 +571,7 @@ private:
Button *tool_option_button[TOOL_OPT_MAX];
MenuButton *transform_menu;
+ MenuButton *gizmos_menu;
MenuButton *view_menu;
ToolButton *lock_button;
@@ -531,6 +603,7 @@ private:
void _xform_dialog_action();
void _menu_item_pressed(int p_option);
void _menu_item_toggled(bool pressed, int p_option);
+ void _menu_gizmo_toggled(int p_option);
HBoxContainer *hbc_menu;
@@ -539,6 +612,7 @@ private:
void _instance_scene();
void _init_indicators();
+ void _init_gizmos_menu();
void _init_grid();
void _finish_indicators();
void _finish_grid();
@@ -558,7 +632,10 @@ private:
static SpatialEditor *singleton;
void _node_removed(Node *p_node);
- SpatialEditorGizmos *gizmos;
+ Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins;
+
+ void _register_all_gizmos();
+
SpatialEditor();
bool is_any_freelook_active() const;
@@ -632,6 +709,8 @@ public:
return viewports[p_idx];
}
+ void register_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> ref);
+
Camera *get_camera() { return NULL; }
void edit(Spatial *p_spatial);
void clear();
@@ -668,4 +747,43 @@ public:
~SpatialEditorPlugin();
};
+class EditorSpatialGizmoPlugin : public Resource {
+
+ GDCLASS(EditorSpatialGizmoPlugin, Resource);
+
+ bool hidden;
+ List<EditorSpatialGizmo *> current_gizmos;
+ HashMap<String, Vector<Ref<SpatialMaterial> > > materials;
+
+protected:
+ virtual bool has_gizmo(Spatial *p_spatial);
+ virtual Ref<EditorSpatialGizmo> create_gizmo(Spatial *p_spatial);
+
+public:
+ void create_material(const String &p_name, const Color &p_color, bool p_billboard = false, bool p_on_top = false, bool p_use_vertex_color = false);
+ void create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top = false, const Color &p_albedo = Color(1, 1, 1, 1));
+ void create_handle_material(const String &p_name, bool p_billboard = false);
+ void add_material(const String &p_name, Ref<SpatialMaterial> p_material);
+
+ Ref<SpatialMaterial> get_material(const String &p_name, EditorSpatialGizmo *p_gizmo = NULL);
+
+ virtual String get_name() const = 0;
+ virtual bool can_be_hidden() const;
+ virtual bool is_selectable_when_hidden() const;
+
+ virtual void redraw(EditorSpatialGizmo *p_gizmo) {}
+ virtual String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { return ""; }
+ virtual Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { return Variant(); }
+ virtual void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {}
+ virtual void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false) {}
+ virtual bool is_gizmo_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const { return false; }
+
+ Ref<EditorSpatialGizmo> get_gizmo(Spatial *p_spatial);
+ void set_hidden(bool p_hidden);
+ void unregister_gizmo(EditorSpatialGizmo *p_gizmo);
+
+ EditorSpatialGizmoPlugin();
+ virtual ~EditorSpatialGizmoPlugin();
+};
+
#endif
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index e4fdd1f251..0419c3d4b1 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -57,8 +57,6 @@ void TextureRegionEditor::_region_draw() {
base_tex = obj_styleBox->get_texture();
else if (atlas_tex.is_valid())
base_tex = atlas_tex->get_atlas();
- else if (tile_set.is_valid() && selected_tile != -1 && tile_set->has_tile(selected_tile))
- base_tex = tile_set->tile_get_texture(selected_tile);
if (base_tex.is_null())
return;
@@ -284,8 +282,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
r = obj_styleBox->get_region_rect();
else if (atlas_tex.is_valid())
r = atlas_tex->get_region();
- else if (tile_set.is_valid() && selected_tile != -1)
- r = tile_set->tile_get_region(selected_tile);
rect.expand_to(r.position);
rect.expand_to(r.position + r.size);
}
@@ -302,9 +298,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
} else if (atlas_tex.is_valid()) {
undo_redo->add_do_method(atlas_tex.ptr(), "set_region", rect);
undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region());
- } else if (tile_set.is_valid() && selected_tile != -1) {
- undo_redo->add_do_method(tile_set.ptr(), "tile_set_region", selected_tile, rect);
- undo_redo->add_undo_method(tile_set.ptr(), "tile_set_region", selected_tile, tile_set->tile_get_region(selected_tile));
}
undo_redo->add_do_method(edit_draw, "update");
undo_redo->add_undo_method(edit_draw, "update");
@@ -327,8 +320,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
rect_prev = obj_styleBox->get_region_rect();
else if (atlas_tex.is_valid())
rect_prev = atlas_tex->get_region();
- else if (tile_set.is_valid() && selected_tile != -1)
- rect_prev = tile_set->tile_get_region(selected_tile);
for (int i = 0; i < 8; i++) {
Vector2 tuv = endpoints[i];
@@ -372,9 +363,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
} else if (obj_styleBox.is_valid()) {
undo_redo->add_do_method(obj_styleBox.ptr(), "set_region_rect", obj_styleBox->get_region_rect());
undo_redo->add_undo_method(obj_styleBox.ptr(), "set_region_rect", rect_prev);
- } else if (tile_set.is_valid()) {
- undo_redo->add_do_method(tile_set.ptr(), "tile_set_region", selected_tile, tile_set->tile_get_region(selected_tile));
- undo_redo->add_undo_method(tile_set.ptr(), "tile_set_region", selected_tile, rect_prev);
}
drag_index = -1;
}
@@ -595,8 +583,6 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) {
obj_styleBox->set_region_rect(rect);
else if (atlas_tex.is_valid())
atlas_tex->set_region(rect);
- else if (tile_set.is_valid() && selected_tile != -1)
- tile_set->tile_set_region(selected_tile, rect);
}
void TextureRegionEditor::_notification(int p_what) {
@@ -623,12 +609,11 @@ void TextureRegionEditor::_notification(int p_what) {
}
void TextureRegionEditor::_node_removed(Object *p_obj) {
- if (p_obj == node_sprite || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr() || p_obj == tile_set.ptr()) {
+ if (p_obj == node_sprite || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr()) {
node_ninepatch = NULL;
node_sprite = NULL;
obj_styleBox = Ref<StyleBox>(NULL);
atlas_tex = Ref<AtlasTexture>(NULL);
- tile_set = Ref<TileSet>(NULL);
hide();
}
}
@@ -677,8 +662,6 @@ void TextureRegionEditor::edit(Object *p_obj) {
obj_styleBox->remove_change_receptor(this);
if (atlas_tex.is_valid())
atlas_tex->remove_change_receptor(this);
- if (tile_set.is_valid())
- tile_set->remove_change_receptor(this);
if (p_obj) {
node_sprite = Object::cast_to<Sprite>(p_obj);
node_ninepatch = Object::cast_to<NinePatchRect>(p_obj);
@@ -686,8 +669,6 @@ void TextureRegionEditor::edit(Object *p_obj) {
obj_styleBox = Ref<StyleBoxTexture>(Object::cast_to<StyleBoxTexture>(p_obj));
if (Object::cast_to<AtlasTexture>(p_obj))
atlas_tex = Ref<AtlasTexture>(Object::cast_to<AtlasTexture>(p_obj));
- if (Object::cast_to<TileSet>(p_obj))
- tile_set = Ref<TileSet>(Object::cast_to<TileSet>(p_obj));
p_obj->add_change_receptor(this);
_edit_region();
} else {
@@ -695,7 +676,6 @@ void TextureRegionEditor::edit(Object *p_obj) {
node_ninepatch = NULL;
obj_styleBox = Ref<StyleBoxTexture>(NULL);
atlas_tex = Ref<AtlasTexture>(NULL);
- tile_set = Ref<TileSet>(NULL);
}
edit_draw->update();
if (node_sprite && !node_sprite->is_region()) {
@@ -724,8 +704,6 @@ void TextureRegionEditor::_edit_region() {
texture = obj_styleBox->get_texture();
else if (atlas_tex.is_valid())
texture = atlas_tex->get_atlas();
- else if (tile_set.is_valid() && selected_tile != -1 && tile_set->has_tile(selected_tile))
- texture = tile_set->tile_get_texture(selected_tile);
if (texture.is_null()) {
edit_draw->update();
@@ -794,8 +772,6 @@ void TextureRegionEditor::_edit_region() {
rect = obj_styleBox->get_region_rect();
else if (atlas_tex.is_valid())
rect = atlas_tex->get_region();
- else if (tile_set.is_valid() && selected_tile != -1)
- rect = tile_set->tile_get_region(selected_tile);
edit_draw->update();
}
@@ -814,10 +790,8 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
node_ninepatch = NULL;
obj_styleBox = Ref<StyleBoxTexture>(NULL);
atlas_tex = Ref<AtlasTexture>(NULL);
- tile_set = Ref<TileSet>(NULL);
editor = p_editor;
undo_redo = editor->get_undo_redo();
- selected_tile = -1;
snap_step = Vector2(10, 10);
snap_separation = Vector2(0, 0);
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index eeba1987a6..bd93be9267 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -38,7 +38,6 @@
#include "scene/gui/nine_patch_rect.h"
#include "scene/resources/style_box.h"
#include "scene/resources/texture.h"
-#include "scene/resources/tile_set.h"
/**
@author Mariano Suligoy
@@ -56,8 +55,6 @@ class TextureRegionEditor : public Control {
};
friend class TextureRegionEditorPlugin;
- friend class TileSetEditor;
- friend class TileSetEditorPlugin;
MenuButton *snap_mode_button;
TextureRect *icon_zoom;
ToolButton *zoom_in;
@@ -91,14 +88,12 @@ class TextureRegionEditor : public Control {
Sprite *node_sprite;
Ref<StyleBoxTexture> obj_styleBox;
Ref<AtlasTexture> atlas_tex;
- Ref<TileSet> tile_set;
Rect2 rect;
Rect2 rect_prev;
float prev_margin;
int edited_margin;
List<Rect2> autoslice_cache;
- int selected_tile;
bool drag;
bool creating;
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 435ef229c5..0b84535c19 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -168,10 +168,11 @@ void TileMapEditor::_menu_option(int p_option) {
}
void TileMapEditor::_palette_selected(int index) {
+ _update_palette();
+}
- if (manual_autotile) {
- _update_palette();
- }
+void TileMapEditor::_palette_multi_selected(int index, bool selected) {
+ _update_palette();
}
void TileMapEditor::_canvas_mouse_enter() {
@@ -296,7 +297,7 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p
}
node->set_cell(p_pos.x, p_pos.y, p_value, p_flip_h, p_flip_v, p_transpose);
- if (manual_autotile) {
+ if (manual_autotile || node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE) {
if (current != -1) {
node->set_cell_autotile_coord(p_pos.x, p_pos.y, position);
}
@@ -317,7 +318,6 @@ void TileMapEditor::_text_entered(const String &p_text) {
}
void TileMapEditor::_text_changed(const String &p_text) {
-
_update_palette();
}
@@ -427,7 +427,7 @@ void TileMapEditor::_update_palette() {
if (tex.is_valid()) {
Rect2 region = tileset->tile_get_region(entries[i].id);
- if (tileset->tile_get_tile_mode(entries[i].id) == TileSet::AUTO_TILE) {
+ if (tileset->tile_get_tile_mode(entries[i].id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(entries[i].id) == TileSet::ATLAS_TILE) {
int spacing = tileset->autotile_get_spacing(entries[i].id);
region.size = tileset->autotile_get_size(entries[i].id);
region.position += (region.size + Vector2(spacing, spacing)) * tileset->autotile_get_icon_coordinate(entries[i].id);
@@ -450,7 +450,7 @@ void TileMapEditor::_update_palette() {
palette->select(0);
}
- if (manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) {
+ 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> &tiles = tileset->autotile_get_bitmask_map(sel_tile);
@@ -676,10 +676,10 @@ void TileMapEditor::_draw_cell(int p_cell, const Point2i &p_point, bool p_flip_h
Vector2 tile_ofs = node->get_tileset()->tile_get_texture_offset(p_cell);
Rect2 r = node->get_tileset()->tile_get_region(p_cell);
- if (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::AUTO_TILE) {
+ if (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::AUTO_TILE || node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE) {
Vector2 offset;
int selected = manual_palette->get_current();
- if (manual_autotile && selected != -1) {
+ if ((manual_autotile || node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE) && selected != -1) {
offset = manual_palette->get_item_metadata(selected);
} else {
offset = node->get_tileset()->autotile_get_icon_coordinate(p_cell);
@@ -1673,6 +1673,7 @@ void TileMapEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_tileset_settings_changed"), &TileMapEditor::_tileset_settings_changed);
ClassDB::bind_method(D_METHOD("_update_transform_buttons"), &TileMapEditor::_update_transform_buttons);
ClassDB::bind_method(D_METHOD("_palette_selected"), &TileMapEditor::_palette_selected);
+ ClassDB::bind_method(D_METHOD("_palette_multi_selected"), &TileMapEditor::_palette_multi_selected);
ClassDB::bind_method(D_METHOD("_fill_points"), &TileMapEditor::_fill_points);
ClassDB::bind_method(D_METHOD("_erase_points"), &TileMapEditor::_erase_points);
@@ -1800,6 +1801,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
palette->set_max_text_lines(2);
palette->set_select_mode(ItemList::SELECT_MULTI);
palette->connect("item_selected", this, "_palette_selected");
+ palette->connect("multi_selected", this, "_palette_multi_selected");
palette_container->add_child(palette);
// Add autotile override palette
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
index b8443ca962..bb76879b02 100644
--- a/editor/plugins/tile_map_editor_plugin.h
+++ b/editor/plugins/tile_map_editor_plugin.h
@@ -184,6 +184,7 @@ class TileMapEditor : public VBoxContainer {
void _update_palette();
void _menu_option(int p_option);
void _palette_selected(int index);
+ void _palette_multi_selected(int index, bool selected);
void _start_undo(const String &p_action);
void _finish_undo();
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 087c4293f1..8d1db5de8f 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -30,6 +30,8 @@
#include "tile_set_editor_plugin.h"
+#include "core/os/input.h"
+#include "core/os/keyboard.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/2d/physics_body_2d.h"
#include "scene/2d/sprite.h"
@@ -39,7 +41,9 @@ void TileSetEditor::edit(const Ref<TileSet> &p_tileset) {
tileset = p_tileset;
tileset->add_change_receptor(this);
- update_tile_list();
+ texture_list->clear();
+ texture_map.clear();
+ update_texture_list();
}
void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) {
@@ -161,75 +165,6 @@ void TileSetEditor::_import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_
_import_node(p_scene, p_library);
}
-void TileSetEditor::_menu_confirm() {
-
- switch (option) {
-
- case MENU_OPTION_MERGE_FROM_SCENE:
- case MENU_OPTION_CREATE_FROM_SCENE: {
-
- EditorNode *en = editor;
- Node *scene = en->get_edited_scene();
- if (!scene)
- break;
-
- _import_scene(scene, tileset, option == MENU_OPTION_MERGE_FROM_SCENE);
-
- } break;
- }
-}
-
-void TileSetEditor::_name_dialog_confirm(const String &name) {
-
- switch (option) {
-
- case MENU_OPTION_REMOVE_ITEM: {
-
- int id = tileset->find_tile_by_name(name);
-
- if (id < 0 && name.is_valid_integer())
- id = name.to_int();
-
- if (tileset->has_tile(id)) {
- tileset->remove_tile(id);
- update_tile_list();
- } else {
- err_dialog->set_text(TTR("Could not find tile:") + " " + name);
- err_dialog->popup_centered(Size2(300, 60));
- }
- } break;
- }
-}
-
-void TileSetEditor::_menu_cbk(int p_option) {
-
- option = p_option;
- switch (p_option) {
-
- case MENU_OPTION_ADD_ITEM: {
- tileset->create_tile(tileset->get_last_unused_tile_id());
- tileset->tile_set_name(tileset->get_last_unused_tile_id() - 1, itos(tileset->get_last_unused_tile_id() - 1));
- update_tile_list();
- } break;
- case MENU_OPTION_REMOVE_ITEM: {
-
- nd->set_title(TTR("Remove Item"));
- nd->set_text(TTR("Item name or ID:"));
- nd->popup_centered(Size2(300, 95));
- } break;
- case MENU_OPTION_CREATE_FROM_SCENE: {
-
- cd->set_text(TTR("Create from scene?"));
- cd->popup_centered(Size2(300, 60));
- } break;
- case MENU_OPTION_MERGE_FROM_SCENE: {
-
- cd->set_text(TTR("Merge from scene?"));
- cd->popup_centered(Size2(300, 60));
- } break;
- }
-}
-
Error TileSetEditor::update_library_file(Node *p_base_scene, Ref<TileSet> ml, bool p_merge) {
_import_scene(p_base_scene, ml, p_merge);
@@ -237,28 +172,36 @@ Error TileSetEditor::update_library_file(Node *p_base_scene, Ref<TileSet> ml, bo
}
void TileSetEditor::_bind_methods() {
-
- ClassDB::bind_method("_menu_cbk", &TileSetEditor::_menu_cbk);
- ClassDB::bind_method("_menu_confirm", &TileSetEditor::_menu_confirm);
- ClassDB::bind_method("_name_dialog_confirm", &TileSetEditor::_name_dialog_confirm);
- ClassDB::bind_method("_on_tile_list_selected", &TileSetEditor::_on_tile_list_selected);
+ ClassDB::bind_method("_on_tileset_toolbar_button_pressed", &TileSetEditor::_on_tileset_toolbar_button_pressed);
+ ClassDB::bind_method("_on_textures_added", &TileSetEditor::_on_textures_added);
+ ClassDB::bind_method("_on_tileset_toolbar_confirm", &TileSetEditor::_on_tileset_toolbar_confirm);
+ ClassDB::bind_method("_on_texture_list_selected", &TileSetEditor::_on_texture_list_selected);
ClassDB::bind_method("_on_edit_mode_changed", &TileSetEditor::_on_edit_mode_changed);
+ ClassDB::bind_method("_on_workspace_mode_changed", &TileSetEditor::_on_workspace_mode_changed);
ClassDB::bind_method("_on_workspace_overlay_draw", &TileSetEditor::_on_workspace_overlay_draw);
+ ClassDB::bind_method("_on_workspace_process", &TileSetEditor::_on_workspace_process);
ClassDB::bind_method("_on_workspace_draw", &TileSetEditor::_on_workspace_draw);
ClassDB::bind_method("_on_workspace_input", &TileSetEditor::_on_workspace_input);
ClassDB::bind_method("_on_tool_clicked", &TileSetEditor::_on_tool_clicked);
ClassDB::bind_method("_on_priority_changed", &TileSetEditor::_on_priority_changed);
ClassDB::bind_method("_on_grid_snap_toggled", &TileSetEditor::_on_grid_snap_toggled);
- ClassDB::bind_method("_set_snap_step_x", &TileSetEditor::_set_snap_step_x);
- ClassDB::bind_method("_set_snap_step_y", &TileSetEditor::_set_snap_step_y);
- ClassDB::bind_method("_set_snap_off_x", &TileSetEditor::_set_snap_off_x);
- ClassDB::bind_method("_set_snap_off_y", &TileSetEditor::_set_snap_off_y);
- ClassDB::bind_method("_set_snap_sep_x", &TileSetEditor::_set_snap_sep_x);
- ClassDB::bind_method("_set_snap_sep_y", &TileSetEditor::_set_snap_sep_y);
+ ClassDB::bind_method("_set_snap_step", &TileSetEditor::_set_snap_step);
+ ClassDB::bind_method("_set_snap_off", &TileSetEditor::_set_snap_off);
+ ClassDB::bind_method("_set_snap_sep", &TileSetEditor::_set_snap_sep);
}
void TileSetEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
+
+ tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_icon(get_icon("ToolAddNode", "EditorIcons"));
+ tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_icon(get_icon("Remove", "EditorIcons"));
+ tileset_toolbar_tools->set_icon(get_icon("Tools", "EditorIcons"));
+
+ tool_workspacemode[WORKSPACE_EDIT]->set_icon(get_icon("Edit", "EditorIcons"));
+ tool_workspacemode[WORKSPACE_CREATE_SINGLE]->set_icon(get_icon("AddSingleTile", "EditorIcons"));
+ tool_workspacemode[WORKSPACE_CREATE_AUTOTILE]->set_icon(get_icon("AddAutotile", "EditorIcons"));
+ tool_workspacemode[WORKSPACE_CREATE_ATLAS]->set_icon(get_icon("AddAtlasTile", "EditorIcons"));
+
tools[TOOL_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons"));
tools[BITMASK_COPY]->set_icon(get_icon("Duplicate", "EditorIcons"));
tools[BITMASK_PASTE]->set_icon(get_icon("Override", "EditorIcons"));
@@ -266,91 +209,126 @@ void TileSetEditor::_notification(int p_what) {
tools[SHAPE_NEW_POLYGON]->set_icon(get_icon("CollisionPolygon2D", "EditorIcons"));
tools[SHAPE_DELETE]->set_icon(get_icon("Remove", "EditorIcons"));
tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_icon("Snap", "EditorIcons"));
- tools[SHAPE_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons"));
+ tools[TOOL_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons"));
tools[ZOOM_OUT]->set_icon(get_icon("ZoomLess", "EditorIcons"));
tools[ZOOM_1]->set_icon(get_icon("ZoomReset", "EditorIcons"));
tools[ZOOM_IN]->set_icon(get_icon("ZoomMore", "EditorIcons"));
+ tools[VISIBLE_INFO]->set_icon(get_icon("InformationSign", "EditorIcons"));
+
+ tool_editmode[EDITMODE_REGION]->set_icon(get_icon("RegionEdit", "EditorIcons"));
+ tool_editmode[EDITMODE_COLLISION]->set_icon(get_icon("StaticBody2D", "EditorIcons"));
+ tool_editmode[EDITMODE_OCCLUSION]->set_icon(get_icon("LightOccluder2D", "EditorIcons"));
+ tool_editmode[EDITMODE_NAVIGATION]->set_icon(get_icon("Navigation2D", "EditorIcons"));
+ tool_editmode[EDITMODE_BITMASK]->set_icon(get_icon("PackedDataContainer", "EditorIcons"));
+ tool_editmode[EDITMODE_PRIORITY]->set_icon(get_icon("MaterialPreviewLight1", "EditorIcons"));
+ tool_editmode[EDITMODE_ICON]->set_icon(get_icon("LargeTexture", "EditorIcons"));
}
}
-void TileSetEditor::_changed_callback(Object *p_changed, const char *p_prop) {
- if (p_prop == StringName("region")) {
- update_tile_list_icon();
- preview->set_region_rect(tileset->tile_get_region(get_current_tile()));
- } else if (p_prop == StringName("name")) {
- update_tile_list_icon();
- } else if (p_prop == StringName("texture") || p_prop == StringName("modulate") || p_prop == StringName("tile_mode")) {
- _on_tile_list_selected(get_current_tile());
- workspace->update();
- preview->set_texture(tileset->tile_get_texture(get_current_tile()));
- preview->set_modulate(tileset->tile_get_modulate(get_current_tile()));
- preview->set_region_rect(tileset->tile_get_region(get_current_tile()));
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE)
- property_editor->show();
- else
- property_editor->hide();
- texture_region_editor->_edit_region();
- update_tile_list_icon();
- } else if (p_prop == StringName("autotile")) {
- workspace->update();
- }
-}
+TileSetEditor::TileSetEditor(EditorNode *p_editor) {
-void TileSetEditor::initialize_bottom_editor() {
+ editor = p_editor;
+ set_name("Tile Set Bottom Editor");
- //Side Panel
- side_panel = memnew(Control);
- side_panel->set_name("Tile Set");
+ HSplitContainer *split = memnew(HSplitContainer);
+ split->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_MINSIZE, 10);
+ add_child(split);
- VSplitContainer *split = memnew(VSplitContainer);
- side_panel->add_child(split);
- split->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ VBoxContainer *left_container = memnew(VBoxContainer);
+ split->add_child(left_container);
- tile_list = memnew(ItemList);
- tile_list->set_v_size_flags(SIZE_EXPAND_FILL);
- tile_list->set_h_size_flags(SIZE_EXPAND_FILL);
- tile_list->set_custom_minimum_size(Size2(10, 200));
- tile_list->connect("item_selected", this, "_on_tile_list_selected");
- split->add_child(tile_list);
+ texture_list = memnew(ItemList);
+ left_container->add_child(texture_list);
+ texture_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ texture_list->set_custom_minimum_size(Size2(200, 0));
+ texture_list->connect("item_selected", this, "_on_texture_list_selected");
- property_editor = memnew(PropertyEditor);
- property_editor->set_v_size_flags(SIZE_EXPAND_FILL);
- property_editor->set_h_size_flags(SIZE_EXPAND_FILL);
- property_editor->set_custom_minimum_size(Size2(10, 70));
- split->add_child(property_editor);
+ HBoxContainer *tileset_toolbar_container = memnew(HBoxContainer);
+ left_container->add_child(tileset_toolbar_container);
- helper = memnew(TileSetEditorHelper(this));
- property_editor->call_deferred("edit", helper);
- helper->add_change_receptor(this);
+ tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE] = memnew(ToolButton);
+ Vector<Variant> p;
+ p.push_back((int)TOOL_TILESET_ADD_TEXTURE);
+ tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->connect("pressed", this, "_on_tileset_toolbar_button_pressed", p);
+ tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]);
+ tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_tooltip(TTR("Add Texture(s) to TileSet"));
+
+ tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE] = memnew(ToolButton);
+ p = Vector<Variant>();
+ p.push_back((int)TOOL_TILESET_REMOVE_TEXTURE);
+ tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->connect("pressed", this, "_on_tileset_toolbar_button_pressed", p);
+ tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]);
+ tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_tooltip(TTR("Remove current Texture from TileSet"));
+
+ Control *toolbar_separator = memnew(Control);
+ toolbar_separator->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ tileset_toolbar_container->add_child(toolbar_separator);
+
+ tileset_toolbar_tools = memnew(MenuButton);
+ tileset_toolbar_tools->set_text("Tools");
+ p = Vector<Variant>();
+ p.push_back((int)TOOL_TILESET_CREATE_SCENE);
+ tileset_toolbar_tools->get_popup()->add_item(TTR("Create from Scene"), TOOL_TILESET_CREATE_SCENE);
+ p = Vector<Variant>();
+ p.push_back((int)TOOL_TILESET_MERGE_SCENE);
+ tileset_toolbar_tools->get_popup()->add_item(TTR("Merge from Scene"), TOOL_TILESET_MERGE_SCENE);
- //Editor
- //Bottom Panel
- bottom_panel = memnew(Control);
- bottom_panel->set_name("Tile Set Bottom Editor");
+ tileset_toolbar_tools->get_popup()->connect("id_pressed", this, "_on_tileset_toolbar_button_pressed");
+ tileset_toolbar_container->add_child(tileset_toolbar_tools);
+
+ //---------------
+ VBoxContainer *right_container = memnew(VBoxContainer);
+ right_container->set_v_size_flags(SIZE_EXPAND_FILL);
+ split->add_child(right_container);
dragging_point = -1;
creating_shape = false;
snap_step = Vector2(32, 32);
+ snap_offset = WORKSPACE_MARGIN;
- bottom_panel->set_custom_minimum_size(Size2(0, 150));
+ set_custom_minimum_size(Size2(0, 150));
VBoxContainer *main_vb = memnew(VBoxContainer);
- bottom_panel->add_child(main_vb);
- main_vb->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ right_container->add_child(main_vb);
+ main_vb->set_v_size_flags(SIZE_EXPAND_FILL);
HBoxContainer *tool_hb = memnew(HBoxContainer);
Ref<ButtonGroup> g(memnew(ButtonGroup));
- String label[EDITMODE_MAX] = { "Collision", "Occlusion", "Navigation", "Bitmask", "Priority", "Icon" };
+ String workspace_label[WORKSPACE_MODE_MAX] = { "Edit", "New Single Tile", "New Autotile", "New Atlas" };
+
+ for (int i = 0; i < (int)WORKSPACE_MODE_MAX; i++) {
+ tool_workspacemode[i] = memnew(Button);
+ tool_workspacemode[i]->set_text(workspace_label[i]);
+ tool_workspacemode[i]->set_toggle_mode(true);
+ tool_workspacemode[i]->set_button_group(g);
+ Vector<Variant> p;
+ p.push_back(i);
+ tool_workspacemode[i]->connect("pressed", this, "_on_workspace_mode_changed", p);
+ tool_hb->add_child(tool_workspacemode[i]);
+ }
+ tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true);
+ workspace_mode = WORKSPACE_EDIT;
+
+ main_vb->add_child(tool_hb);
+ main_vb->add_child(memnew(HSeparator));
+
+ tool_hb = memnew(HBoxContainer);
+ Control *spacer = memnew(Control);
+ spacer->set_custom_minimum_size(Size2(30, 0));
+ tool_hb->add_child(spacer);
+
+ g = Ref<ButtonGroup>(memnew(ButtonGroup));
+ String label[EDITMODE_MAX] = { "Region", "Collision", "Occlusion", "Navigation", "Bitmask", "Priority", "Icon" };
for (int i = 0; i < (int)EDITMODE_MAX; i++) {
tool_editmode[i] = memnew(Button);
tool_editmode[i]->set_text(label[i]);
tool_editmode[i]->set_toggle_mode(true);
tool_editmode[i]->set_button_group(g);
- Vector<Variant> args;
- args.push_back(i);
- tool_editmode[i]->connect("pressed", this, "_on_edit_mode_changed", args);
+ Vector<Variant> p;
+ p.push_back(i);
+ tool_editmode[i]->connect("pressed", this, "_on_edit_mode_changed", p);
tool_hb->add_child(tool_editmode[i]);
}
tool_editmode[EDITMODE_COLLISION]->set_pressed(true);
@@ -360,127 +338,52 @@ void TileSetEditor::initialize_bottom_editor() {
main_vb->add_child(memnew(HSeparator));
toolbar = memnew(HBoxContainer);
- for (int i = 0; i < (int)TOOLBAR_MAX; i++) {
- tool_containers[i] = memnew(HBoxContainer);
- toolbar->add_child(tool_containers[i]);
- tool_containers[i]->hide();
- }
-
Ref<ButtonGroup> tg(memnew(ButtonGroup));
- Vector<Variant> p;
+ p = Vector<Variant>();
tools[TOOL_SELECT] = memnew(ToolButton);
- tool_containers[TOOLBAR_DUMMY]->add_child(tools[TOOL_SELECT]);
+ toolbar->add_child(tools[TOOL_SELECT]);
tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings."));
tools[TOOL_SELECT]->set_toggle_mode(true);
tools[TOOL_SELECT]->set_button_group(tg);
tools[TOOL_SELECT]->set_pressed(true);
p.push_back((int)TOOL_SELECT);
tools[TOOL_SELECT]->connect("pressed", this, "_on_tool_clicked", p);
- tool_containers[TOOLBAR_DUMMY]->show();
tools[BITMASK_COPY] = memnew(ToolButton);
p.push_back((int)BITMASK_COPY);
tools[BITMASK_COPY]->connect("pressed", this, "_on_tool_clicked", p);
- tool_containers[TOOLBAR_BITMASK]->add_child(tools[BITMASK_COPY]);
+ toolbar->add_child(tools[BITMASK_COPY]);
tools[BITMASK_PASTE] = memnew(ToolButton);
p = Vector<Variant>();
p.push_back((int)BITMASK_PASTE);
tools[BITMASK_PASTE]->connect("pressed", this, "_on_tool_clicked", p);
- tool_containers[TOOLBAR_BITMASK]->add_child(tools[BITMASK_PASTE]);
+ toolbar->add_child(tools[BITMASK_PASTE]);
tools[BITMASK_CLEAR] = memnew(ToolButton);
p = Vector<Variant>();
p.push_back((int)BITMASK_CLEAR);
tools[BITMASK_CLEAR]->connect("pressed", this, "_on_tool_clicked", p);
- tool_containers[TOOLBAR_BITMASK]->add_child(tools[BITMASK_CLEAR]);
+ toolbar->add_child(tools[BITMASK_CLEAR]);
tools[SHAPE_NEW_POLYGON] = memnew(ToolButton);
- tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_NEW_POLYGON]);
+ toolbar->add_child(tools[SHAPE_NEW_POLYGON]);
tools[SHAPE_NEW_POLYGON]->set_toggle_mode(true);
tools[SHAPE_NEW_POLYGON]->set_button_group(tg);
- tool_containers[TOOLBAR_SHAPE]->add_child(memnew(VSeparator));
+ toolbar->add_child(memnew(VSeparator));
tools[SHAPE_DELETE] = memnew(ToolButton);
p = Vector<Variant>();
p.push_back((int)SHAPE_DELETE);
tools[SHAPE_DELETE]->connect("pressed", this, "_on_tool_clicked", p);
- tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_DELETE]);
- tool_containers[TOOLBAR_SHAPE]->add_child(memnew(VSeparator));
+ toolbar->add_child(tools[SHAPE_DELETE]);
+ toolbar->add_child(memnew(VSeparator));
tools[SHAPE_KEEP_INSIDE_TILE] = memnew(ToolButton);
tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true);
tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true);
- tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_KEEP_INSIDE_TILE]);
- tools[SHAPE_GRID_SNAP] = memnew(ToolButton);
- tools[SHAPE_GRID_SNAP]->set_toggle_mode(true);
- tools[SHAPE_GRID_SNAP]->connect("toggled", this, "_on_grid_snap_toggled");
- tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_GRID_SNAP]);
-
- hb_grid = memnew(HBoxContainer);
- tool_containers[TOOLBAR_SHAPE]->add_child(hb_grid);
-
- hb_grid->add_child(memnew(VSeparator));
- hb_grid->add_child(memnew(Label(TTR("Offset:"))));
-
- sb_off_x = memnew(SpinBox);
- sb_off_x->set_min(-256);
- sb_off_x->set_max(256);
- sb_off_x->set_step(1);
- sb_off_x->set_value(snap_offset.x);
- sb_off_x->set_suffix("px");
- sb_off_x->connect("value_changed", this, "_set_snap_off_x");
- hb_grid->add_child(sb_off_x);
-
- sb_off_y = memnew(SpinBox);
- sb_off_y->set_min(-256);
- sb_off_y->set_max(256);
- sb_off_y->set_step(1);
- sb_off_y->set_value(snap_offset.y);
- sb_off_y->set_suffix("px");
- sb_off_y->connect("value_changed", this, "_set_snap_off_y");
- hb_grid->add_child(sb_off_y);
-
- hb_grid->add_child(memnew(VSeparator));
- hb_grid->add_child(memnew(Label(TTR("Step:"))));
-
- sb_step_x = memnew(SpinBox);
- sb_step_x->set_min(-256);
- sb_step_x->set_max(256);
- sb_step_x->set_step(1);
- sb_step_x->set_value(snap_step.x);
- sb_step_x->set_suffix("px");
- sb_step_x->connect("value_changed", this, "_set_snap_step_x");
- hb_grid->add_child(sb_step_x);
-
- sb_step_y = memnew(SpinBox);
- sb_step_y->set_min(-256);
- sb_step_y->set_max(256);
- sb_step_y->set_step(1);
- sb_step_y->set_value(snap_step.y);
- sb_step_y->set_suffix("px");
- sb_step_y->connect("value_changed", this, "_set_snap_step_y");
- hb_grid->add_child(sb_step_y);
-
- hb_grid->add_child(memnew(VSeparator));
- hb_grid->add_child(memnew(Label(TTR("Separation:"))));
-
- sb_sep_x = memnew(SpinBox);
- sb_sep_x->set_min(0);
- sb_sep_x->set_max(256);
- sb_sep_x->set_step(1);
- sb_sep_x->set_value(snap_separation.x);
- sb_sep_x->set_suffix("px");
- sb_sep_x->connect("value_changed", this, "_set_snap_sep_x");
- hb_grid->add_child(sb_sep_x);
-
- sb_sep_y = memnew(SpinBox);
- sb_sep_y->set_min(0);
- sb_sep_y->set_max(256);
- sb_sep_y->set_step(1);
- sb_sep_y->set_value(snap_separation.y);
- sb_sep_y->set_suffix("px");
- sb_sep_y->connect("value_changed", this, "_set_snap_sep_y");
- hb_grid->add_child(sb_sep_y);
-
- hb_grid->hide();
+ toolbar->add_child(tools[SHAPE_KEEP_INSIDE_TILE]);
+ tools[TOOL_GRID_SNAP] = memnew(ToolButton);
+ tools[TOOL_GRID_SNAP]->set_toggle_mode(true);
+ tools[TOOL_GRID_SNAP]->connect("toggled", this, "_on_grid_snap_toggled");
+ toolbar->add_child(tools[TOOL_GRID_SNAP]);
spin_priority = memnew(SpinBox);
spin_priority->set_min(1);
@@ -491,8 +394,6 @@ void TileSetEditor::initialize_bottom_editor() {
spin_priority->hide();
toolbar->add_child(spin_priority);
- tool_containers[TOOLBAR_SHAPE]->show();
-
Control *separator = memnew(Control);
separator->set_h_size_flags(SIZE_EXPAND_FILL);
toolbar->add_child(separator);
@@ -502,22 +403,31 @@ void TileSetEditor::initialize_bottom_editor() {
p.push_back((int)ZOOM_OUT);
tools[ZOOM_OUT]->connect("pressed", this, "_on_tool_clicked", p);
toolbar->add_child(tools[ZOOM_OUT]);
+ tools[ZOOM_OUT]->set_tooltip(TTR("Zoom Out"));
tools[ZOOM_1] = memnew(ToolButton);
p = Vector<Variant>();
p.push_back((int)ZOOM_1);
tools[ZOOM_1]->connect("pressed", this, "_on_tool_clicked", p);
toolbar->add_child(tools[ZOOM_1]);
+ tools[ZOOM_1]->set_tooltip(TTR("Reset Zoom"));
tools[ZOOM_IN] = memnew(ToolButton);
p = Vector<Variant>();
p.push_back((int)ZOOM_IN);
tools[ZOOM_IN]->connect("pressed", this, "_on_tool_clicked", p);
toolbar->add_child(tools[ZOOM_IN]);
+ tools[ZOOM_IN]->set_tooltip(TTR("Zoom In"));
+
+ tools[VISIBLE_INFO] = memnew(ToolButton);
+ tools[VISIBLE_INFO]->set_toggle_mode(true);
+ tools[VISIBLE_INFO]->set_tooltip(TTR("Display tile's names (hold Alt Key)"));
+ toolbar->add_child(tools[VISIBLE_INFO]);
main_vb->add_child(toolbar);
scroll = memnew(ScrollContainer);
main_vb->add_child(scroll);
scroll->set_v_size_flags(SIZE_EXPAND_FILL);
+ scroll->set_clip_contents(true);
workspace_container = memnew(Control);
scroll->add_child(workspace_container);
@@ -527,6 +437,7 @@ void TileSetEditor::initialize_bottom_editor() {
workspace_container->add_child(workspace_overlay);
workspace = memnew(Control);
+ workspace->set_focus_mode(FOCUS_ALL);
workspace->connect("draw", this, "_on_workspace_draw");
workspace->connect("gui_input", this, "_on_workspace_input");
workspace->set_draw_behind_parent(true);
@@ -536,39 +447,35 @@ void TileSetEditor::initialize_bottom_editor() {
workspace->add_child(preview);
preview->set_centered(false);
preview->set_draw_behind_parent(true);
- preview->set_region(true);
-}
+ preview->set_position(WORKSPACE_MARGIN);
-TileSetEditor::TileSetEditor(EditorNode *p_editor) {
-
- menu = memnew(MenuButton);
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(menu);
- menu->hide();
- menu->set_text(TTR("Tile Set"));
- menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM);
- menu->get_popup()->add_item(TTR("Remove Item"), MENU_OPTION_REMOVE_ITEM);
- menu->get_popup()->add_separator();
- menu->get_popup()->add_item(TTR("Create from Scene"), MENU_OPTION_CREATE_FROM_SCENE);
- menu->get_popup()->add_item(TTR("Merge from Scene"), MENU_OPTION_MERGE_FROM_SCENE);
- menu->get_popup()->connect("id_pressed", this, "_menu_cbk");
- editor = p_editor;
+ //---------------
cd = memnew(ConfirmationDialog);
add_child(cd);
- cd->get_ok()->connect("pressed", this, "_menu_confirm");
-
- nd = memnew(EditorNameDialog);
- add_child(nd);
- nd->set_hide_on_ok(true);
- nd->get_line_edit()->set_margin(MARGIN_TOP, 28);
- nd->connect("name_confirmed", this, "_name_dialog_confirm");
+ cd->connect("confirmed", this, "_on_tileset_toolbar_confirm");
+ //---------------
err_dialog = memnew(AcceptDialog);
add_child(err_dialog);
- err_dialog->set_title(TTR("Error"));
- draw_handles = false;
+ //---------------
+ texture_dialog = memnew(EditorFileDialog);
+ texture_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES);
+ texture_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILES);
+ texture_dialog->clear_filters();
+ List<String> extensions;
+
+ ResourceLoader::get_recognized_extensions_for_type("Texture", &extensions);
+ for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
- initialize_bottom_editor();
+ texture_dialog->add_filter("*." + E->get() + " ; " + E->get().to_upper());
+ }
+ add_child(texture_dialog);
+ texture_dialog->connect("files_selected", this, "_on_textures_added");
+
+ //---------------
+ helper = memnew(TilesetEditorContext(this));
+ tile_names_opacity = 0;
}
TileSetEditor::~TileSetEditor() {
@@ -576,57 +483,166 @@ TileSetEditor::~TileSetEditor() {
memdelete(helper);
}
-void TileSetEditor::_on_tile_list_selected(int p_index) {
- if (get_current_tile() >= 0) {
+void TileSetEditor::_on_tileset_toolbar_button_pressed(int p_index) {
+ option = p_index;
+ switch (option) {
+ case TOOL_TILESET_ADD_TEXTURE: {
+ texture_dialog->popup_centered_ratio();
+ } break;
+ case TOOL_TILESET_REMOVE_TEXTURE: {
+ if (get_current_texture().is_valid()) {
+ cd->set_text(TTR("Remove Selected Textue and ALL TILES wich uses it?"));
+ cd->popup_centered(Size2(300, 60));
+ } else {
+ err_dialog->set_text(TTR("You haven't selected a texture to remove."));
+ err_dialog->popup_centered(Size2(300, 60));
+ }
+ } break;
+ case TOOL_TILESET_CREATE_SCENE: {
+
+ cd->set_text(TTR("Create from scene?"));
+ cd->popup_centered(Size2(300, 60));
+ } break;
+ case TOOL_TILESET_MERGE_SCENE: {
+
+ cd->set_text(TTR("Merge from scene?"));
+ cd->popup_centered(Size2(300, 60));
+ } break;
+ }
+}
+
+void TileSetEditor::_on_tileset_toolbar_confirm() {
+ switch (option) {
+ case TOOL_TILESET_REMOVE_TEXTURE: {
+ RID current_rid = get_current_texture()->get_rid();
+ List<int> ids;
+ tileset->get_tile_list(&ids);
+ for (List<int>::Element *E = ids.front(); E; E = E->next()) {
+ if (tileset->tile_get_texture(E->get())->get_rid() == current_rid) {
+ tileset->remove_tile(E->get());
+ }
+ }
+ texture_list->remove_item(texture_list->find_metadata(current_rid));
+ texture_map.erase(current_rid);
+ _on_texture_list_selected(-1);
+ } break;
+ case TOOL_TILESET_MERGE_SCENE:
+ case TOOL_TILESET_CREATE_SCENE: {
+
+ EditorNode *en = editor;
+ Node *scene = en->get_edited_scene();
+ if (!scene)
+ break;
+ _import_scene(scene, tileset, option == TOOL_TILESET_MERGE_SCENE);
+
+ edit(tileset);
+ } break;
+ }
+}
+
+void TileSetEditor::_on_texture_list_selected(int p_index) {
+ if (get_current_texture().is_valid()) {
current_item_index = p_index;
- preview->set_texture(tileset->tile_get_texture(get_current_tile()));
- preview->set_modulate(tileset->tile_get_modulate(get_current_tile()));
- preview->set_region_rect(tileset->tile_get_region(get_current_tile()));
- workspace->set_custom_minimum_size(tileset->tile_get_region(get_current_tile()).size);
+ preview->set_texture(get_current_texture());
+ workspace->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2);
+ workspace_container->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2);
+ workspace_overlay->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2);
update_workspace_tile_mode();
} else {
current_item_index = -1;
preview->set_texture(NULL);
workspace->set_custom_minimum_size(Size2i());
+ update_workspace_tile_mode();
}
- texture_region_editor->selected_tile = get_current_tile();
- texture_region_editor->_edit_region();
- helper->selected_tile = get_current_tile();
- helper->_change_notify("");
+ set_current_tile(-1);
workspace->update();
}
+void TileSetEditor::_on_textures_added(const PoolStringArray &p_paths) {
+ int invalid_count = 0;
+ for (int i = 0; i < p_paths.size(); i++) {
+ Ref<Texture> t = Ref<Texture>(ResourceLoader::load(p_paths[i]));
+ if (texture_map.has(t->get_rid())) {
+ invalid_count++;
+ } else {
+ texture_list->add_item(t->get_path().get_file());
+ texture_map.insert(t->get_rid(), t);
+ texture_list->set_item_metadata(texture_list->get_item_count() - 1, t->get_rid());
+ }
+ }
+ update_texture_list_icon();
+ texture_list->select(texture_list->get_item_count() - 1);
+ _on_texture_list_selected(texture_list->get_item_count() - 1);
+ if (invalid_count > 0) {
+ err_dialog->set_text(String::num(invalid_count, 0) + TTR(" file(s) was not added because was already on the list."));
+ err_dialog->popup_centered(Size2(300, 60));
+ }
+}
+
void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) {
edit_mode = (EditMode)p_edit_mode;
switch (edit_mode) {
+ case EDITMODE_REGION: {
+ tools[TOOL_SELECT]->show();
+ tools[BITMASK_COPY]->hide();
+ tools[BITMASK_PASTE]->hide();
+ tools[BITMASK_CLEAR]->hide();
+ tools[SHAPE_NEW_POLYGON]->hide();
+ if (workspace_mode == WORKSPACE_EDIT)
+ tools[SHAPE_DELETE]->show();
+ else
+ tools[SHAPE_DELETE]->hide();
+ tools[SHAPE_KEEP_INSIDE_TILE]->hide();
+ tools[TOOL_GRID_SNAP]->show();
+
+ tools[TOOL_SELECT]->set_pressed(true);
+ tools[TOOL_SELECT]->set_tooltip(TTR("Drag handles to edit Rect.\nClick on another Tile to edit it."));
+ spin_priority->hide();
+ } break;
case EDITMODE_BITMASK: {
- tool_containers[TOOLBAR_DUMMY]->show();
- tool_containers[TOOLBAR_BITMASK]->show();
- tool_containers[TOOLBAR_SHAPE]->hide();
+ tools[TOOL_SELECT]->show();
+ tools[BITMASK_COPY]->show();
+ tools[BITMASK_PASTE]->show();
+ tools[BITMASK_CLEAR]->show();
+ tools[SHAPE_NEW_POLYGON]->hide();
+ tools[SHAPE_DELETE]->hide();
+ tools[SHAPE_KEEP_INSIDE_TILE]->hide();
+ tools[TOOL_GRID_SNAP]->hide();
+
tools[TOOL_SELECT]->set_pressed(true);
- tools[TOOL_SELECT]->set_tooltip(TTR("LMB: set bit on.\nRMB: set bit off."));
+ tools[TOOL_SELECT]->set_tooltip(TTR("LMB: set bit on.\nRMB: set bit off.\nClick on another Tile to edit it."));
spin_priority->hide();
} break;
case EDITMODE_COLLISION:
case EDITMODE_NAVIGATION:
case EDITMODE_OCCLUSION: {
- tool_containers[TOOLBAR_DUMMY]->show();
- tool_containers[TOOLBAR_BITMASK]->hide();
- tool_containers[TOOLBAR_SHAPE]->show();
- tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile."));
+ tools[TOOL_SELECT]->show();
+ tools[BITMASK_COPY]->hide();
+ tools[BITMASK_PASTE]->hide();
+ tools[BITMASK_CLEAR]->hide();
+ tools[SHAPE_NEW_POLYGON]->show();
+ tools[SHAPE_DELETE]->show();
+ tools[SHAPE_KEEP_INSIDE_TILE]->show();
+ tools[TOOL_GRID_SNAP]->show();
+
+ tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile.\nClick on another Tile to edit it."));
spin_priority->hide();
-
select_coord(edited_shape_coord);
} break;
default: {
- tool_containers[TOOLBAR_DUMMY]->show();
- tool_containers[TOOLBAR_BITMASK]->hide();
- tool_containers[TOOLBAR_SHAPE]->hide();
+ tools[TOOL_SELECT]->show();
+ tools[BITMASK_COPY]->hide();
+ tools[BITMASK_PASTE]->hide();
+ tools[BITMASK_CLEAR]->hide();
+ tools[SHAPE_NEW_POLYGON]->hide();
+ tools[SHAPE_DELETE]->hide();
+ tools[SHAPE_KEEP_INSIDE_TILE]->hide();
+ tools[TOOL_GRID_SNAP]->show();
if (edit_mode == EDITMODE_ICON) {
- tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings."));
+ tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.\nClick on another Tile to edit it."));
spin_priority->hide();
} else {
- tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change its priority."));
+ tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change its priority.\nClick on another Tile to edit it."));
spin_priority->show();
}
} break;
@@ -634,25 +650,52 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) {
workspace->update();
}
+void TileSetEditor::_on_workspace_mode_changed(int p_workspace_mode) {
+ workspace_mode = (WorkspaceMode)p_workspace_mode;
+ if (p_workspace_mode == WORKSPACE_EDIT) {
+ update_workspace_tile_mode();
+ } else {
+ for (int i = 0; i < EDITMODE_MAX; i++) {
+ tool_editmode[i]->hide();
+ }
+ tool_editmode[EDITMODE_REGION]->show();
+ tool_editmode[EDITMODE_REGION]->set_pressed(true);
+ _on_edit_mode_changed(EDITMODE_REGION);
+ }
+}
+
void TileSetEditor::_on_workspace_draw() {
- if (get_current_tile() >= 0 && !tileset.is_null()) {
+ const Color COLOR_AUTOTILE = Color(0.266373, 0.565288, 0.988281);
+ const Color COLOR_SINGLE = Color(0.988281, 0.909323, 0.266373);
+ const Color COLOR_ATLAS = Color(0.78653, 0.812835, 0.832031);
+
+ if (tileset.is_null())
+ return;
+ if (!get_current_texture().is_valid())
+ return;
+
+ draw_highlight_current_tile();
+
+ draw_grid_snap();
+ if (get_current_tile() >= 0) {
int spacing = tileset->autotile_get_spacing(get_current_tile());
Vector2 size = tileset->autotile_get_size(get_current_tile());
Rect2i region = tileset->tile_get_region(get_current_tile());
- Color c(0.347214, 0.722656, 0.617063);
switch (edit_mode) {
case EDITMODE_ICON: {
Vector2 coord = tileset->autotile_get_icon_coordinate(get_current_tile());
- draw_highlight_tile(coord);
+ draw_highlight_subtile(coord);
} break;
case EDITMODE_BITMASK: {
- c = Color(1, 0, 0, 0.5);
+ Color c(1, 0, 0, 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);
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
if (mask & TileSet::BIND_TOPLEFT) {
@@ -702,9 +745,9 @@ void TileSetEditor::_on_workspace_draw() {
case EDITMODE_COLLISION:
case EDITMODE_OCCLUSION:
case EDITMODE_NAVIGATION: {
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) {
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
Vector2 coord = edited_shape_coord;
- draw_highlight_tile(coord);
+ draw_highlight_subtile(coord);
}
draw_polygon_shapes();
draw_grid_snap();
@@ -723,89 +766,334 @@ void TileSetEditor::_on_workspace_draw() {
}
}
spin_priority->set_suffix(" / " + String::num(total, 0));
- draw_highlight_tile(edited_shape_coord, queue_others);
+ draw_highlight_subtile(edited_shape_coord, queue_others);
} break;
}
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) {
- float j = -size.x; //make sure to draw at 0
- while (j < region.size.x) {
- j += size.x;
- if (spacing <= 0) {
- workspace->draw_line(Point2(j, 0), Point2(j, region.size.y), c);
- } else {
- workspace->draw_rect(Rect2(Point2(j, 0), Size2(spacing, region.size.y)), c);
- }
- j += spacing;
- }
- j = -size.y; //make sure to draw at 0
- while (j < region.size.y) {
- j += size.y;
- if (spacing <= 0) {
- workspace->draw_line(Point2(0, j), Point2(region.size.x, j), c);
- } else {
- workspace->draw_rect(Rect2(Point2(0, j), Size2(region.size.x, spacing)), c);
- }
- j += spacing;
+ draw_tile_subdivision(get_current_tile(), Color(0.347214, 0.722656, 0.617063));
+ }
+
+ RID current_texture_rid = get_current_texture()->get_rid();
+ List<int> *tiles = new List<int>();
+ tileset->get_tile_list(tiles);
+ for (List<int>::Element *E = tiles->front(); E; E = E->next()) {
+ int t_id = E->get();
+ if (tileset->tile_get_texture(t_id)->get_rid() == current_texture_rid && (t_id != get_current_tile() || edit_mode != EDITMODE_REGION)) {
+ Rect2i region = tileset->tile_get_region(t_id);
+ region.position += WORKSPACE_MARGIN;
+ Color c;
+ if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE)
+ c = COLOR_SINGLE;
+ else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE)
+ c = COLOR_AUTOTILE;
+ else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE)
+ c = COLOR_ATLAS;
+ draw_tile_subdivision(t_id, Color(0.347214, 0.722656, 0.617063, 0.5));
+ workspace->draw_rect(region, c, false);
+ }
+ }
+ if (edit_mode == EDITMODE_REGION) {
+ if (workspace_mode != WORKSPACE_EDIT) {
+ Rect2i region = edited_region;
+ Color c;
+ if (workspace_mode == WORKSPACE_CREATE_SINGLE)
+ c = COLOR_SINGLE;
+ else if (workspace_mode == WORKSPACE_CREATE_AUTOTILE)
+ c = COLOR_AUTOTILE;
+ else if (workspace_mode == WORKSPACE_CREATE_ATLAS)
+ c = COLOR_ATLAS;
+ workspace->draw_rect(region, c, false);
+ draw_edited_region_subdivision();
+ } else {
+ int t_id = get_current_tile();
+ Rect2i region;
+ if (draw_edited_region)
+ region = edited_region;
+ else {
+ region = tileset->tile_get_region(t_id);
+ region.position += WORKSPACE_MARGIN;
}
+ Color c;
+ if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE)
+ c = COLOR_SINGLE;
+ else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE)
+ c = COLOR_AUTOTILE;
+ else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE)
+ c = COLOR_ATLAS;
+ if (draw_edited_region)
+ draw_edited_region_subdivision();
+ else
+ draw_tile_subdivision(t_id, Color(0.347214, 0.722656, 0.617063, 1));
+ workspace->draw_rect(region, c, false);
}
}
workspace_overlay->update();
}
+void TileSetEditor::_on_workspace_process() {
+ float a = tile_names_opacity;
+ if (Input::get_singleton()->is_key_pressed(KEY_ALT) || tools[VISIBLE_INFO]->is_pressed()) {
+ a += get_tree()->get_idle_process_time() * 2;
+ } else {
+ a -= get_tree()->get_idle_process_time() * 2;
+ }
+
+ a = CLAMP(a, 0, 1);
+ if (a != tile_names_opacity)
+ workspace_overlay->update();
+ tile_names_opacity = a;
+}
+
void TileSetEditor::_on_workspace_overlay_draw() {
+ if (!tileset.is_valid())
+ return;
+ if (!get_current_texture().is_valid())
+ return;
+
+ const Color COLOR_AUTOTILE = Color(0.266373, 0.565288, 0.988281);
+ const Color COLOR_SINGLE = Color(0.988281, 0.909323, 0.266373);
+ const Color COLOR_ATLAS = Color(0.78653, 0.812835, 0.832031);
+
+ if (tile_names_opacity > 0) {
+ RID current_texture_rid = get_current_texture()->get_rid();
+ List<int> *tiles = new List<int>();
+ tileset->get_tile_list(tiles);
+ for (List<int>::Element *E = tiles->front(); E; E = E->next()) {
+ int t_id = E->get();
+ if (tileset->tile_get_texture(t_id)->get_rid() == current_texture_rid) {
+ Rect2i region = tileset->tile_get_region(t_id);
+ region.position += WORKSPACE_MARGIN;
+ region.position *= workspace->get_scale().x;
+ Color c;
+ if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE)
+ c = COLOR_SINGLE;
+ else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE)
+ c = COLOR_AUTOTILE;
+ else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE)
+ c = COLOR_ATLAS;
+ c.a = tile_names_opacity;
+ Ref<Font> font = get_font("font", "Label");
+ region.set_size(font->get_string_size(tileset->tile_get_name(t_id)));
+ workspace_overlay->draw_rect(region, c);
+ region.position.y += region.size.y - 2;
+ c = Color(0.1, 0.1, 0.1, tile_names_opacity);
+ workspace_overlay->draw_string(font, region.position, tileset->tile_get_name(t_id), c);
+ }
+ }
+ }
+
int t_id = get_current_tile();
- if (t_id < 0 || !draw_handles)
+ if (t_id < 0)
return;
Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons");
-
- for (int i = 0; i < current_shape.size(); i++) {
- workspace_overlay->draw_texture(handle, current_shape[i] * workspace->get_scale().x - handle->get_size() * 0.5);
+ if (draw_handles) {
+ for (int i = 0; i < current_shape.size(); i++) {
+ workspace_overlay->draw_texture(handle, current_shape[i] * workspace->get_scale().x - handle->get_size() * 0.5);
+ }
}
}
#define MIN_DISTANCE_SQUARED 6
void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
+ if (tileset.is_null())
+ return;
+ if (!get_current_texture().is_valid())
+ return;
- if (get_current_tile() >= 0 && !tileset.is_null()) {
- Ref<InputEventMouseButton> mb = p_ie;
- Ref<InputEventMouseMotion> mm = p_ie;
+ static bool dragging;
+ static bool erasing;
+ draw_edited_region = false;
- static bool dragging;
- static bool erasing;
+ Rect2 current_tile_region = Rect2();
+ if (get_current_tile() >= 0) {
+ current_tile_region = tileset->tile_get_region(get_current_tile());
+ }
+ current_tile_region.position += WORKSPACE_MARGIN;
+
+ Ref<InputEventMouseButton> mb = p_ie;
+ Ref<InputEventMouseMotion> mm = p_ie;
+
+ if (mb.is_valid()) {
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (!current_tile_region.has_point(mb->get_position())) {
+ List<int> *tiles = new List<int>();
+ tileset->get_tile_list(tiles);
+ for (List<int>::Element *E = tiles->front(); E; E = E->next()) {
+ int t_id = E->get();
+ if (get_current_texture()->get_rid() == tileset->tile_get_texture(t_id)->get_rid()) {
+ Rect2 r = tileset->tile_get_region(t_id);
+ r.position += WORKSPACE_MARGIN;
+ if (r.has_point(mb->get_position())) {
+ set_current_tile(t_id);
+ workspace->update();
+ workspace_overlay->update();
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ // Drag Middle Mouse
+ if (mm.is_valid()) {
+ if (mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ Vector2 dragged(mm->get_relative().x, mm->get_relative().y);
+ scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x);
+ scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x);
+ }
+ }
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Vector2 size = tileset->autotile_get_size(get_current_tile());
- switch (edit_mode) {
- case EDITMODE_ICON: {
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
- Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y)));
- tileset->autotile_set_icon_coordinate(get_current_tile(), coord);
- Rect2 region = tileset->tile_get_region(get_current_tile());
- region.size = size;
- coord.x *= (spacing + size.x);
- coord.y *= (spacing + size.y);
- region.position += coord;
- tile_list->set_item_icon_region(current_item_index, region);
- workspace->update();
+ if (edit_mode == EDITMODE_REGION) {
+ if (mb.is_valid()) {
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (get_current_tile() >= 0 || workspace_mode != WORKSPACE_EDIT) {
+ dragging = true;
+ region_from = mb->get_position();
+ edited_region = Rect2(region_from, Size2());
+ workspace->update();
+ workspace_overlay->update();
+ return;
+ }
+ } else if (dragging && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ dragging = false;
+ edited_region = Rect2();
+ workspace->update();
+ workspace_overlay->update();
+ return;
+ } else if (dragging && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ dragging = false;
+ update_edited_region(mb->get_position());
+ edited_region.position -= WORKSPACE_MARGIN;
+ if (!edited_region.has_no_area()) {
+ if (get_current_tile() >= 0 && workspace_mode == WORKSPACE_EDIT) {
+ tileset->tile_set_region(get_current_tile(), edited_region);
+ } else {
+ int t_id = tileset->get_last_unused_tile_id();
+ tileset->create_tile(t_id);
+ tileset->tile_set_texture(t_id, get_current_texture());
+ tileset->tile_set_region(t_id, edited_region);
+ tileset->tile_set_name(t_id, get_current_texture()->get_path().get_file() + " " + String::num(t_id, 0));
+ if (workspace_mode != WORKSPACE_CREATE_SINGLE) {
+ tileset->autotile_set_size(t_id, snap_step);
+ tileset->autotile_set_spacing(t_id, snap_separation.x);
+ tileset->tile_set_tile_mode(t_id, workspace_mode == WORKSPACE_CREATE_AUTOTILE ? TileSet::AUTO_TILE : TileSet::ATLAS_TILE);
+ }
+ set_current_tile(t_id);
+ tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true);
+ _on_workspace_mode_changed(WORKSPACE_EDIT);
}
}
- } break;
- case EDITMODE_BITMASK: {
- if (mb.is_valid()) {
- if (mb->is_pressed()) {
- if (dragging) {
- return;
+ workspace->update();
+ workspace_overlay->update();
+ return;
+ }
+ } else if (mm.is_valid()) {
+ if (dragging) {
+ update_edited_region(mm->get_position());
+ draw_edited_region = true;
+ workspace->update();
+ workspace_overlay->update();
+ return;
+ }
+ }
+ }
+ if (workspace_mode == WORKSPACE_EDIT) {
+
+ if (get_current_tile() >= 0) {
+ int spacing = tileset->autotile_get_spacing(get_current_tile());
+ Vector2 size = tileset->autotile_get_size(get_current_tile());
+ switch (edit_mode) {
+ case EDITMODE_ICON: {
+ if (mb.is_valid()) {
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && current_tile_region.has_point(mb->get_position())) {
+ 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)));
+ tileset->autotile_set_icon_coordinate(get_current_tile(), coord);
+ Rect2 region = tileset->tile_get_region(get_current_tile());
+ region.size = size;
+ coord.x *= (spacing + size.x);
+ coord.y *= (spacing + size.y);
+ region.position += coord;
+ workspace->update();
+ }
+ }
+ } break;
+ case EDITMODE_BITMASK: {
+ if (mb.is_valid()) {
+ if (mb->is_pressed()) {
+ if (dragging) {
+ return;
+ }
+ 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);
+ 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;
+ if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
+ if (pos.x < size.x / 2) {
+ if (pos.y < size.y / 2) {
+ bit = TileSet::BIND_TOPLEFT;
+ } else {
+ bit = TileSet::BIND_BOTTOMLEFT;
+ }
+ } else {
+ if (pos.y < size.y / 2) {
+ bit = TileSet::BIND_TOPRIGHT;
+ } else {
+ bit = TileSet::BIND_BOTTOMRIGHT;
+ }
+ }
+ } else {
+ if (pos.x < size.x / 3) {
+ if (pos.y < size.y / 3) {
+ bit = TileSet::BIND_TOPLEFT;
+ } else if (pos.y > (size.y / 3) * 2) {
+ bit = TileSet::BIND_BOTTOMLEFT;
+ } else {
+ bit = TileSet::BIND_LEFT;
+ }
+ } else if (pos.x > (size.x / 3) * 2) {
+ if (pos.y < size.y / 3) {
+ bit = TileSet::BIND_TOPRIGHT;
+ } else if (pos.y > (size.y / 3) * 2) {
+ bit = TileSet::BIND_BOTTOMRIGHT;
+ } else {
+ bit = TileSet::BIND_RIGHT;
+ }
+ } else {
+ if (pos.y < size.y / 3) {
+ bit = TileSet::BIND_TOP;
+ } else if (pos.y > (size.y / 3) * 2) {
+ bit = TileSet::BIND_BOTTOM;
+ } else {
+ bit = TileSet::BIND_CENTER;
+ }
+ }
+ }
+ uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
+ if (erasing) {
+ mask &= ~bit;
+ } else {
+ mask |= bit;
+ }
+ tileset->autotile_set_bitmask(get_current_tile(), coord, mask);
+ workspace->update();
+ }
+ } else {
+ if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) {
+ dragging = false;
+ erasing = false;
+ }
}
- if (mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) {
- dragging = true;
- erasing = (mb->get_button_index() == BUTTON_RIGHT);
- Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y)));
+ }
+ if (mm.is_valid()) {
+ if (dragging && current_tile_region.has_point(mm->get_position())) {
+ 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 = mb->get_position() - pos;
+ pos = mm->get_position() - (pos + current_tile_region.position);
uint16_t bit = 0;
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
if (pos.x < size.x / 2) {
@@ -857,269 +1145,198 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
tileset->autotile_set_bitmask(get_current_tile(), coord, mask);
workspace->update();
}
- } else {
- if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) {
- dragging = false;
- erasing = false;
- }
}
- }
- if (mm.is_valid()) {
- if (dragging) {
- Vector2 coord((int)(mm->get_position().x / (spacing + size.x)), (int)(mm->get_position().y / (spacing + size.y)));
- Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
- pos = mm->get_position() - pos;
- uint16_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) {
- bit = TileSet::BIND_TOPLEFT;
- } else {
- bit = TileSet::BIND_BOTTOMLEFT;
- }
- } else {
- if (pos.y < size.y / 2) {
- bit = TileSet::BIND_TOPRIGHT;
- } else {
- bit = TileSet::BIND_BOTTOMRIGHT;
- }
- }
- } else {
- if (pos.x < size.x / 3) {
- if (pos.y < size.y / 3) {
- bit = TileSet::BIND_TOPLEFT;
- } else if (pos.y > (size.y / 3) * 2) {
- bit = TileSet::BIND_BOTTOMLEFT;
- } else {
- bit = TileSet::BIND_LEFT;
- }
- } else if (pos.x > (size.x / 3) * 2) {
- if (pos.y < size.y / 3) {
- bit = TileSet::BIND_TOPRIGHT;
- } else if (pos.y > (size.y / 3) * 2) {
- bit = TileSet::BIND_BOTTOMRIGHT;
- } else {
- bit = TileSet::BIND_RIGHT;
- }
- } else {
- if (pos.y < size.y / 3) {
- bit = TileSet::BIND_TOP;
- } else if (pos.y > (size.y / 3) * 2) {
- bit = TileSet::BIND_BOTTOM;
- } else {
- bit = TileSet::BIND_CENTER;
- }
- }
- }
- uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
- if (erasing) {
- mask &= ~bit;
- } else {
- mask |= bit;
- }
- tileset->autotile_set_bitmask(get_current_tile(), coord, mask);
- workspace->update();
+ } break;
+ case EDITMODE_COLLISION:
+ case EDITMODE_OCCLUSION:
+ case EDITMODE_NAVIGATION:
+ case EDITMODE_PRIORITY: {
+ Vector2 shape_anchor = Vector2(0, 0);
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
+ shape_anchor = edited_shape_coord;
+ shape_anchor.x *= (size.x + spacing);
+ shape_anchor.y *= (size.y + spacing);
}
- }
- } break;
- case EDITMODE_COLLISION:
- case EDITMODE_OCCLUSION:
- case EDITMODE_NAVIGATION:
- case EDITMODE_PRIORITY: {
- Vector2 shape_anchor = Vector2(0, 0);
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) {
- shape_anchor = edited_shape_coord;
- shape_anchor.x *= (size.x + spacing);
- shape_anchor.y *= (size.y + spacing);
- }
- if (tools[TOOL_SELECT]->is_pressed()) {
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
- if (edit_mode != EDITMODE_PRIORITY && current_shape.size() > 0) {
- for (int i = 0; i < current_shape.size(); i++) {
- if ((current_shape[i] - mb->get_position()).length_squared() <= MIN_DISTANCE_SQUARED) {
- dragging_point = i;
- workspace->update();
- return;
+ shape_anchor += current_tile_region.position;
+ if (tools[TOOL_SELECT]->is_pressed()) {
+ if (mb.is_valid()) {
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (edit_mode != EDITMODE_PRIORITY && current_shape.size() > 0) {
+ for (int i = 0; i < current_shape.size(); i++) {
+ if ((current_shape[i] - mb->get_position()).length_squared() <= MIN_DISTANCE_SQUARED) {
+ dragging_point = i;
+ workspace->update();
+ return;
+ }
}
}
- }
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) {
- Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y)));
- if (edited_shape_coord != coord) {
- edited_shape_coord = coord;
- edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord);
- edited_navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord);
- Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile());
- bool found_collision_shape = false;
- for (int i = 0; i < sd.size(); i++) {
- if (sd[i].autotile_coord == coord) {
- edited_collision_shape = sd[i].shape;
- found_collision_shape = true;
- break;
+ if ((tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) && current_tile_region.has_point(mb->get_position())) {
+ 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)));
+ if (edited_shape_coord != coord) {
+ edited_shape_coord = coord;
+ edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord);
+ edited_navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord);
+ Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile());
+ bool found_collision_shape = false;
+ for (int i = 0; i < sd.size(); i++) {
+ if (sd[i].autotile_coord == coord) {
+ edited_collision_shape = sd[i].shape;
+ found_collision_shape = true;
+ break;
+ }
}
+ if (!found_collision_shape)
+ edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL);
+ select_coord(edited_shape_coord);
}
- if (!found_collision_shape)
- edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL);
- select_coord(edited_shape_coord);
}
- }
- workspace->update();
- } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
- if (edit_mode == EDITMODE_COLLISION) {
- if (dragging_point >= 0) {
- dragging_point = -1;
+ workspace->update();
+ } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (edit_mode == EDITMODE_COLLISION) {
+ if (dragging_point >= 0) {
+ dragging_point = -1;
- Vector<Vector2> points;
+ Vector<Vector2> points;
- for (int i = 0; i < current_shape.size(); i++) {
- Vector2 p = current_shape[i];
- if (tools[SHAPE_GRID_SNAP]->is_pressed() || tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) {
- p = snap_point(p);
+ for (int i = 0; i < current_shape.size(); i++) {
+ Vector2 p = current_shape[i];
+ if (tools[TOOL_GRID_SNAP]->is_pressed() || tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) {
+ p = snap_point(p);
+ }
+ points.push_back(p - shape_anchor);
}
- points.push_back(p - shape_anchor);
- }
- edited_collision_shape->set_points(points);
+ edited_collision_shape->set_points(points);
- workspace->update();
- }
- } else if (edit_mode == EDITMODE_OCCLUSION) {
- if (dragging_point >= 0) {
- dragging_point = -1;
-
- PoolVector<Vector2> polygon;
- polygon.resize(current_shape.size());
- PoolVector<Vector2>::Write w = polygon.write();
-
- for (int i = 0; i < current_shape.size(); i++) {
- w[i] = current_shape[i] - shape_anchor;
+ workspace->update();
}
+ } else if (edit_mode == EDITMODE_OCCLUSION) {
+ if (dragging_point >= 0) {
+ dragging_point = -1;
- w = PoolVector<Vector2>::Write();
- edited_occlusion_shape->set_polygon(polygon);
+ PoolVector<Vector2> polygon;
+ polygon.resize(current_shape.size());
+ PoolVector<Vector2>::Write w = polygon.write();
- workspace->update();
- }
- } else if (edit_mode == EDITMODE_NAVIGATION) {
- if (dragging_point >= 0) {
- dragging_point = -1;
+ for (int i = 0; i < current_shape.size(); i++) {
+ w[i] = current_shape[i] - shape_anchor;
+ }
- PoolVector<Vector2> polygon;
- Vector<int> indices;
- polygon.resize(current_shape.size());
- PoolVector<Vector2>::Write w = polygon.write();
+ w = PoolVector<Vector2>::Write();
+ edited_occlusion_shape->set_polygon(polygon);
- for (int i = 0; i < current_shape.size(); i++) {
- w[i] = current_shape[i] - shape_anchor;
- indices.push_back(i);
+ workspace->update();
}
+ } else if (edit_mode == EDITMODE_NAVIGATION) {
+ if (dragging_point >= 0) {
+ dragging_point = -1;
+
+ PoolVector<Vector2> polygon;
+ Vector<int> indices;
+ polygon.resize(current_shape.size());
+ PoolVector<Vector2>::Write w = polygon.write();
+
+ for (int i = 0; i < current_shape.size(); i++) {
+ w[i] = current_shape[i] - shape_anchor;
+ indices.push_back(i);
+ }
- w = PoolVector<Vector2>::Write();
- edited_navigation_shape->set_vertices(polygon);
- edited_navigation_shape->add_polygon(indices);
-
- workspace->update();
- }
- }
- }
- } else if (mm.is_valid()) {
- if (dragging_point >= 0) {
- current_shape.set(dragging_point, snap_point(mm->get_position()));
- workspace->update();
- }
- }
- } else if (tools[SHAPE_NEW_POLYGON]->is_pressed()) {
+ w = PoolVector<Vector2>::Write();
+ edited_navigation_shape->set_vertices(polygon);
+ edited_navigation_shape->add_polygon(indices);
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
- Vector2 pos = mb->get_position();
- pos = snap_point(pos);
- if (creating_shape) {
- if (current_shape.size() > 0) {
- if ((pos - current_shape[0]).length_squared() <= MIN_DISTANCE_SQUARED) {
- if (current_shape.size() > 2) {
- close_shape(shape_anchor);
- workspace->update();
- return;
- }
+ workspace->update();
}
}
- current_shape.push_back(pos);
+ }
+ } else if (mm.is_valid()) {
+ if (dragging_point >= 0) {
+ current_shape.set(dragging_point, snap_point(mm->get_position()));
workspace->update();
- } else {
- int t_id = get_current_tile();
- if (t_id >= 0) {
- if (edit_mode == EDITMODE_COLLISION) {
- Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(t_id);
- for (int i = 0; i < sd.size(); i++) {
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || sd[i].autotile_coord == edited_shape_coord) {
- Ref<ConvexPolygonShape2D> shape = sd[i].shape;
-
- if (!shape.is_null()) {
- sd.remove(i);
- tileset->tile_set_shapes(get_current_tile(), sd);
- edited_collision_shape = Ref<Shape2D>();
- workspace->update();
- }
- break;
+ }
+ }
+ } else if (tools[SHAPE_NEW_POLYGON]->is_pressed()) {
+
+ if (mb.is_valid()) {
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ Vector2 pos = mb->get_position();
+ pos = snap_point(pos);
+ if (creating_shape) {
+ if (current_shape.size() > 0) {
+ if ((pos - current_shape[0]).length_squared() <= MIN_DISTANCE_SQUARED) {
+ if (current_shape.size() > 2) {
+ close_shape(shape_anchor);
+ workspace->update();
+ return;
}
}
- } else if (edit_mode == EDITMODE_OCCLUSION) {
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) {
- Map<Vector2, Ref<OccluderPolygon2D> > map = tileset->autotile_get_light_oclusion_map(t_id);
- for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) {
- if (E->key() == edited_shape_coord) {
- tileset->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord);
+ }
+ current_shape.push_back(pos);
+ workspace->update();
+ } else {
+ int t_id = get_current_tile();
+ if (t_id >= 0) {
+ if (edit_mode == EDITMODE_COLLISION) {
+ Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(t_id);
+ for (int i = 0; i < sd.size(); i++) {
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || sd[i].autotile_coord == edited_shape_coord) {
+ Ref<ConvexPolygonShape2D> shape = sd[i].shape;
+
+ if (!shape.is_null()) {
+ sd.remove(i);
+ tileset->tile_set_shapes(get_current_tile(), sd);
+ edited_collision_shape = Ref<Shape2D>();
+ workspace->update();
+ }
break;
}
}
- } else
- tileset->tile_set_light_occluder(t_id, Ref<OccluderPolygon2D>());
+ } else if (edit_mode == EDITMODE_OCCLUSION) {
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
+ Map<Vector2, Ref<OccluderPolygon2D> > map = tileset->autotile_get_light_oclusion_map(t_id);
+ for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) {
+ if (E->key() == edited_shape_coord) {
+ tileset->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord);
+ break;
+ }
+ }
+ } else
+ tileset->tile_set_light_occluder(t_id, Ref<OccluderPolygon2D>());
- edited_occlusion_shape = Ref<OccluderPolygon2D>();
- workspace->update();
- } else if (edit_mode == EDITMODE_NAVIGATION) {
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) {
- Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id);
- for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) {
- if (E->key() == edited_shape_coord) {
- tileset->autotile_set_navigation_polygon(t_id, Ref<NavigationPolygon>(), edited_shape_coord);
- break;
+ edited_occlusion_shape = Ref<OccluderPolygon2D>();
+ workspace->update();
+ } else if (edit_mode == EDITMODE_NAVIGATION) {
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
+ Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id);
+ for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) {
+ if (E->key() == edited_shape_coord) {
+ tileset->autotile_set_navigation_polygon(t_id, Ref<NavigationPolygon>(), edited_shape_coord);
+ break;
+ }
}
- }
- } else
- tileset->tile_set_navigation_polygon(t_id, Ref<NavigationPolygon>());
- edited_navigation_shape = Ref<NavigationPolygon>();
- workspace->update();
+ } else
+ tileset->tile_set_navigation_polygon(t_id, Ref<NavigationPolygon>());
+ edited_navigation_shape = Ref<NavigationPolygon>();
+ workspace->update();
+ }
}
- }
- creating_shape = true;
- current_shape.resize(0);
- current_shape.push_back(snap_point(pos));
+ creating_shape = true;
+ current_shape.resize(0);
+ current_shape.push_back(snap_point(pos));
+ }
+ } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT && current_shape.size() > 2) {
+ if (creating_shape) {
+ close_shape(shape_anchor);
+ }
}
- } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT && current_shape.size() > 2) {
+ } else if (mm.is_valid()) {
if (creating_shape) {
- close_shape(shape_anchor);
+ workspace->update();
}
}
- } else if (mm.is_valid()) {
- if (creating_shape) {
- workspace->update();
- }
}
- }
- } break;
- }
-
- //Drag Middle Mouse
- if (mm.is_valid()) {
- if (mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
-
- Vector2 dragged(mm->get_relative().x, mm->get_relative().y);
- scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x);
- scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x);
+ } break;
}
}
}
@@ -1144,6 +1361,16 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
workspace->update();
} else {
switch (edit_mode) {
+ case EDITMODE_REGION: {
+ if (workspace_mode == WORKSPACE_EDIT && get_current_tile() >= 0) {
+ tileset->remove_tile(get_current_tile());
+ workspace->update();
+ workspace_overlay->update();
+ }
+ tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true);
+ workspace_mode = WORKSPACE_EDIT;
+ update_workspace_tile_mode();
+ } break;
case EDITMODE_COLLISION: {
if (!edited_collision_shape.is_null()) {
Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile());
@@ -1186,22 +1413,22 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
if (scale > 0.1) {
scale /= 2;
workspace->set_scale(Vector2(scale, scale));
- workspace_container->set_custom_minimum_size(preview->get_region_rect().size * scale);
- workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size * scale);
+ workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale);
+ workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale);
}
} else if (p_tool == ZOOM_1) {
workspace->set_scale(Vector2(1, 1));
- workspace_container->set_custom_minimum_size(preview->get_region_rect().size);
- workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size);
+ workspace_container->set_custom_minimum_size(workspace->get_rect().size);
+ workspace_overlay->set_custom_minimum_size(workspace->get_rect().size);
} else if (p_tool == ZOOM_IN) {
float scale = workspace->get_scale().x;
scale *= 2;
workspace->set_scale(Vector2(scale, scale));
- workspace_container->set_custom_minimum_size(preview->get_region_rect().size * scale);
- workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size * scale);
+ workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale);
+ workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale);
} else if (p_tool == TOOL_SELECT) {
if (creating_shape) {
- //Cancel Creation
+ // Cancel Creation
creating_shape = false;
current_shape.resize(0);
workspace->update();
@@ -1215,66 +1442,140 @@ void TileSetEditor::_on_priority_changed(float val) {
}
void TileSetEditor::_on_grid_snap_toggled(bool p_val) {
- if (p_val)
- hb_grid->show();
- else
- hb_grid->hide();
+ helper->set_snap_options_visible(p_val);
workspace->update();
}
-void TileSetEditor::_set_snap_step_x(float p_val) {
- snap_step.x = p_val;
+void TileSetEditor::_set_snap_step(Vector2 p_val) {
+ snap_step.x = CLAMP(p_val.x, 0, 256);
+ snap_step.y = CLAMP(p_val.y, 0, 256);
workspace->update();
}
-void TileSetEditor::_set_snap_step_y(float p_val) {
- snap_step.y = p_val;
+void TileSetEditor::_set_snap_off(Vector2 p_val) {
+ snap_offset.x = CLAMP(p_val.x, 0, 256 + WORKSPACE_MARGIN.x);
+ snap_offset.y = CLAMP(p_val.y, 0, 256 + WORKSPACE_MARGIN.y);
workspace->update();
}
-void TileSetEditor::_set_snap_off_x(float p_val) {
- snap_offset.x = p_val;
+void TileSetEditor::_set_snap_sep(Vector2 p_val) {
+ snap_separation.x = CLAMP(p_val.x, 0, 256);
+ snap_separation.y = CLAMP(p_val.y, 0, 256);
workspace->update();
}
-void TileSetEditor::_set_snap_off_y(float p_val) {
- snap_offset.y = p_val;
- workspace->update();
-}
-void TileSetEditor::_set_snap_sep_x(float p_val) {
- snap_separation.x = p_val;
- workspace->update();
-}
+void TileSetEditor::draw_highlight_current_tile() {
-void TileSetEditor::_set_snap_sep_y(float p_val) {
- snap_separation.y = p_val;
- workspace->update();
+ if (get_current_tile() >= 0) {
+ Rect2 region = tileset->tile_get_region(get_current_tile());
+ region.position += WORKSPACE_MARGIN;
+ workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, region.position.y), Color(0.3, 0.3, 0.3, 0.3));
+ workspace->draw_rect(Rect2(0, region.position.y, region.position.x, region.size.y), Color(0.3, 0.3, 0.3, 0.3));
+ workspace->draw_rect(Rect2(region.position.x + region.size.x, region.position.y, workspace->get_rect().size.x - region.position.x - region.size.x, region.size.y), Color(0.3, 0.3, 0.3, 0.3));
+ workspace->draw_rect(Rect2(0, region.position.y + region.size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - region.size.y - region.position.y), Color(0.3, 0.3, 0.3, 0.3));
+ } else {
+ workspace->draw_rect(Rect2(Point2(0, 0), workspace->get_rect().size), Color(0.3, 0.3, 0.3, 0.3));
+ }
}
-void TileSetEditor::draw_highlight_tile(Vector2 coord, const Vector<Vector2> &other_highlighted) {
+void TileSetEditor::draw_highlight_subtile(Vector2 coord, const Vector<Vector2> &other_highlighted) {
Vector2 size = tileset->autotile_get_size(get_current_tile());
int spacing = tileset->autotile_get_spacing(get_current_tile());
Rect2 region = tileset->tile_get_region(get_current_tile());
coord.x *= (size.x + spacing);
coord.y *= (size.y + spacing);
- workspace->draw_rect(Rect2(0, 0, region.size.x, coord.y), Color(0.5, 0.5, 0.5, 0.5));
- workspace->draw_rect(Rect2(0, coord.y, coord.x, size.y), Color(0.5, 0.5, 0.5, 0.5));
- workspace->draw_rect(Rect2(coord.x + size.x, coord.y, region.size.x - coord.x - size.x, size.y), Color(0.5, 0.5, 0.5, 0.5));
- workspace->draw_rect(Rect2(0, coord.y + size.y, region.size.x, region.size.y - size.y - coord.y), Color(0.5, 0.5, 0.5, 0.5));
+ coord += region.position;
+ coord += WORKSPACE_MARGIN;
+ workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, coord.y), Color(0.3, 0.3, 0.3, 0.3));
+ workspace->draw_rect(Rect2(0, coord.y, coord.x, size.y), Color(0.3, 0.3, 0.3, 0.3));
+ workspace->draw_rect(Rect2(coord.x + size.x, coord.y, workspace->get_rect().size.x - coord.x - size.x, size.y), Color(0.3, 0.3, 0.3, 0.3));
+ workspace->draw_rect(Rect2(0, coord.y + size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - size.y - coord.y), Color(0.3, 0.3, 0.3, 0.3));
coord += Vector2(1, 1) / workspace->get_scale().x;
workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0, 0), false);
for (int i = 0; i < other_highlighted.size(); i++) {
coord = other_highlighted[i];
coord.x *= (size.x + spacing);
coord.y *= (size.y + spacing);
+ coord += region.position;
+ coord += WORKSPACE_MARGIN;
coord += Vector2(1, 1) / workspace->get_scale().x;
- workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0, 0), false);
+ workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0.5, 0.5), false);
+ }
+}
+
+void TileSetEditor::draw_tile_subdivision(int p_id, Color p_color) const {
+ Color c = p_color;
+ if (tileset->tile_get_tile_mode(p_id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(p_id) == TileSet::ATLAS_TILE) {
+ Rect2 region = tileset->tile_get_region(p_id);
+ Size2 size = tileset->autotile_get_size(p_id);
+ int spacing = tileset->autotile_get_spacing(p_id);
+ float j = 0;
+ while (j < region.size.x) {
+ j += size.x;
+ if (spacing <= 0) {
+ workspace->draw_line(region.position + WORKSPACE_MARGIN + Point2(j, 0), region.position + WORKSPACE_MARGIN + Point2(j, region.size.y), c);
+ } else {
+ workspace->draw_rect(Rect2(region.position + WORKSPACE_MARGIN + Point2(j, 0), Size2(spacing, region.size.y)), c);
+ }
+ j += spacing;
+ }
+ j = 0;
+ while (j < region.size.y) {
+ j += size.y;
+ if (spacing <= 0) {
+ workspace->draw_line(region.position + WORKSPACE_MARGIN + Point2(0, j), region.position + WORKSPACE_MARGIN + Point2(region.size.x, j), c);
+ } else {
+ workspace->draw_rect(Rect2(region.position + WORKSPACE_MARGIN + Point2(0, j), Size2(region.size.x, spacing)), c);
+ }
+ j += spacing;
+ }
+ }
+}
+
+void TileSetEditor::draw_edited_region_subdivision() const {
+ Color c = Color(0.347214, 0.722656, 0.617063, 1);
+ Rect2 region = edited_region;
+ Size2 size;
+ int spacing;
+ bool draw;
+ if (workspace_mode == WORKSPACE_EDIT) {
+ int p_id = get_current_tile();
+ size = tileset->autotile_get_size(p_id);
+ spacing = tileset->autotile_get_spacing(p_id);
+ draw = tileset->tile_get_tile_mode(p_id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(p_id) == TileSet::ATLAS_TILE;
+ } else {
+ size = snap_step;
+ spacing = snap_separation.x;
+ draw = workspace_mode != WORKSPACE_CREATE_SINGLE;
+ }
+ if (draw) {
+
+ float j = 0;
+ while (j < region.size.x) {
+ j += size.x;
+ if (spacing <= 0) {
+ workspace->draw_line(region.position + Point2(j, 0), region.position + Point2(j, region.size.y), c);
+ } else {
+ workspace->draw_rect(Rect2(region.position + Point2(j, 0), Size2(spacing, region.size.y)), c);
+ }
+ j += spacing;
+ }
+ j = 0;
+ while (j < region.size.y) {
+ j += size.y;
+ if (spacing <= 0) {
+ workspace->draw_line(region.position + Point2(0, j), region.position + Point2(region.size.x, j), c);
+ } else {
+ workspace->draw_rect(Rect2(region.position + Point2(0, j), Size2(region.size.x, spacing)), c);
+ }
+ j += spacing;
+ }
}
}
void TileSetEditor::draw_grid_snap() {
- if (tools[SHAPE_GRID_SNAP]->is_pressed()) {
+ if (tools[TOOL_GRID_SNAP]->is_pressed()) {
Color grid_color = Color(0.39, 0, 1, 0.2f);
Size2 s = workspace->get_size();
@@ -1328,7 +1629,7 @@ void TileSetEditor::draw_polygon_shapes() {
for (int i = 0; i < sd.size(); i++) {
Vector2 coord = Vector2(0, 0);
Vector2 anchor = Vector2(0, 0);
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) {
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
coord = sd[i].autotile_coord;
anchor = tileset->autotile_get_size(t_id);
anchor.x += tileset->autotile_get_spacing(t_id);
@@ -1336,6 +1637,8 @@ void TileSetEditor::draw_polygon_shapes() {
anchor.x *= coord.x;
anchor.y *= coord.y;
}
+ anchor += WORKSPACE_MARGIN;
+ anchor += tileset->tile_get_region(t_id).position;
Ref<ConvexPolygonShape2D> shape = sd[i].shape;
if (shape.is_valid()) {
Color c_bg;
@@ -1407,6 +1710,8 @@ void TileSetEditor::draw_polygon_shapes() {
anchor.y += tileset->autotile_get_spacing(t_id);
anchor.x *= coord.x;
anchor.y *= coord.y;
+ anchor += WORKSPACE_MARGIN;
+ anchor += tileset->tile_get_region(t_id).position;
Ref<OccluderPolygon2D> shape = E->value();
if (shape.is_valid()) {
Color c_bg;
@@ -1483,6 +1788,8 @@ void TileSetEditor::draw_polygon_shapes() {
anchor.y += tileset->autotile_get_spacing(t_id);
anchor.x *= coord.x;
anchor.y *= coord.y;
+ anchor += WORKSPACE_MARGIN;
+ anchor += tileset->tile_get_region(t_id).position;
Ref<NavigationPolygon> shape = E->value();
if (shape.is_valid()) {
Color c_bg;
@@ -1558,10 +1865,10 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) {
shape->set_points(segments);
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE)
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE)
tileset->tile_add_shape(get_current_tile(), shape, Transform2D(), false, edited_shape_coord);
else
- tileset->tile_set_shape(get_current_tile(), 0, shape);
+ tileset->tile_add_shape(get_current_tile(), shape, Transform2D());
edited_collision_shape = shape;
}
@@ -1582,7 +1889,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) {
w = PoolVector<Vector2>::Write();
shape->set_polygon(polygon);
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE)
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE)
tileset->autotile_set_light_occluder(get_current_tile(), shape, edited_shape_coord);
else
tileset->tile_set_light_occluder(get_current_tile(), shape);
@@ -1606,7 +1913,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) {
shape->set_vertices(polygon);
shape->add_polygon(indices);
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE)
+ if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE)
tileset->autotile_set_navigation_polygon(get_current_tile(), shape, edited_shape_coord);
else
tileset->tile_set_navigation_polygon(get_current_tile(), shape);
@@ -1619,6 +1926,8 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) {
void TileSetEditor::select_coord(const Vector2 &coord) {
current_shape = PoolVector2Array();
+ Rect2 current_tile_region = tileset->tile_get_region(get_current_tile());
+ current_tile_region.position += WORKSPACE_MARGIN;
if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
if (edited_collision_shape != tileset->tile_get_shape(get_current_tile(), 0))
edited_collision_shape = tileset->tile_get_shape(get_current_tile(), 0);
@@ -1631,14 +1940,14 @@ void TileSetEditor::select_coord(const Vector2 &coord) {
current_shape.resize(0);
if (edited_collision_shape.is_valid()) {
for (int i = 0; i < edited_collision_shape->get_points().size(); i++) {
- current_shape.push_back(edited_collision_shape->get_points()[i]);
+ current_shape.push_back(edited_collision_shape->get_points()[i] + current_tile_region.position);
}
}
} else if (edit_mode == EDITMODE_OCCLUSION) {
current_shape.resize(0);
if (edited_occlusion_shape.is_valid()) {
for (int i = 0; i < edited_occlusion_shape->get_polygon().size(); i++) {
- current_shape.push_back(edited_occlusion_shape->get_polygon()[i]);
+ current_shape.push_back(edited_occlusion_shape->get_polygon()[i] + current_tile_region.position);
}
}
} else if (edit_mode == EDITMODE_NAVIGATION) {
@@ -1647,7 +1956,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) {
if (edited_navigation_shape->get_polygon_count() > 0) {
PoolVector<Vector2> vertices = edited_navigation_shape->get_vertices();
for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) {
- current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]]);
+ current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]] + current_tile_region.position);
}
}
}
@@ -1658,6 +1967,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) {
Vector2 shape_anchor = coord;
shape_anchor.x *= (size.x + spacing);
shape_anchor.y *= (size.y + spacing);
+ shape_anchor += current_tile_region.position;
if (edit_mode == EDITMODE_COLLISION) {
current_shape.resize(0);
if (edited_collision_shape.is_valid()) {
@@ -1684,6 +1994,9 @@ void TileSetEditor::select_coord(const Vector2 &coord) {
}
}
}
+ workspace->update();
+ workspace_container->update();
+ helper->_change_notify("");
}
Vector2 TileSetEditor::snap_point(const Vector2 &point) {
@@ -1694,11 +2007,13 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) {
Vector2 anchor = coord;
anchor.x *= (tile_size.x + spacing);
anchor.y *= (tile_size.y + spacing);
+ anchor += tileset->tile_get_region(get_current_tile()).position;
+ anchor += WORKSPACE_MARGIN;
Rect2 region(anchor, tile_size);
if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE)
- region.position = Point2(0, 0);
+ region.position = tileset->tile_get_region(get_current_tile()).position + WORKSPACE_MARGIN;
- if (tools[SHAPE_GRID_SNAP]->is_pressed()) {
+ if (tools[TOOL_GRID_SNAP]->is_pressed()) {
p.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p.x, snap_separation.x);
p.y = Math::snap_scalar_seperation(snap_offset.y, snap_step.y, p.y, snap_separation.y);
}
@@ -1715,211 +2030,332 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) {
return p;
}
-void TileSetEditor::update_tile_list() {
- int selected_tile = get_current_tile();
-
- if (selected_tile < 0)
- selected_tile = 0;
+void TileSetEditor::update_texture_list() {
+ Ref<Texture> selected_texture = get_current_texture();
helper->set_tileset(tileset);
- tile_list->clear();
List<int> ids;
tileset->get_tile_list(&ids);
for (List<int>::Element *E = ids.front(); E; E = E->next()) {
- tile_list->add_item(tileset->tile_get_name(E->get()));
- tile_list->set_item_metadata(tile_list->get_item_count() - 1, E->get());
- tile_list->set_item_icon(tile_list->get_item_count() - 1, tileset->tile_get_texture(E->get()));
- Rect2 region = tileset->tile_get_region(E->get());
- if (tileset->tile_get_tile_mode(E->get()) == TileSet::AUTO_TILE) {
- region.size = tileset->autotile_get_size(E->get());
- Vector2 pos = tileset->autotile_get_icon_coordinate(E->get());
- pos.x *= (tileset->autotile_get_spacing(E->get()) + region.size.x);
- pos.y *= (tileset->autotile_get_spacing(E->get()) + region.size.y);
- region.position += pos;
+ if (!texture_map.has(tileset->tile_get_texture(E->get())->get_rid())) {
+ texture_list->add_item(tileset->tile_get_texture(E->get())->get_path().get_file());
+ texture_map.insert(tileset->tile_get_texture(E->get())->get_rid(), tileset->tile_get_texture(E->get()));
+ texture_list->set_item_metadata(texture_list->get_item_count() - 1, tileset->tile_get_texture(E->get())->get_rid());
}
- tile_list->set_item_icon_region(tile_list->get_item_count() - 1, region);
- tile_list->set_item_icon_modulate(tile_list->get_item_count() - 1, tileset->tile_get_modulate(E->get()));
}
- if (tile_list->get_item_count() > 0 && selected_tile < tile_list->get_item_count()) {
- tile_list->select(selected_tile);
- _on_tile_list_selected(selected_tile);
+ if (texture_list->get_item_count() > 0 && selected_texture.is_valid()) {
+ texture_list->select(texture_list->find_metadata(selected_texture->get_rid()));
+ if (texture_list->get_selected_items().size() > 0)
+ _on_texture_list_selected(texture_list->get_selected_items()[0]);
+ } else if (get_current_texture().is_valid()) {
+ _on_texture_list_selected(texture_list->find_metadata(get_current_texture()->get_rid()));
+ } else {
+ _on_texture_list_selected(-1);
}
+ update_texture_list_icon();
helper->_change_notify("");
}
-void TileSetEditor::update_tile_list_icon() {
- List<int> ids;
- tileset->get_tile_list(&ids);
- int current_idx = 0;
- for (List<int>::Element *E = ids.front(); E; E = E->next()) {
- if (current_idx >= tile_list->get_item_count())
- break;
-
- Rect2 region = tileset->tile_get_region(E->get());
- if (tileset->tile_get_tile_mode(E->get()) == TileSet::AUTO_TILE) {
- region.size = tileset->autotile_get_size(E->get());
- Vector2 pos = tileset->autotile_get_icon_coordinate(E->get());
- pos.x *= (tileset->autotile_get_spacing(E->get()) + region.size.x);
- pos.y *= (tileset->autotile_get_spacing(E->get()) + region.size.y);
- region.position += pos;
- }
- tile_list->set_item_metadata(current_idx, E->get());
- tile_list->set_item_icon(current_idx, tileset->tile_get_texture(E->get()));
- tile_list->set_item_icon_region(current_idx, region);
- tile_list->set_item_icon_modulate(current_idx, tileset->tile_get_modulate(E->get()));
- tile_list->set_item_text(current_idx, tileset->tile_get_name(E->get()));
- current_idx += 1;
+void TileSetEditor::update_texture_list_icon() {
+
+ for (int current_idx = 0; current_idx < texture_list->get_item_count(); current_idx++) {
+ RID rid = texture_list->get_item_metadata(current_idx);
+ texture_list->set_item_icon(current_idx, texture_map[rid]);
+ texture_list->set_item_icon_region(current_idx, Rect2(0, 0, 150, 100));
}
- tile_list->update();
+ texture_list->update();
}
void TileSetEditor::update_workspace_tile_mode() {
- if (get_current_tile() < 0)
+
+ if (workspace_mode != WORKSPACE_EDIT) {
+ for (int i = 0; i < EDITMODE_MAX; i++) {
+ tool_editmode[i]->hide();
+ }
+ tool_editmode[EDITMODE_REGION]->show();
+ tool_editmode[EDITMODE_REGION]->set_pressed(true);
+ _on_edit_mode_changed(EDITMODE_REGION);
+ return;
+ }
+
+ if (get_current_tile() < 0) {
+ for (int i = 0; i < EDITMODE_MAX; i++) {
+ tool_editmode[i]->hide();
+ }
+ for (int i = 0; i < ZOOM_OUT; i++) {
+ tools[i]->hide();
+ }
return;
+ }
+
+ for (int i = 0; i < EDITMODE_MAX; i++) {
+ tool_editmode[i]->show();
+ }
+
if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
if (tool_editmode[EDITMODE_ICON]->is_pressed() || tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) {
tool_editmode[EDITMODE_COLLISION]->set_pressed(true);
- _on_edit_mode_changed(EDITMODE_COLLISION);
- } else {
- select_coord(Vector2(0, 0));
+ edit_mode = EDITMODE_COLLISION;
}
+ select_coord(Vector2(0, 0));
tool_editmode[EDITMODE_ICON]->hide();
tool_editmode[EDITMODE_BITMASK]->hide();
tool_editmode[EDITMODE_PRIORITY]->hide();
- property_editor->hide();
+ } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
+ if (edit_mode == EDITMODE_ICON)
+ select_coord(tileset->autotile_get_icon_coordinate(get_current_tile()));
+ else
+ select_coord(edited_shape_coord);
+ } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
+ if (tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) {
+ tool_editmode[EDITMODE_COLLISION]->set_pressed(true);
+ edit_mode = EDITMODE_COLLISION;
+ }
+ if (edit_mode == EDITMODE_ICON)
+ select_coord(tileset->autotile_get_icon_coordinate(get_current_tile()));
+ else
+ select_coord(edited_shape_coord);
+
+ tool_editmode[EDITMODE_BITMASK]->hide();
+ tool_editmode[EDITMODE_PRIORITY]->hide();
+ }
+ _on_edit_mode_changed(edit_mode);
+}
+
+void TileSetEditor::update_edited_region(const Vector2 &end_point) {
+ edited_region = Rect2(region_from, Size2());
+ if (tools[TOOL_GRID_SNAP]->is_pressed()) {
+ Vector2 grid_coord;
+ grid_coord.x = Math::floor((region_from.x - snap_offset.x) / (snap_step.x + snap_separation.x));
+ grid_coord.y = Math::floor((region_from.y - snap_offset.y) / (snap_step.y + snap_separation.y));
+ grid_coord.x *= (snap_step.x + snap_separation.x);
+ grid_coord.y *= (snap_step.y + snap_separation.y);
+ grid_coord += snap_offset;
+ edited_region.expand_to(grid_coord);
+ grid_coord += snap_step;
+ edited_region.expand_to(grid_coord);
+ grid_coord.x = Math::floor((end_point.x - snap_offset.x) / (snap_step.x + snap_separation.x));
+ grid_coord.y = Math::floor((end_point.y - snap_offset.y) / (snap_step.y + snap_separation.y));
+ grid_coord.x *= (snap_step.x + snap_separation.x);
+ grid_coord.y *= (snap_step.y + snap_separation.y);
+ grid_coord += snap_offset;
+ edited_region.expand_to(grid_coord);
+ grid_coord += snap_step;
+ if (grid_coord.x < end_point.x)
+ grid_coord.x += snap_separation.x;
+ if (grid_coord.y < end_point.y)
+ grid_coord.y += snap_separation.y;
+ edited_region.expand_to(grid_coord);
} else {
- tool_editmode[EDITMODE_ICON]->show();
- tool_editmode[EDITMODE_BITMASK]->show();
- tool_editmode[EDITMODE_PRIORITY]->show();
- property_editor->show();
+ edited_region.expand_to(end_point);
}
}
-int TileSetEditor::get_current_tile() {
- if (tile_list->get_selected_items().size() == 0)
- return -1;
+int TileSetEditor::get_current_tile() const {
+ return current_tile;
+}
+
+void TileSetEditor::set_current_tile(int p_id) {
+ if (current_tile != p_id) {
+ current_tile = p_id;
+ helper->_change_notify("");
+ select_coord(Vector2(0, 0));
+ update_workspace_tile_mode();
+ }
+}
+
+Ref<Texture> TileSetEditor::get_current_texture() {
+ if (texture_list->get_selected_items().size() == 0)
+ return Ref<Texture>();
else
- return tile_list->get_item_metadata(tile_list->get_selected_items()[0]);
+ return texture_map[texture_list->get_item_metadata(texture_list->get_selected_items()[0])];
}
-void TileSetEditorHelper::set_tileset(const Ref<TileSet> &p_tileset) {
+void TilesetEditorContext::set_tileset(const Ref<TileSet> &p_tileset) {
tileset = p_tileset;
}
-bool TileSetEditorHelper::_set(const StringName &p_name, const Variant &p_value) {
+void TilesetEditorContext::set_snap_options_visible(bool p_visible) {
+ snap_options_visible = p_visible;
+ _change_notify("");
+}
- if (selected_tile < 0 || tileset.is_null())
- return false;
+bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name.operator String();
- bool v = false;
- if (name == "bitmask_mode") {
- tileset->set(String::num(selected_tile, 0) + "/autotile/bitmask_mode", p_value, &v);
- } else if (name.left(7) == "layout/") {
- tileset->set(String::num(selected_tile, 0) + "/autotile" + name.right(6), p_value, &v);
- }
- if (v) {
- tileset->_change_notify("autotile");
+
+ if (name == "options_offset") {
+ Vector2 snap = p_value;
+ tileset_editor->_set_snap_off(snap + WORKSPACE_MARGIN);
+ return true;
+ } else if (name == "options_step") {
+ Vector2 snap = p_value;
+ tileset_editor->_set_snap_step(snap);
+ return true;
+ } else if (name == "options_separation") {
+ Vector2 snap = p_value;
+ tileset_editor->_set_snap_sep(snap);
+ return true;
+ } else if (p_name.operator String().left(5) == "tile_") {
+ String name = p_name.operator String().right(5);
+ bool v = false;
+
+ if (tileset_editor->get_current_tile() < 0 || tileset.is_null())
+ return false;
+
+ if (name == "autotile_bitmask_mode") {
+ tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", p_value, &v);
+ } else if (name == "subtile_size") {
+ tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/tile_size", p_value, &v);
+ } else if (name == "subtile_spacing") {
+ tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/spacing", p_value, &v);
+ } else {
+ tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/" + name, p_value, &v);
+ }
+ if (v) {
+ tileset->_change_notify("");
+ tileset_editor->workspace->update();
+ tileset_editor->workspace_overlay->update();
+ }
+ return v;
}
- return v;
-}
-bool TileSetEditorHelper::_get(const StringName &p_name, Variant &r_ret) const {
+ tileset_editor->err_dialog->set_text(TTR("This property can't be changed."));
+ tileset_editor->err_dialog->popup_centered(Size2(300, 60));
+ return false;
+}
- if (selected_tile < 0 || tileset.is_null())
- return false;
- if (!tileset->has_tile(selected_tile))
- return false;
+bool TilesetEditorContext::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name.operator String();
bool v = false;
- if (name == "bitmask_mode") {
- r_ret = tileset->get(String::num(selected_tile, 0) + "/autotile/bitmask_mode", &v);
- } else if (name.left(7) == "layout/") {
- r_ret = tileset->get(String::num(selected_tile, 0) + "/autotile" + name.right(6), &v);
+
+ if (name == "options_offset") {
+ r_ret = tileset_editor->snap_offset - WORKSPACE_MARGIN;
+ v = true;
+ } else if (name == "options_step") {
+ r_ret = tileset_editor->snap_step;
+ v = true;
+ } else if (name == "options_separation") {
+ r_ret = tileset_editor->snap_separation;
+ v = true;
+ } else if (name.left(5) == "tile_") {
+ name = name.right(5);
+
+ if (tileset_editor->get_current_tile() < 0 || tileset.is_null())
+ return false;
+ if (!tileset->has_tile(tileset_editor->get_current_tile()))
+ return false;
+
+ if (name == "autotile_bitmask_mode") {
+ r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", &v);
+ } else if (name == "subtile_size") {
+ r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/tile_size", &v);
+ } else if (name == "subtile_spacing") {
+ r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/spacing", &v);
+ } else {
+ r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/" + name, &v);
+ }
+ return v;
+ } else if (name == "selected_collision") {
+ r_ret = tileset_editor->edited_collision_shape;
+ v = true;
+ } else if (name == "selected_navigation") {
+ r_ret = tileset_editor->edited_navigation_shape;
+ v = true;
+ } else if (name == "selected_occlusion") {
+ r_ret = tileset_editor->edited_occlusion_shape;
+ v = true;
}
return v;
}
-void TileSetEditorHelper::_get_property_list(List<PropertyInfo> *p_list) const {
-
- if (selected_tile < 0 || tileset.is_null())
- return;
+void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::INT, "bitmask_mode", PROPERTY_HINT_ENUM, "2x2,3x3 (minimal),3x3"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "layout/tile_size"));
- p_list->push_back(PropertyInfo(Variant::INT, "layout/spacing", PROPERTY_HINT_RANGE, "0,256,1"));
+ if (snap_options_visible) {
+ p_list->push_back(PropertyInfo(Variant::NIL, "Snap Options", PROPERTY_HINT_NONE, "options_", PROPERTY_USAGE_GROUP));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_offset"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_step"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_separation"));
+ }
+ if (tileset_editor->get_current_tile() >= 0 && !tileset.is_null()) {
+ int id = tileset_editor->get_current_tile();
+ p_list->push_back(PropertyInfo(Variant::NIL, "Selected Tile", PROPERTY_HINT_NONE, "tile_", PROPERTY_USAGE_GROUP));
+ p_list->push_back(PropertyInfo(Variant::STRING, "tile_name"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_tex_offset"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"));
+ p_list->push_back(PropertyInfo(Variant::COLOR, "tile_modulate"));
+ p_list->push_back(PropertyInfo(Variant::INT, "tile_tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE,ATLAS_TILE"));
+ if (tileset->tile_get_tile_mode(id) == TileSet::AUTO_TILE) {
+ p_list->push_back(PropertyInfo(Variant::INT, "tile_autotile_bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3 (minimal),3X3"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_subtile_size"));
+ p_list->push_back(PropertyInfo(Variant::INT, "tile_subtile_spacing", PROPERTY_HINT_RANGE, "0, 256, 1"));
+ } else if (tileset->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_subtile_size"));
+ p_list->push_back(PropertyInfo(Variant::INT, "tile_subtile_spacing", PROPERTY_HINT_RANGE, "0, 256, 1"));
+ }
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_occluder_offset"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_navigation_offset"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::INT, "tile_z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"));
+ }
+ if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_COLLISION && tileset_editor->edited_collision_shape.is_valid()) {
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_collision", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_collision_shape->get_class()));
+ }
+ if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_NAVIGATION && tileset_editor->edited_navigation_shape.is_valid()) {
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_navigation", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_navigation_shape->get_class()));
+ }
+ if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_OCCLUSION && tileset_editor->edited_occlusion_shape.is_valid()) {
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_occlusion", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_occlusion_shape->get_class()));
+ }
}
-TileSetEditorHelper::TileSetEditorHelper(TileSetEditor *p_tileset_editor) {
-
+TilesetEditorContext::TilesetEditorContext(TileSetEditor *p_tileset_editor) {
tileset_editor = p_tileset_editor;
- selected_tile = -1;
}
void TileSetEditorPlugin::edit(Object *p_node) {
if (Object::cast_to<TileSet>(p_node)) {
tileset_editor->edit(Object::cast_to<TileSet>(p_node));
- tileset_editor->show();
- tileset_editor->texture_region_editor->edit(p_node);
- } else
- tileset_editor->hide();
+ editor->get_inspector()->edit(tileset_editor->helper);
+ }
}
bool TileSetEditorPlugin::handles(Object *p_node) const {
- return p_node->is_class("TileSet");
+ return p_node->is_class("TileSet") ||
+ p_node->is_class("TilesetEditorContext");
}
void TileSetEditorPlugin::make_visible(bool p_visible) {
-
if (p_visible) {
- tileset_editor->show();
- tileset_editor->menu->show();
tileset_editor_button->show();
- tileset_editor->side_panel->show();
if (tileset_editor_button->is_pressed()) {
- tileset_editor->bottom_panel->show();
+ tileset_editor->show();
}
- texture_region_button->show();
- if (texture_region_button->is_pressed())
- tileset_editor->texture_region_editor->show();
+ get_tree()->connect("idle_frame", tileset_editor, "_on_workspace_process");
} else {
tileset_editor->hide();
- tileset_editor->menu->hide();
- tileset_editor->side_panel->hide();
- tileset_editor->bottom_panel->hide();
tileset_editor_button->hide();
- texture_region_button->hide();
- tileset_editor->texture_region_editor->hide();
+ get_tree()->disconnect("idle_frame", tileset_editor, "_on_workspace_process");
}
}
TileSetEditorPlugin::TileSetEditorPlugin(EditorNode *p_node) {
-
+ editor = p_node;
tileset_editor = memnew(TileSetEditor(p_node));
- add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, tileset_editor);
- tileset_editor->set_anchors_and_margins_preset(Control::PRESET_TOP_WIDE);
- tileset_editor->set_end(Point2(0, 22));
- tileset_editor->hide();
-
- tileset_editor->texture_region_editor = memnew(TextureRegionEditor(p_node));
- texture_region_button = p_node->add_bottom_panel_item(TTR("Texture Region"), tileset_editor->texture_region_editor);
- texture_region_button->set_tooltip(TTR("Texture Region Editor"));
-
- tileset_editor->texture_region_editor->set_custom_minimum_size(Size2(0, 200));
- tileset_editor->texture_region_editor->hide();
- texture_region_button->hide();
+ tileset_editor_button =
+ p_node->add_bottom_panel_item(TTR("Tile Set"), tileset_editor);
+ tileset_editor_button->set_tooltip(TTR("Tile Set Editor"));
- add_control_to_container(CONTAINER_CANVAS_EDITOR_SIDE, tileset_editor->side_panel);
- tileset_editor->side_panel->set_anchors_and_margins_preset(Control::PRESET_WIDE);
- tileset_editor->side_panel->set_custom_minimum_size(Size2(200, 0));
- tileset_editor->side_panel->hide();
- tileset_editor_button = p_node->add_bottom_panel_item(TTR("Tile Set"), tileset_editor->bottom_panel);
+ tileset_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
+ tileset_editor->hide();
tileset_editor_button->hide();
}
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index 4894d641a3..0c175e718c 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -33,21 +33,38 @@
#include "editor/editor_name_dialog.h"
#include "editor/editor_node.h"
-#include "editor/plugins/texture_region_editor_plugin.h"
#include "scene/2d/sprite.h"
#include "scene/resources/convex_polygon_shape_2d.h"
#include "scene/resources/tile_set.h"
-class TileSetEditorHelper;
+#define WORKSPACE_MARGIN Vector2(10, 10)
+class TilesetEditorContext;
-class TileSetEditor : public Control {
+class TileSetEditor : public Panel {
friend class TileSetEditorPlugin;
- friend class TextureRegionEditor;
+ friend class TilesetEditorContext;
- GDCLASS(TileSetEditor, Control);
+ GDCLASS(TileSetEditor, Panel)
+
+ enum TextureToolButtons {
+ TOOL_TILESET_ADD_TEXTURE,
+ TOOL_TILESET_REMOVE_TEXTURE,
+ TOOL_TILESET_CREATE_SCENE,
+ TOOL_TILESET_MERGE_SCENE,
+ TOOL_TILESET_MAX
+ };
+
+ enum WorkspaceMode {
+ WORKSPACE_EDIT,
+ WORKSPACE_CREATE_SINGLE,
+ WORKSPACE_CREATE_AUTOTILE,
+ WORKSPACE_CREATE_ATLAS,
+ WORKSPACE_MODE_MAX
+ };
enum EditMode {
+ EDITMODE_REGION,
EDITMODE_COLLISION,
EDITMODE_OCCLUSION,
EDITMODE_NAVIGATION,
@@ -57,13 +74,6 @@ class TileSetEditor : public Control {
EDITMODE_MAX
};
- enum TileSetToolbar {
- TOOLBAR_DUMMY,
- TOOLBAR_BITMASK,
- TOOLBAR_SHAPE,
- TOOLBAR_MAX
- };
-
enum TileSetTools {
TOOL_SELECT,
BITMASK_COPY,
@@ -71,17 +81,42 @@ class TileSetEditor : public Control {
BITMASK_CLEAR,
SHAPE_NEW_POLYGON,
SHAPE_DELETE,
- SHAPE_CREATE_FROM_BITMASK,
- SHAPE_CREATE_FROM_NOT_BITMASK,
SHAPE_KEEP_INSIDE_TILE,
- SHAPE_GRID_SNAP,
+ TOOL_GRID_SNAP,
ZOOM_OUT,
ZOOM_1,
ZOOM_IN,
+ VISIBLE_INFO,
TOOL_MAX
};
Ref<TileSet> tileset;
+ TilesetEditorContext *helper;
+ EditorNode *editor;
+
+ ConfirmationDialog *cd;
+ AcceptDialog *err_dialog;
+ EditorFileDialog *texture_dialog;
+
+ ItemList *texture_list;
+ int option;
+ ToolButton *tileset_toolbar_buttons[TOOL_TILESET_MAX];
+ MenuButton *tileset_toolbar_tools;
+ Map<RID, Ref<Texture> > texture_map;
+
+ bool creating_shape;
+ int dragging_point;
+ float tile_names_opacity;
+ Vector2 region_from;
+ Rect2 edited_region;
+ bool draw_edited_region;
+ Vector2 edited_shape_coord;
+ PoolVector2Array current_shape;
+ Map<Vector2, uint16_t> bitmask_map_copy;
+
+ Vector2 snap_step;
+ Vector2 snap_offset;
+ Vector2 snap_separation;
Ref<ConvexPolygonShape2D> edited_collision_shape;
Ref<OccluderPolygon2D> edited_occlusion_shape;
@@ -94,55 +129,19 @@ class TileSetEditor : public Control {
bool draw_handles;
Control *workspace_overlay;
Control *workspace;
+ Button *tool_workspacemode[WORKSPACE_MODE_MAX];
Button *tool_editmode[EDITMODE_MAX];
- HBoxContainer *tool_containers[TOOLBAR_MAX];
HBoxContainer *toolbar;
- HBoxContainer *hb_grid;
ToolButton *tools[TOOL_MAX];
SpinBox *spin_priority;
- SpinBox *sb_step_y;
- SpinBox *sb_step_x;
- SpinBox *sb_off_y;
- SpinBox *sb_off_x;
- SpinBox *sb_sep_y;
- SpinBox *sb_sep_x;
+ WorkspaceMode workspace_mode;
EditMode edit_mode;
+ int current_tile;
- Vector2 snap_step;
- Vector2 snap_offset;
- Vector2 snap_separation;
+ void update_texture_list();
+ void update_texture_list_icon();
- bool creating_shape;
- int dragging_point;
- Vector2 edited_shape_coord;
- PoolVector2Array current_shape;
- Map<Vector2, uint16_t> bitmask_map_copy;
-
- EditorNode *editor;
- TextureRegionEditor *texture_region_editor;
- Control *bottom_panel;
- Control *side_panel;
- ItemList *tile_list;
- PropertyEditor *property_editor;
- TileSetEditorHelper *helper;
-
- MenuButton *menu;
- ConfirmationDialog *cd;
- EditorNameDialog *nd;
- AcceptDialog *err_dialog;
-
- enum {
-
- MENU_OPTION_ADD_ITEM,
- MENU_OPTION_REMOVE_ITEM,
- MENU_OPTION_CREATE_FROM_SCENE,
- MENU_OPTION_MERGE_FROM_SCENE
- };
-
- int option;
- void _menu_cbk(int p_option);
- void _menu_confirm();
- void _name_dialog_confirm(const String &name);
+ Ref<Texture> get_current_texture();
static void _import_node(Node *p_node, Ref<TileSet> p_library);
static void _import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge);
@@ -150,7 +149,6 @@ class TileSetEditor : public Control {
protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void _changed_callback(Object *p_changed, const char *p_prop);
public:
void edit(const Ref<TileSet> &p_tileset);
@@ -160,53 +158,61 @@ public:
~TileSetEditor();
private:
- void _on_tile_list_selected(int p_index);
+ void _on_tileset_toolbar_button_pressed(int p_index);
+ void _on_tileset_toolbar_confirm();
+ void _on_texture_list_selected(int p_index);
+ void _on_textures_added(const PoolStringArray &p_paths);
void _on_edit_mode_changed(int p_edit_mode);
+ void _on_workspace_mode_changed(int p_workspace_mode);
void _on_workspace_overlay_draw();
void _on_workspace_draw();
+ void _on_workspace_process();
void _on_workspace_input(const Ref<InputEvent> &p_ie);
void _on_tool_clicked(int p_tool);
void _on_priority_changed(float val);
void _on_grid_snap_toggled(bool p_val);
- void _set_snap_step_x(float p_val);
- void _set_snap_step_y(float p_val);
- void _set_snap_off_x(float p_val);
- void _set_snap_off_y(float p_val);
- void _set_snap_sep_x(float p_val);
- void _set_snap_sep_y(float p_val);
-
- void initialize_bottom_editor();
- void draw_highlight_tile(Vector2 coord, const Vector<Vector2> &other_highlighted = Vector<Vector2>());
+ void _set_snap_step(Vector2 p_val);
+ void _set_snap_off(Vector2 p_val);
+ void _set_snap_sep(Vector2 p_val);
+
+ void draw_highlight_current_tile();
+ void draw_highlight_subtile(Vector2 coord, const Vector<Vector2> &other_highlighted = Vector<Vector2>());
+ void draw_tile_subdivision(int p_id, Color p_color) const;
+ void draw_edited_region_subdivision() const;
void draw_grid_snap();
void draw_polygon_shapes();
void close_shape(const Vector2 &shape_anchor);
void select_coord(const Vector2 &coord);
Vector2 snap_point(const Vector2 &point);
- void update_tile_list();
- void update_tile_list_icon();
void update_workspace_tile_mode();
+ void update_edited_region(const Vector2 &end_point);
- int get_current_tile();
+ int get_current_tile() const;
+ void set_current_tile(int p_id);
};
-class TileSetEditorHelper : public Object {
+class TilesetEditorContext : public Object {
friend class TileSetEditor;
- GDCLASS(TileSetEditorHelper, Object);
+ GDCLASS(TilesetEditorContext, Object);
Ref<TileSet> tileset;
TileSetEditor *tileset_editor;
- int selected_tile;
+ bool snap_options_visible;
public:
void set_tileset(const Ref<TileSet> &p_tileset);
+private:
+ void set_snap_options_visible(bool p_visible);
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- TileSetEditorHelper(TileSetEditor *p_tileset_editor);
+public:
+ TilesetEditorContext(TileSetEditor *p_tileset_editor);
};
class TileSetEditorPlugin : public EditorPlugin {
@@ -214,11 +220,9 @@ class TileSetEditorPlugin : public EditorPlugin {
GDCLASS(TileSetEditorPlugin, EditorPlugin);
TileSetEditor *tileset_editor;
+ Button *tileset_editor_button;
EditorNode *editor;
- ToolButton *tileset_editor_button;
- ToolButton *texture_region_button;
-
public:
virtual String get_name() const { return "TileSet"; }
bool has_main_screen() const { return false; }
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 73a9c8ac1a..d9419af549 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -164,7 +164,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node
Ref<PackedScene> sdata = ResourceLoader::load(p_files[i]);
if (!sdata.is_valid()) {
current_option = -1;
- accept->get_ok()->set_text(TTR("Ugh"));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error loading scene from %s"), p_files[i]));
accept->popup_centered_minsize();
error = true;
@@ -174,7 +174,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node
Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
if (!instanced_scene) {
current_option = -1;
- accept->get_ok()->set_text(TTR("Ugh"));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error instancing scene from %s"), p_files[i]));
accept->popup_centered_minsize();
error = true;
@@ -233,7 +233,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node
void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) {
Ref<PackedScene> sdata = ResourceLoader::load(p_file);
if (!sdata.is_valid()) {
- accept->get_ok()->set_text(TTR("Ugh"));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error loading scene from %s"), p_file));
accept->popup_centered_minsize();
return;
@@ -241,7 +241,7 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base)
Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
if (!instanced_scene) {
- accept->get_ok()->set_text(TTR("Ugh"));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(vformat(TTR("Error instancing scene from %s"), p_file));
accept->popup_centered_minsize();
return;
@@ -413,7 +413,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (scene_tree->get_selected() == edited_scene) {
current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation can't be done on the tree root."));
accept->popup_centered_minsize();
break;
@@ -474,7 +474,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (editor_selection->is_selected(edited_scene)) {
current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation can't be done on the tree root."));
accept->popup_centered_minsize();
break;
@@ -544,7 +544,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (editor_selection->is_selected(edited_scene)) {
current_option = -1;
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation can't be done on the tree root."));
accept->popup_centered_minsize();
break;
@@ -631,7 +631,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *scene = editor_data->get_edited_scene_root();
if (!scene) {
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation can't be done without a scene."));
accept->popup_centered_minsize();
break;
@@ -640,7 +640,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
List<Node *> selection = editor_selection->get_selected_node_list();
if (selection.size() != 1) {
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation requires a single selected node."));
accept->popup_centered_minsize();
break;
@@ -649,14 +649,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *tocopy = selection.front()->get();
if (tocopy == scene) {
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Can not perform with the root node."));
accept->popup_centered_minsize();
break;
}
if (tocopy != editor_data->get_edited_scene_root() && tocopy->get_filename() != "") {
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation can't be done on instanced scenes."));
accept->popup_centered_minsize();
break;
@@ -1737,7 +1737,7 @@ void SceneTreeDock::_new_scene_from(String p_file) {
List<Node *> selection = editor_selection->get_selected_node_list();
if (selection.size() != 1) {
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("This operation requires a single selected node."));
accept->popup_centered_minsize();
return;
@@ -1755,7 +1755,7 @@ void SceneTreeDock::_new_scene_from(String p_file) {
memdelete(copy);
if (err != OK) {
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Couldn't save new scene. Likely dependencies (instances) couldn't be satisfied."));
accept->popup_centered_minsize();
return;
@@ -1767,14 +1767,14 @@ void SceneTreeDock::_new_scene_from(String p_file) {
err = ResourceSaver::save(p_file, sdata, flg);
if (err != OK) {
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Error saving scene."));
accept->popup_centered_minsize();
return;
}
_replace_with_branch_scene(p_file, base);
} else {
- accept->get_ok()->set_text(TTR("I see..."));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Error duplicating scene to save it."));
accept->popup_centered_minsize();
return;
diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
index c450c0fd4c..b0505eebda 100644
--- a/editor/spatial_editor_gizmos.cpp
+++ b/editor/spatial_editor_gizmos.cpp
@@ -47,7 +47,10 @@
// Keep small children away from this file.
// It's so ugly it will eat them alive
-#define HANDLE_HALF_SIZE 0.05
+// The previous comment is kept only for historical reasons.
+// No children will be harmed by the visioning of this file... hopefully.
+
+#define HANDLE_HALF_SIZE 9.5
bool EditorSpatialGizmo::can_draw() const {
return is_editable();
@@ -85,11 +88,37 @@ void EditorSpatialGizmo::clear() {
void EditorSpatialGizmo::redraw() {
- if (get_script_instance() && get_script_instance()->has_method("redraw"))
- get_script_instance()->call("redraw");
+ ERR_FAIL_COND(!gizmo_plugin);
+ gizmo_plugin->redraw(this);
+}
+
+String EditorSpatialGizmo::get_handle_name(int p_idx) const {
+ ERR_FAIL_COND_V(!gizmo_plugin, "");
+ return gizmo_plugin->get_handle_name(this, p_idx);
+}
+
+Variant EditorSpatialGizmo::get_handle_value(int p_idx) {
+ ERR_FAIL_COND_V(!gizmo_plugin, Variant());
+ return gizmo_plugin->get_handle_value(this, p_idx);
+}
+
+void EditorSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
+ ERR_FAIL_COND(!gizmo_plugin);
+ return gizmo_plugin->set_handle(this, p_idx, p_camera, p_point);
+}
+
+void EditorSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
+ ERR_FAIL_COND(!gizmo_plugin);
+ return gizmo_plugin->commit_handle(this, p_idx, p_restore, p_cancel);
+}
+
+void EditorSpatialGizmo::set_spatial_node(Spatial *p_node) {
+
+ ERR_FAIL_NULL(p_node);
+ spatial_node = p_node;
}
-void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base) {
+void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base, bool p_hidden) {
instance = VS::get_singleton()->instance_create2(mesh->get_rid(), p_base->get_world()->get_scenario());
VS::get_singleton()->instance_attach_object_instance_id(instance, p_base->get_instance_id());
@@ -98,7 +127,8 @@ void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base) {
if (extra_margin)
VS::get_singleton()->instance_set_extra_visibility_margin(instance, 1);
VS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance, VS::SHADOW_CASTING_SETTING_OFF);
- VS::get_singleton()->instance_set_layer_mask(instance, 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER); //gizmos are 26
+ int layer = p_hidden ? 0 : 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER;
+ VS::get_singleton()->instance_set_layer_mask(instance, layer); //gizmos are 26
}
void EditorSpatialGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard, const RID &p_skeleton) {
@@ -110,7 +140,7 @@ void EditorSpatialGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard
ins.mesh = p_mesh;
ins.skeleton = p_skeleton;
if (valid) {
- ins.create_instance(spatial_node);
+ ins.create_instance(spatial_node, hidden);
VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
}
@@ -159,7 +189,7 @@ void EditorSpatialGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Mat
ins.billboard = p_billboard;
ins.mesh = mesh;
if (valid) {
- ins.create_instance(spatial_node);
+ ins.create_instance(spatial_node, hidden);
VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
}
@@ -210,7 +240,7 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material> &p_material,
ins.unscaled = true;
ins.billboard = true;
if (valid) {
- ins.create_instance(spatial_node);
+ ins.create_instance(spatial_node, hidden);
VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
}
@@ -233,7 +263,7 @@ void EditorSpatialGizmo::add_collision_segments(const Vector<Vector3> &p_lines)
}
}
-void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_billboard, bool p_secondary) {
+void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, bool p_billboard, bool p_secondary) {
billboard_handle = p_billboard;
@@ -257,7 +287,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi
for (int i = 0; i < p_handles.size(); i++) {
Color col(1, 1, 1, 1);
- if (is_gizmo_handle_highlighted(i))
+ if (gizmo_plugin->is_gizmo_handle_highlighted(this, i))
col = Color(0, 0, 1, 0.9);
if (SpatialEditor::get_singleton()->get_over_gizmo_handle() != i)
@@ -268,10 +298,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi
}
a[VS::ARRAY_COLOR] = colors;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, a);
- if (p_billboard)
- mesh->surface_set_material(0, SpatialEditorGizmos::singleton->handle2_material_billboard);
- else
- mesh->surface_set_material(0, SpatialEditorGizmos::singleton->handle2_material);
+ mesh->surface_set_material(0, p_material);
if (p_billboard) {
float md = 0;
@@ -288,7 +315,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi
ins.billboard = p_billboard;
ins.extra_margin = true;
if (valid) {
- ins.create_instance(spatial_node);
+ ins.create_instance(spatial_node, hidden);
VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
}
instances.push_back(ins);
@@ -330,17 +357,13 @@ void EditorSpatialGizmo::add_solid_box(Ref<Material> &p_material, Vector3 p_size
add_mesh(m);
}
-void EditorSpatialGizmo::set_spatial_node(Spatial *p_node) {
-
- ERR_FAIL_NULL(p_node);
- spatial_node = p_node;
-}
-
bool EditorSpatialGizmo::intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum) {
ERR_FAIL_COND_V(!spatial_node, false);
ERR_FAIL_COND_V(!valid, false);
+ if (hidden && !gizmo_plugin->is_selectable_when_hidden()) return false;
+
if (selectable_icon_size > 0.0f) {
Vector3 origin = spatial_node->get_global_transform().get_origin();
@@ -413,7 +436,9 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point,
ERR_FAIL_COND_V(!spatial_node, false);
ERR_FAIL_COND_V(!valid, false);
- if (r_gizmo_handle) {
+ if (hidden && !gizmo_plugin->is_selectable_when_hidden()) return false;
+
+ if (r_gizmo_handle && !hidden) {
Transform t = spatial_node->get_global_transform();
t.orthonormalize();
@@ -428,7 +453,8 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point,
Vector3 hpos = t.xform(secondary_handles[i]);
Vector2 p = p_camera->unproject_position(hpos);
- if (p.distance_to(p_point) < SpatialEditorGizmos::singleton->handle_t->get_width() * 0.6) {
+
+ if (p.distance_to(p_point) < HANDLE_HALF_SIZE) {
real_t dp = p_camera->get_transform().origin.distance_to(hpos);
if (dp < min_d) {
@@ -453,7 +479,8 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point,
Vector3 hpos = t.xform(handles[i]);
Vector2 p = p_camera->unproject_position(hpos);
- if (p.distance_to(p_point) < SpatialEditorGizmos::singleton->handle_t->get_width() * 0.6) {
+
+ if (p.distance_to(p_point) < HANDLE_HALF_SIZE) {
real_t dp = p_camera->get_transform().origin.distance_to(hpos);
if (dp < min_d) {
@@ -597,7 +624,7 @@ void EditorSpatialGizmo::create() {
for (int i = 0; i < instances.size(); i++) {
- instances.write[i].create_instance(spatial_node);
+ instances.write[i].create_instance(spatial_node, hidden);
}
transform();
@@ -624,96 +651,21 @@ void EditorSpatialGizmo::free() {
instances.write[i].instance = RID();
}
+ clear();
+
valid = false;
}
-Ref<SpatialMaterial> EditorSpatialGizmo::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) {
-
- String name = p_name;
-
- if (!is_editable()) {
- name += "@readonly";
- } else if (is_selected()) {
- name += "@selected";
- }
-
- if (SpatialEditorGizmos::singleton->material_cache.has(name)) {
- return SpatialEditorGizmos::singleton->material_cache[name];
- }
-
- Color color = p_color;
-
- if (!is_editable()) {
- color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced");
- }
- if (!is_selected()) {
- color.a *= 0.3;
- }
-
- Ref<SpatialMaterial> line_material;
- line_material.instance();
- line_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- line_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- if (p_use_vertex_color) {
- line_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- line_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+void EditorSpatialGizmo::set_hidden(bool p_hidden) {
+ hidden = p_hidden;
+ int layer = hidden ? 0 : 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER;
+ for (int i = 0; i < instances.size(); ++i) {
+ VS::get_singleton()->instance_set_layer_mask(instances[i].instance, layer);
}
-
- if (p_billboard) {
- line_material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
- }
-
- if (p_on_top && is_selected()) {
- line_material->set_on_top_of_alpha();
- }
-
- line_material->set_albedo(color);
-
- SpatialEditorGizmos::singleton->material_cache[name] = line_material;
-
- return line_material;
}
-Ref<SpatialMaterial> EditorSpatialGizmo::create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top, const Color &p_albedo) {
-
- String name = p_name;
-
- if (!is_editable()) {
- name += "@readonly";
- } else if (is_selected()) {
- name += "@selected";
- }
-
- if (SpatialEditorGizmos::singleton->material_cache.has(name)) {
- return SpatialEditorGizmos::singleton->material_cache[name];
- }
-
- Color color = p_albedo;
-
- if (!is_editable()) {
- color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced");
- } else if (!is_selected()) {
- color.a *= 0.3;
- }
-
- Ref<SpatialMaterial> icon;
- icon.instance();
- icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
- icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
- icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- icon->set_albedo(color);
- icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, p_texture);
- icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true);
- icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
-
- if (p_on_top && is_selected()) {
- icon->set_on_top_of_alpha();
- }
-
- SpatialEditorGizmos::singleton->material_cache[name] = icon;
-
- return icon;
+void EditorSpatialGizmo::set_plugin(EditorSpatialGizmoPlugin *p_plugin) {
+ gizmo_plugin = p_plugin;
}
void EditorSpatialGizmo::_bind_methods() {
@@ -726,6 +678,7 @@ void EditorSpatialGizmo::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_handles", "handles", "billboard", "secondary"), &EditorSpatialGizmo::add_handles, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_spatial_node", "node"), &EditorSpatialGizmo::_set_spatial_node);
ClassDB::bind_method(D_METHOD("clear"), &EditorSpatialGizmo::clear);
+ ClassDB::bind_method(D_METHOD("set_hidden", "hidden"), &EditorSpatialGizmo::set_hidden);
BIND_VMETHOD(MethodInfo("redraw"));
BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", PropertyInfo(Variant::INT, "index")));
@@ -743,12 +696,17 @@ void EditorSpatialGizmo::_bind_methods() {
EditorSpatialGizmo::EditorSpatialGizmo() {
valid = false;
billboard_handle = false;
+ hidden = false;
base = NULL;
+ selected = false;
+ instanced = false;
spatial_node = NULL;
+ gizmo_plugin = NULL;
}
EditorSpatialGizmo::~EditorSpatialGizmo() {
+ if (gizmo_plugin != NULL) gizmo_plugin->unregister_gizmo(this);
clear();
}
@@ -761,7 +719,30 @@ Vector3 EditorSpatialGizmo::get_handle_pos(int p_idx) const {
//// light gizmo
-String LightSpatialGizmo::get_handle_name(int p_idx) const {
+LightSpatialGizmoPlugin::LightSpatialGizmoPlugin() {
+
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/light", Color(1, 1, 0.2));
+
+ create_material("lines", gizmo_color);
+ create_material("lines_billboard", gizmo_color, true);
+
+ create_icon_material("light_directional_icon", SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons"));
+ create_icon_material("light_omni_icon", SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons"));
+ create_icon_material("light_spot_icon", SpatialEditor::get_singleton()->get_icon("GizmoSpotLight", "EditorIcons"));
+
+ create_handle_material("handles");
+ create_handle_material("handles_billboard", true);
+}
+
+bool LightSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<Light>(p_spatial) != NULL;
+}
+
+String LightSpatialGizmoPlugin::get_name() const {
+ return "Lights";
+}
+
+String LightSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
if (p_idx == 0)
return "Radius";
@@ -769,8 +750,9 @@ String LightSpatialGizmo::get_handle_name(int p_idx) const {
return "Aperture";
}
-Variant LightSpatialGizmo::get_handle_value(int p_idx) const {
+Variant LightSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+ Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node());
if (p_idx == 0)
return light->get_param(Light::PARAM_RANGE);
if (p_idx == 1)
@@ -808,8 +790,9 @@ static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vec
return a * 180.0 / Math_PI;
}
-void LightSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
+void LightSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+ Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node());
Transform gt = light->get_global_transform();
gt.orthonormalize();
Transform gi = gt.affine_inverse();
@@ -848,8 +831,9 @@ void LightSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_
}
}
-void LightSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
+void LightSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+ Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node());
if (p_cancel) {
light->set_param(p_idx == 0 ? Light::PARAM_RANGE : Light::PARAM_SPOT_ANGLE, p_restore);
@@ -871,14 +855,16 @@ void LightSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool
}
}
-void LightSpatialGizmo::redraw() {
+void LightSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node());
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/light");
+ p_gizmo->clear();
if (Object::cast_to<DirectionalLight>(light)) {
- Ref<Material> material = create_material("light_directional_material", gizmo_color);
- Ref<Material> icon = create_icon_material("light_directional_icon", SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons"));
+ Ref<Material> material = get_material("lines", p_gizmo);
+ Ref<Material> icon = get_material("light_directional_icon", p_gizmo);
const int arrow_points = 7;
const float arrow_length = 1.5;
@@ -909,16 +895,15 @@ void LightSpatialGizmo::redraw() {
}
}
- add_lines(lines, material);
- add_collision_segments(lines);
- add_unscaled_billboard(icon, 0.05);
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
}
if (Object::cast_to<OmniLight>(light)) {
- Ref<Material> material = create_material("light_omni_material", gizmo_color, true);
- Ref<Material> icon = create_icon_material("light_omni_icon", SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons"));
- clear();
+ Ref<Material> material = get_material("lines_billboard", p_gizmo);
+ Ref<Material> icon = get_material("light_omni_icon", p_gizmo);
OmniLight *on = Object::cast_to<OmniLight>(light);
@@ -941,29 +926,27 @@ void LightSpatialGizmo::redraw() {
points.push_back(Vector3(b.x, b.y, 0));
}
- add_lines(points, material, true);
- add_collision_segments(points);
+ p_gizmo->add_lines(points, material, true);
+ p_gizmo->add_collision_segments(points);
- add_unscaled_billboard(icon, 0.05);
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
Vector<Vector3> handles;
handles.push_back(Vector3(r, 0, 0));
- add_handles(handles, true);
+ p_gizmo->add_handles(handles, get_material("handles_billboard"), true);
}
if (Object::cast_to<SpotLight>(light)) {
- Ref<Material> material = create_material("light_spot_material", gizmo_color);
- Ref<Material> icon = create_icon_material("light_spot_icon", SpatialEditor::get_singleton()->get_icon("GizmoSpotLight", "EditorIcons"));
-
- clear();
+ Ref<Material> material = get_material("lines", p_gizmo);
+ Ref<Material> icon = get_material("light_spot_icon", p_gizmo);
Vector<Vector3> points;
- SpotLight *on = Object::cast_to<SpotLight>(light);
+ SpotLight *sl = Object::cast_to<SpotLight>(light);
- float r = on->get_param(Light::PARAM_RANGE);
- float w = r * Math::sin(Math::deg2rad(on->get_param(Light::PARAM_SPOT_ANGLE)));
- float d = r * Math::cos(Math::deg2rad(on->get_param(Light::PARAM_SPOT_ANGLE)));
+ float r = sl->get_param(Light::PARAM_RANGE);
+ float w = r * Math::sin(Math::deg2rad(sl->get_param(Light::PARAM_SPOT_ANGLE)));
+ float d = r * Math::cos(Math::deg2rad(sl->get_param(Light::PARAM_SPOT_ANGLE)));
for (int i = 0; i < 360; i++) {
@@ -985,7 +968,7 @@ void LightSpatialGizmo::redraw() {
points.push_back(Vector3(0, 0, -r));
points.push_back(Vector3());
- add_lines(points, material);
+ p_gizmo->add_lines(points, material);
Vector<Vector3> handles;
handles.push_back(Vector3(0, 0, -r));
@@ -1017,33 +1000,45 @@ void LightSpatialGizmo::redraw() {
collision_segments.push_back(Vector3(0, 0, -r));
collision_segments.push_back(Vector3());
- add_handles(handles);
- add_collision_segments(collision_segments);
- add_unscaled_billboard(icon, 0.05);
+ p_gizmo->add_handles(handles, get_material("handles"));
+ p_gizmo->add_collision_segments(collision_segments);
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
}
}
-LightSpatialGizmo::LightSpatialGizmo(Light *p_light) {
+//////
+
+//// player gizmo
+AudioStreamPlayer3DSpatialGizmoPlugin::AudioStreamPlayer3DSpatialGizmoPlugin() {
+
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1));
- light = p_light;
- set_spatial_node(p_light);
+ create_icon_material("stream_player_3d_icon", SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer", "EditorIcons"));
+ create_material("stream_player_3d_material", gizmo_color);
+ create_handle_material("handles");
}
-//////
+bool AudioStreamPlayer3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<AudioStreamPlayer3D>(p_spatial) != NULL;
+}
-//// player gizmo
+String AudioStreamPlayer3DSpatialGizmoPlugin::get_name() const {
+ return "AudioStreamPlayer3D";
+}
-String AudioStreamPlayer3DSpatialGizmo::get_handle_name(int p_idx) const {
+String AudioStreamPlayer3DSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
return "Emission Radius";
}
-Variant AudioStreamPlayer3DSpatialGizmo::get_handle_value(int p_idx) const {
-
+Variant AudioStreamPlayer3DSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+ AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
return player->get_emission_angle();
}
-void AudioStreamPlayer3DSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
+void AudioStreamPlayer3DSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+ AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
Transform gt = player->get_global_transform();
gt.orthonormalize();
@@ -1081,7 +1076,9 @@ void AudioStreamPlayer3DSpatialGizmo::set_handle(int p_idx, Camera *p_camera, co
}
}
-void AudioStreamPlayer3DSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
+void AudioStreamPlayer3DSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
if (p_cancel) {
@@ -1097,16 +1094,17 @@ void AudioStreamPlayer3DSpatialGizmo::commit_handle(int p_idx, const Variant &p_
}
}
-void AudioStreamPlayer3DSpatialGizmo::redraw() {
+void AudioStreamPlayer3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
- clear();
+ AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
- Ref<Material> icon = create_icon_material("stream_player_3d_material", SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer", "EditorIcons"));
+ Ref<Material> icon = get_material("stream_player_3d_icon", p_gizmo);
if (player->is_emission_angle_enabled()) {
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/stream_player_3d");
- Ref<Material> material = create_material("stream_player_3d_material", gizmo_color);
+ Ref<Material> material = get_material("stream_player_3d_material", p_gizmo);
float pc = player->get_emission_angle();
@@ -1138,27 +1136,40 @@ void AudioStreamPlayer3DSpatialGizmo::redraw() {
points.write[200 + i * 2 + 1] = Vector3();
}
- add_lines(points, material);
- add_collision_segments(points);
+ p_gizmo->add_lines(points, material);
+ p_gizmo->add_collision_segments(points);
Vector<Vector3> handles;
float ha = Math::deg2rad(player->get_emission_angle());
handles.push_back(Vector3(Math::sin(ha), 0, -Math::cos(ha)));
- add_handles(handles);
+ p_gizmo->add_handles(handles, get_material("handles"));
}
- add_unscaled_billboard(icon, 0.05);
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
}
-AudioStreamPlayer3DSpatialGizmo::AudioStreamPlayer3DSpatialGizmo(AudioStreamPlayer3D *p_player) {
+//////
+
+CameraSpatialGizmoPlugin::CameraSpatialGizmoPlugin() {
+
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8));
- player = p_player;
- set_spatial_node(p_player);
+ create_material("camera_material", gizmo_color);
+ create_icon_material("camera_icon", SpatialEditor::get_singleton()->get_icon("GizmoCamera", "EditorIcons"));
+ create_handle_material("handles");
}
-//////
+bool CameraSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<Camera>(p_spatial) != NULL;
+}
+
+String CameraSpatialGizmoPlugin::get_name() const {
+ return "Camera";
+}
-String CameraSpatialGizmo::get_handle_name(int p_idx) const {
+String CameraSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node());
if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) {
return "FOV";
@@ -1166,7 +1177,10 @@ String CameraSpatialGizmo::get_handle_name(int p_idx) const {
return "Size";
}
}
-Variant CameraSpatialGizmo::get_handle_value(int p_idx) const {
+
+Variant CameraSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node());
if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) {
return camera->get_fov();
@@ -1175,7 +1189,10 @@ Variant CameraSpatialGizmo::get_handle_value(int p_idx) const {
return camera->get_size();
}
}
-void CameraSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+void CameraSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+ Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node());
Transform gt = camera->get_global_transform();
gt.orthonormalize();
@@ -1201,7 +1218,10 @@ void CameraSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p
camera->set("size", d);
}
}
-void CameraSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
+
+void CameraSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node());
if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) {
@@ -1231,16 +1251,17 @@ void CameraSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool
}
}
-void CameraSpatialGizmo::redraw() {
+void CameraSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
- clear();
+ Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
Vector<Vector3> lines;
Vector<Vector3> handles;
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/camera");
- Ref<Material> material = create_material("camera_material", gizmo_color);
- Ref<Material> icon = create_icon_material("camera_icon", SpatialEditor::get_singleton()->get_icon("GizmoCamera", "EditorIcons"));
+ Ref<Material> material = get_material("camera_material", p_gizmo);
+ Ref<Material> icon = get_material("camera_icon", p_gizmo);
switch (camera->get_projection()) {
@@ -1310,71 +1331,81 @@ void CameraSpatialGizmo::redraw() {
} break;
}
- add_lines(lines, material);
- add_collision_segments(lines);
- add_unscaled_billboard(icon, 0.05);
- add_handles(handles);
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+ p_gizmo->add_handles(handles, get_material("handles"));
}
-CameraSpatialGizmo::CameraSpatialGizmo(Camera *p_camera) {
+//////
- camera = p_camera;
- set_spatial_node(camera);
+MeshInstanceSpatialGizmoPlugin::MeshInstanceSpatialGizmoPlugin() {
}
-//////
+bool MeshInstanceSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<MeshInstance>(p_spatial) != NULL && Object::cast_to<SoftBody>(p_spatial) == NULL;
+}
-bool MeshInstanceSpatialGizmo::can_draw() const {
- return true; //mesh can always draw (even though nothing is displayed)
+String MeshInstanceSpatialGizmoPlugin::get_name() const {
+ return "MeshInstance";
}
-void MeshInstanceSpatialGizmo::redraw() {
- clear();
+bool MeshInstanceSpatialGizmoPlugin::can_be_hidden() const {
+ return false;
+}
+
+void MeshInstanceSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ MeshInstance *mesh = Object::cast_to<MeshInstance>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
Ref<Mesh> m = mesh->get_mesh();
+
if (!m.is_valid())
return; //none
Ref<TriangleMesh> tm = m->generate_triangle_mesh();
if (tm.is_valid()) {
- add_collision_triangles(tm);
+ p_gizmo->add_collision_triangles(tm);
}
}
-MeshInstanceSpatialGizmo::MeshInstanceSpatialGizmo(MeshInstance *p_mesh) {
+/////
+Sprite3DSpatialGizmoPlugin::Sprite3DSpatialGizmoPlugin() {
+}
- mesh = p_mesh;
- set_spatial_node(p_mesh);
+bool Sprite3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<Sprite3D>(p_spatial) != NULL;
}
-/////
+String Sprite3DSpatialGizmoPlugin::get_name() const {
+ return "Sprite3D";
+}
-bool Sprite3DSpatialGizmo::can_draw() const {
- return true;
+bool Sprite3DSpatialGizmoPlugin::can_be_hidden() const {
+ return false;
}
-void Sprite3DSpatialGizmo::redraw() {
- clear();
+void Sprite3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ Sprite3D *sprite = Object::cast_to<Sprite3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
Ref<TriangleMesh> tm = sprite->generate_triangle_mesh();
if (tm.is_valid()) {
- add_collision_triangles(tm);
+ p_gizmo->add_collision_triangles(tm);
}
}
-Sprite3DSpatialGizmo::Sprite3DSpatialGizmo(SpriteBase3D *p_sprite) {
-
- sprite = p_sprite;
- set_spatial_node(p_sprite);
-}
-
///
-void Position3DSpatialGizmo::redraw() {
+Position3DSpatialGizmoPlugin::Position3DSpatialGizmoPlugin() {
+ pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ cursor_points = Vector<Vector3>();
- clear();
- add_mesh(SpatialEditorGizmos::singleton->pos3d_mesh);
- Vector<Vector3> cursor_points;
+ PoolVector<Color> cursor_colors;
float cs = 0.25;
cursor_points.push_back(Vector3(+cs, 0, 0));
cursor_points.push_back(Vector3(-cs, 0, 0));
@@ -1382,23 +1413,65 @@ void Position3DSpatialGizmo::redraw() {
cursor_points.push_back(Vector3(0, -cs, 0));
cursor_points.push_back(Vector3(0, 0, +cs));
cursor_points.push_back(Vector3(0, 0, -cs));
- add_collision_segments(cursor_points);
+ cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7));
+ cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7));
+ cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7));
+ cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7));
+ cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7));
+ cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7));
+
+ Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
+ mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+ mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+ mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ mat->set_line_width(3);
+ Array d;
+ d.resize(VS::ARRAY_MAX);
+ d[Mesh::ARRAY_VERTEX] = cursor_points;
+ d[Mesh::ARRAY_COLOR] = cursor_colors;
+ pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d);
+ pos3d_mesh->surface_set_material(0, mat);
}
-Position3DSpatialGizmo::Position3DSpatialGizmo(Position3D *p_p3d) {
+bool Position3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<Position3D>(p_spatial) != NULL;
+}
+
+String Position3DSpatialGizmoPlugin::get_name() const {
+ return "Position3D";
+}
+
+void Position3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
- p3d = p_p3d;
- set_spatial_node(p3d);
+ p_gizmo->clear();
+ p_gizmo->add_mesh(pos3d_mesh);
+ p_gizmo->add_collision_segments(cursor_points);
}
/////
-void SkeletonSpatialGizmo::redraw() {
+SkeletonSpatialGizmoPlugin::SkeletonSpatialGizmoPlugin() {
- clear();
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
+ create_material("skeleton_material", gizmo_color);
+}
+
+bool SkeletonSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<Skeleton>(p_spatial) != NULL;
+}
+
+String SkeletonSpatialGizmoPlugin::get_name() const {
+ return "Skeleton";
+}
+
+void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ Skeleton *skel = Object::cast_to<Skeleton>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/skeleton");
- Ref<Material> material = create_material("skeleton_material", gizmo_color);
+ Ref<Material> material = get_material("skeleton_material", p_gizmo);
SpatialMaterial *sm = Object::cast_to<SpatialMaterial>(material.ptr());
{ // Reset
@@ -1452,7 +1525,9 @@ void SkeletonSpatialGizmo::redraw() {
Color bonecolor = Color(1.0, 0.4, 0.4, 0.3);
Color rootcolor = Color(0.4, 1.0, 0.4, 0.1);
- for (int i = 0; i < skel->get_bone_count(); i++) {
+ for (int i_bone = 0; i_bone < skel->get_bone_count(); i_bone++) {
+
+ int i = skel->get_process_order(i_bone);
int parent = skel->get_bone_parent(i);
@@ -1604,24 +1679,28 @@ void SkeletonSpatialGizmo::redraw() {
}
Ref<ArrayMesh> m = surface_tool->commit();
- add_mesh(m, false, skel->get_skeleton());
+ p_gizmo->add_mesh(m, false, skel->get_skeleton());
}
-SkeletonSpatialGizmo::SkeletonSpatialGizmo(Skeleton *p_skel) {
+////
+
+PhysicalBoneSpatialGizmoPlugin::PhysicalBoneSpatialGizmoPlugin() {
+ create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)));
+}
- skel = p_skel;
- set_spatial_node(p_skel);
+bool PhysicalBoneSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<PhysicalBone>(p_spatial) != NULL;
}
-PhysicalBoneSpatialGizmo::PhysicalBoneSpatialGizmo(PhysicalBone *p_pb) :
- EditorSpatialGizmo(),
- physical_bone(p_pb) {
- set_spatial_node(p_pb);
+String PhysicalBoneSpatialGizmoPlugin::get_name() const {
+ return "PhysicalBones";
}
-void PhysicalBoneSpatialGizmo::redraw() {
+void PhysicalBoneSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
- clear();
+ p_gizmo->clear();
+
+ PhysicalBone *physical_bone = Object::cast_to<PhysicalBone>(p_gizmo->get_spatial_node());
if (!physical_bone)
return;
@@ -1635,26 +1714,25 @@ void PhysicalBoneSpatialGizmo::redraw() {
switch (physical_bone->get_joint_type()) {
case PhysicalBone::JOINT_TYPE_PIN: {
- PinJointSpatialGizmo::CreateGizmo(physical_bone->get_joint_offset(), points);
+ JointSpatialGizmoPlugin::CreatePinJointGizmo(physical_bone->get_joint_offset(), points);
} break;
case PhysicalBone::JOINT_TYPE_CONE: {
const PhysicalBone::ConeJointData *cjd(static_cast<const PhysicalBone::ConeJointData *>(physical_bone->get_joint_data()));
- ConeTwistJointSpatialGizmo::CreateGizmo(
+ JointSpatialGizmoPlugin::CreateConeTwistJointGizmo(
physical_bone->get_joint_offset(),
physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
pb ? pb->get_global_transform() : Transform(),
pbp ? pbp->get_global_transform() : Transform(),
cjd->swing_span,
cjd->twist_span,
- points,
pb ? &points : NULL,
pbp ? &points : NULL);
} break;
case PhysicalBone::JOINT_TYPE_HINGE: {
const PhysicalBone::HingeJointData *hjd(static_cast<const PhysicalBone::HingeJointData *>(physical_bone->get_joint_data()));
- HingeJointSpatialGizmo::CreateGizmo(
+ JointSpatialGizmoPlugin::CreateHingeJointGizmo(
physical_bone->get_joint_offset(),
physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
pb ? pb->get_global_transform() : Transform(),
@@ -1669,7 +1747,7 @@ void PhysicalBoneSpatialGizmo::redraw() {
case PhysicalBone::JOINT_TYPE_SLIDER: {
const PhysicalBone::SliderJointData *sjd(static_cast<const PhysicalBone::SliderJointData *>(physical_bone->get_joint_data()));
- SliderJointSpatialGizmo::CreateGizmo(
+ JointSpatialGizmoPlugin::CreateSliderJointGizmo(
physical_bone->get_joint_offset(),
physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
pb ? pb->get_global_transform() : Transform(),
@@ -1685,7 +1763,7 @@ void PhysicalBoneSpatialGizmo::redraw() {
case PhysicalBone::JOINT_TYPE_6DOF: {
const PhysicalBone::SixDOFJointData *sdofjd(static_cast<const PhysicalBone::SixDOFJointData *>(physical_bone->get_joint_data()));
- Generic6DOFJointSpatialGizmo::CreateGizmo(
+ JointSpatialGizmoPlugin::CreateGeneric6DOFJointGizmo(
physical_bone->get_joint_offset(),
physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
@@ -1721,14 +1799,15 @@ void PhysicalBoneSpatialGizmo::redraw() {
return;
}
- Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
+ Ref<Material> material = get_material("joint_material", p_gizmo);
- add_collision_segments(points);
- add_lines(points, material);
+ p_gizmo->add_collision_segments(points);
+ p_gizmo->add_lines(points, material);
}
// FIXME: Kept as reference for reimplementation in 3.1+
#if 0
+
void RoomSpatialGizmo::redraw() {
clear();
@@ -1745,41 +1824,41 @@ void RoomSpatialGizmo::redraw() {
for (int i = 0; i < fc; i++) {
- Vector3 fn = r[i].get_plane().normal;
+ Vector3 fn = r[i].get_plane().normal;
- for (int j = 0; j < 3; j++) {
+ for (int j = 0; j < 3; j++) {
- _EdgeKey ek;
- ek.from = r[i].vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
- ek.to = r[i].vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
- if (ek.from < ek.to)
- SWAP(ek.from, ek.to);
+ _EdgeKey ek;
+ ek.from = r[i].vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
+ ek.to = r[i].vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
+ if (ek.from < ek.to)
+ SWAP(ek.from, ek.to);
- Map<_EdgeKey, Vector3>::Element *E = edge_map.find(ek);
+ Map<_EdgeKey, Vector3>::Element *E = edge_map.find(ek);
- if (E) {
+ if (E) {
- if (E->get().dot(fn) > 0.9) {
+ if (E->get().dot(fn) > 0.9) {
- E->get() = Vector3();
- }
+ E->get() = Vector3();
+ }
- } else {
+ } else {
- edge_map[ek] = fn;
- }
+ edge_map[ek] = fn;
+ }
+ }
}
- }
for (Map<_EdgeKey, Vector3>::Element *E = edge_map.front(); E; E = E->next()) {
- if (E->get() != Vector3()) {
- lines.push_back(E->key().from);
- lines.push_back(E->key().to);
+ if (E->get() != Vector3()) {
+ lines.push_back(E->key().from);
+ lines.push_back(E->key().to);
+ }
}
- }
- add_lines(lines, SpatialEditorGizmos::singleton->room_material);
+ add_lines(lines, EditorSpatialGizmos::singleton->room_material);
add_collision_segments(lines);
}
@@ -1797,31 +1876,31 @@ void PortalSpatialGizmo::redraw() {
Vector<Point2> points = portal->get_shape();
if (points.size() == 0) {
- return;
- }
+ return;
+ }
Vector<Vector3> lines;
Vector3 center;
for (int i = 0; i < points.size(); i++) {
- Vector3 f;
- f.x = points[i].x;
- f.y = points[i].y;
- Vector3 fn;
- fn.x = points[(i + 1) % points.size()].x;
- fn.y = points[(i + 1) % points.size()].y;
- center += f;
+ Vector3 f;
+ f.x = points[i].x;
+ f.y = points[i].y;
+ Vector3 fn;
+ fn.x = points[(i + 1) % points.size()].x;
+ fn.y = points[(i + 1) % points.size()].y;
+ center += f;
- lines.push_back(f);
- lines.push_back(fn);
- }
+ lines.push_back(f);
+ lines.push_back(fn);
+ }
center /= points.size();
lines.push_back(center);
lines.push_back(center + Vector3(0, 0, 1));
- add_lines(lines, SpatialEditorGizmos::singleton->portal_material);
+ add_lines(lines, EditorSpatialGizmos::singleton->portal_material);
add_collision_segments(lines);
}
@@ -1834,33 +1913,58 @@ PortalSpatialGizmo::PortalSpatialGizmo(Portal *p_portal) {
#endif
/////
-void RayCastSpatialGizmo::redraw() {
+RayCastSpatialGizmoPlugin::RayCastSpatialGizmoPlugin() {
- clear();
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ create_material("shape_material", gizmo_color);
+}
+
+bool RayCastSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<RayCast>(p_spatial) != NULL;
+}
+
+String RayCastSpatialGizmoPlugin::get_name() const {
+ return "RayCast";
+}
+
+void RayCastSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ RayCast *raycast = Object::cast_to<RayCast>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
Vector<Vector3> lines;
lines.push_back(Vector3());
lines.push_back(raycast->get_cast_to());
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
- Ref<Material> material = create_material("shape_material", gizmo_color);
+ Ref<SpatialMaterial> material = get_material("shape_material", p_gizmo);
- add_lines(lines, material);
- add_collision_segments(lines);
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
}
-RayCastSpatialGizmo::RayCastSpatialGizmo(RayCast *p_raycast) {
+/////
+
+VehicleWheelSpatialGizmoPlugin::VehicleWheelSpatialGizmoPlugin() {
- set_spatial_node(p_raycast);
- raycast = p_raycast;
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ create_material("shape_material", gizmo_color);
}
-/////
+bool VehicleWheelSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<VehicleWheel>(p_spatial) != NULL;
+}
-void VehicleWheelSpatialGizmo::redraw() {
+String VehicleWheelSpatialGizmoPlugin::get_name() const {
+ return "VehicleWheel";
+}
- clear();
+void VehicleWheelSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ VehicleWheel *car_wheel = Object::cast_to<VehicleWheel>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
Vector<Vector3> points;
@@ -1904,23 +2008,36 @@ void VehicleWheelSpatialGizmo::redraw() {
points.push_back(Vector3(0, -r, r * 2));
points.push_back(Vector3(-r * 2 * 0.2, -r, r * 2 * 0.8));
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
- Ref<Material> material = create_material("shape_material", gizmo_color);
+ Ref<Material> material = get_material("shape_material", p_gizmo);
- add_lines(points, material);
- add_collision_segments(points);
+ p_gizmo->add_lines(points, material);
+ p_gizmo->add_collision_segments(points);
}
-VehicleWheelSpatialGizmo::VehicleWheelSpatialGizmo(VehicleWheel *p_car_wheel) {
+///////////
- set_spatial_node(p_car_wheel);
- car_wheel = p_car_wheel;
+SoftBodySpatialGizmoPlugin::SoftBodySpatialGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ create_material("shape_material", gizmo_color);
+ create_handle_material("handles");
}
-///////////
+bool SoftBodySpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<SoftBody>(p_spatial) != NULL;
+}
-void SoftBodySpatialGizmo::redraw() {
- clear();
+String SoftBodySpatialGizmoPlugin::get_name() const {
+ return "SoftBody";
+}
+
+bool SoftBodySpatialGizmoPlugin::is_selectable_when_hidden() const {
+ return true;
+}
+
+void SoftBodySpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+ SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
if (!soft_body || soft_body->get_mesh().is_null()) {
return;
@@ -1936,84 +2053,840 @@ void SoftBodySpatialGizmo::redraw() {
return;
}
+ Ref<TriangleMesh> tm = soft_body->get_mesh()->generate_triangle_mesh();
+
Vector<Vector3> points;
soft_body->get_mesh()->generate_debug_mesh_indices(points);
-
soft_body->get_mesh()->clear_cache();
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
- Ref<Material> material = create_material("shape_material", gizmo_color);
+ Ref<Material> material = get_material("shape_material", p_gizmo);
- add_lines(lines, material);
- add_collision_segments(lines);
- add_handles(points);
-}
-
-bool SoftBodySpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) {
- return EditorSpatialGizmo::intersect_ray(p_camera, p_point, r_pos, r_normal, r_gizmo_handle, p_sec_first);
-
- /* Perform a shape cast but doesn't work with softbody
- PhysicsDirectSpaceState *space_state = PhysicsServer::get_singleton()->space_get_direct_state(SceneTree::get_singleton()->get_root()->get_world()->get_space());
- if (!physics_sphere_shape.is_valid()) {
- physics_sphere_shape = PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_SPHERE);
- real_t radius = 0.02;
- PhysicsServer::get_singleton()->shape_set_data(physics_sphere_shape, radius);
- }
-
- Vector3 sphere_motion(p_camera->project_ray_normal(p_point));
- real_t closest_safe;
- real_t closest_unsafe;
- PhysicsDirectSpaceState::ShapeRestInfo result;
- bool collided = space_state->cast_motion(
- physics_sphere_shape,
- p_camera->get_transform(),
- sphere_motion * Vector3(1000, 1000, 1000),
- 0.f,
- closest_safe,
- closest_unsafe,
- Set<RID>(),
- 0xFFFFFFFF,
- 0xFFFFFFFF,
- &result);
-
- if (collided) {
-
- if (result.collider_id == soft_body->get_instance_id()) {
- print_line("Collided");
- } else {
- print_line("Collided but with wrong object: " + itos(result.collider_id));
- }
- } else {
- print_line("Not collided, motion: x: " + rtos(sphere_motion[0]) + " y: " + rtos(sphere_motion[1]) + " z: " + rtos(sphere_motion[2]));
- }
- return false;
- */
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+ p_gizmo->add_handles(points, get_material("handles"));
+ p_gizmo->add_collision_triangles(tm);
+}
+
+String SoftBodySpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
+ return "SoftBody pin point";
+}
+
+Variant SoftBodySpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+ SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node());
+ return Variant(soft_body->is_point_pinned(p_idx));
}
-void SoftBodySpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
+void SoftBodySpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+ SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node());
soft_body->pin_point_toggle(p_idx);
- redraw();
}
-bool SoftBodySpatialGizmo::is_gizmo_handle_highlighted(int idx) const {
+bool SoftBodySpatialGizmoPlugin::is_gizmo_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const {
+ SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node());
return soft_body->is_point_pinned(idx);
}
-SoftBodySpatialGizmo::SoftBodySpatialGizmo(SoftBody *p_soft_physics_body) :
- EditorSpatialGizmo(),
- soft_body(p_soft_physics_body) {
- set_spatial_node(p_soft_physics_body);
+///////////
+
+VisibilityNotifierGizmoPlugin::VisibilityNotifierGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7));
+ create_material("visibility_notifier_material", gizmo_color);
+ gizmo_color.a = 0.1;
+ create_material("visibility_notifier_solid_material", gizmo_color);
+ create_handle_material("handles");
}
-SoftBodySpatialGizmo::~SoftBodySpatialGizmo() {
- //if (!physics_sphere_shape.is_valid()) {
- // PhysicsServer::get_singleton()->free(physics_sphere_shape);
- //}
+bool VisibilityNotifierGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<VisibilityNotifier>(p_spatial) != NULL;
}
-///////////
+String VisibilityNotifierGizmoPlugin::get_name() const {
+ return "VisibilityNotifier";
+}
+
+String VisibilityNotifierGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ switch (p_idx) {
+ case 0: return "Size X";
+ case 1: return "Size Y";
+ case 2: return "Size Z";
+ case 3: return "Pos X";
+ case 4: return "Pos Y";
+ case 5: return "Pos Z";
+ }
+
+ return "";
+}
+
+Variant VisibilityNotifierGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node());
+ return notifier->get_aabb();
+}
+void VisibilityNotifierGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+ VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node());
+
+ Transform gt = notifier->get_global_transform();
+
+ Transform gi = gt.affine_inverse();
+
+ bool move = p_idx >= 3;
+ p_idx = p_idx % 3;
+
+ AABB aabb = notifier->get_aabb();
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
+
+ Vector3 ofs = aabb.position + aabb.size * 0.5;
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ if (move) {
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb);
+
+ float d = ra[p_idx];
+
+ aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5;
+ notifier->set_aabb(aabb);
+
+ } else {
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb);
+
+ float d = ra[p_idx] - ofs[p_idx];
+ if (d < 0.001)
+ d = 0.001;
+ //resize
+ aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d;
+ aabb.size[p_idx] = d * 2;
+ notifier->set_aabb(aabb);
+ }
+}
+
+void VisibilityNotifierGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node());
+
+ if (p_cancel) {
+ notifier->set_aabb(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Notifier AABB"));
+ ur->add_do_method(notifier, "set_aabb", notifier->get_aabb());
+ ur->add_undo_method(notifier, "set_aabb", p_restore);
+ ur->commit_action();
+}
+
+void VisibilityNotifierGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ AABB aabb = notifier->get_aabb();
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
+ ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
+ handles.push_back(ax);
+ }
+
+ Vector3 center = aabb.position + aabb.size * 0.5;
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = 1.0;
+ handles.push_back(center + ax);
+ lines.push_back(center);
+ lines.push_back(center + ax);
+ }
+
+ Ref<Material> material = get_material("visibility_notifier_material", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+
+ if (p_gizmo->is_selected()) {
+ Ref<Material> solid_material = get_material("visibility_notifier_solid_material", p_gizmo);
+ p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
+ }
+
+ p_gizmo->add_handles(handles, get_material("handles"));
+}
+
+////
+
+ParticlesGizmoPlugin::ParticlesGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4));
+ create_material("particles_material", gizmo_color);
+ gizmo_color.a = 0.1;
+ create_material("particles_solid_material", gizmo_color);
+ create_icon_material("particles_icon", SpatialEditor::get_singleton()->get_icon("GizmoParticles", "EditorIcons"));
+ create_handle_material("handles");
+}
+
+bool ParticlesGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<Particles>(p_spatial) != NULL;
+}
+
+String ParticlesGizmoPlugin::get_name() const {
+ return "Particles";
+}
+
+bool ParticlesGizmoPlugin::is_selectable_when_hidden() const {
+ return true;
+}
+
+String ParticlesGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ switch (p_idx) {
+ case 0: return "Size X";
+ case 1: return "Size Y";
+ case 2: return "Size Z";
+ case 3: return "Pos X";
+ case 4: return "Pos Y";
+ case 5: return "Pos Z";
+ }
+
+ return "";
+}
+Variant ParticlesGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node());
+ return particles->get_visibility_aabb();
+}
+void ParticlesGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+ Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node());
+
+ Transform gt = particles->get_global_transform();
+ //gt.orthonormalize();
+ Transform gi = gt.affine_inverse();
+
+ bool move = p_idx >= 3;
+ p_idx = p_idx % 3;
+
+ AABB aabb = particles->get_visibility_aabb();
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
+
+ Vector3 ofs = aabb.position + aabb.size * 0.5;
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ if (move) {
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb);
+
+ float d = ra[p_idx];
+
+ aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5;
+ particles->set_visibility_aabb(aabb);
+
+ } else {
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb);
+
+ float d = ra[p_idx] - ofs[p_idx];
+ if (d < 0.001)
+ d = 0.001;
+ //resize
+ aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d;
+ aabb.size[p_idx] = d * 2;
+ particles->set_visibility_aabb(aabb);
+ }
+}
+
+void ParticlesGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node());
+
+ if (p_cancel) {
+ particles->set_visibility_aabb(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Particles AABB"));
+ ur->add_do_method(particles, "set_custom_aabb", particles->get_visibility_aabb());
+ ur->add_undo_method(particles, "set_custom_aabb", p_restore);
+ ur->commit_action();
+}
+
+void ParticlesGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ AABB aabb = particles->get_visibility_aabb();
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
+ ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
+ handles.push_back(ax);
+ }
+
+ Vector3 center = aabb.position + aabb.size * 0.5;
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = 1.0;
+ handles.push_back(center + ax);
+ lines.push_back(center);
+ lines.push_back(center + ax);
+ }
+
+ Ref<Material> material = get_material("particles_material", p_gizmo);
+ Ref<Material> icon = get_material("particles_icon", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+
+ if (p_gizmo->is_selected()) {
+ Ref<Material> solid_material = get_material("particles_solid_material", p_gizmo);
+ p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
+ }
+
+ p_gizmo->add_handles(handles, get_material("handles"));
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+}
+////
+
+ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5));
+
+ create_material("reflection_probe_material", gizmo_color);
+
+ gizmo_color.a = 0.5;
+ create_material("reflection_internal_material", gizmo_color);
+
+ gizmo_color.a = 0.1;
+ create_material("reflection_probe_solid_material", gizmo_color);
+
+ create_icon_material("reflection_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoReflectionProbe", "EditorIcons"));
+ create_handle_material("handles");
+}
+
+bool ReflectionProbeGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<ReflectionProbe>(p_spatial) != NULL;
+}
+
+String ReflectionProbeGizmoPlugin::get_name() const {
+ return "ReflectionProbe";
+}
+
+String ReflectionProbeGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ switch (p_idx) {
+ case 0: return "Extents X";
+ case 1: return "Extents Y";
+ case 2: return "Extents Z";
+ case 3: return "Origin X";
+ case 4: return "Origin Y";
+ case 5: return "Origin Z";
+ }
+
+ return "";
+}
+Variant ReflectionProbeGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+ return AABB(probe->get_extents(), probe->get_origin_offset());
+}
+void ReflectionProbeGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+ Transform gt = probe->get_global_transform();
+
+ Transform gi = gt.affine_inverse();
+
+ if (p_idx < 3) {
+ Vector3 extents = probe->get_extents();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
+ float d = ra[p_idx];
+ if (d < 0.001)
+ d = 0.001;
+
+ extents[p_idx] = d;
+ probe->set_extents(extents);
+ } else {
+
+ p_idx -= 3;
+
+ Vector3 origin = probe->get_origin_offset();
+ origin[p_idx] = 0;
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(origin - axis * 16384, origin + axis * 16384, sg[0], sg[1], ra, rb);
+ float d = ra[p_idx];
+ d += 0.25;
+
+ origin[p_idx] = d;
+ probe->set_origin_offset(origin);
+ }
+}
+
+void ReflectionProbeGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+
+ AABB restore = p_restore;
+
+ if (p_cancel) {
+ probe->set_extents(restore.position);
+ probe->set_origin_offset(restore.size);
+ return;
+ }
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Probe Extents"));
+ ur->add_do_method(probe, "set_extents", probe->get_extents());
+ ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset());
+ ur->add_undo_method(probe, "set_extents", restore.position);
+ ur->add_undo_method(probe, "set_origin_offset", restore.size);
+ ur->commit_action();
+}
+
+void ReflectionProbeGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ Vector<Vector3> internal_lines;
+ Vector3 extents = probe->get_extents();
+
+ AABB aabb;
+ aabb.position = -extents;
+ aabb.size = extents * 2;
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ for (int i = 0; i < 8; i++) {
+ Vector3 ep = aabb.get_endpoint(i);
+ internal_lines.push_back(probe->get_origin_offset());
+ internal_lines.push_back(ep);
+ }
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ handles.push_back(ax);
+ }
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 orig_handle = probe->get_origin_offset();
+ orig_handle[i] -= 0.25;
+ lines.push_back(orig_handle);
+ handles.push_back(orig_handle);
+
+ orig_handle[i] += 0.5;
+ lines.push_back(orig_handle);
+ }
+
+ Ref<Material> material = get_material("reflection_probe_material", p_gizmo);
+ Ref<Material> material_internal = get_material("reflection_internal_material", p_gizmo);
+ Ref<Material> icon = get_material("reflection_probe_icon", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_lines(internal_lines, material_internal);
+
+ if (p_gizmo->is_selected()) {
+ Ref<Material> solid_material = get_material("reflection_probe_solid_material", p_gizmo);
+ p_gizmo->add_solid_box(solid_material, probe->get_extents() * 2.0);
+ }
+
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+ p_gizmo->add_collision_segments(lines);
+ p_gizmo->add_handles(handles, get_material("handles"));
+}
+
+GIProbeGizmoPlugin::GIProbeGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6));
+
+ create_material("gi_probe_material", gizmo_color);
+
+ gizmo_color.a = 0.5;
+ create_material("gi_probe_internal_material", gizmo_color);
+
+ gizmo_color.a = 0.1;
+ create_material("gi_probe_solid_material", gizmo_color);
+
+ create_icon_material("gi_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoGIProbe", "EditorIcons"));
+ create_handle_material("handles");
+}
+
+bool GIProbeGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<GIProbe>(p_spatial) != NULL;
+}
+
+String GIProbeGizmoPlugin::get_name() const {
+ return "GIProbe";
+}
+
+String GIProbeGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ switch (p_idx) {
+ case 0: return "Extents X";
+ case 1: return "Extents Y";
+ case 2: return "Extents Z";
+ }
+
+ return "";
+}
+Variant GIProbeGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
+ return probe->get_extents();
+}
+void GIProbeGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+ GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
-String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const {
+ Transform gt = probe->get_global_transform();
+ //gt.orthonormalize();
+ Transform gi = gt.affine_inverse();
+
+ Vector3 extents = probe->get_extents();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
+ float d = ra[p_idx];
+ if (d < 0.001)
+ d = 0.001;
+
+ extents[p_idx] = d;
+ probe->set_extents(extents);
+}
+
+void GIProbeGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
+
+ Vector3 restore = p_restore;
+
+ if (p_cancel) {
+ probe->set_extents(restore);
+ return;
+ }
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Probe Extents"));
+ ur->add_do_method(probe, "set_extents", probe->get_extents());
+ ur->add_undo_method(probe, "set_extents", restore);
+ ur->commit_action();
+}
+
+void GIProbeGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
+
+ Ref<Material> material = get_material("gi_probe_material", p_gizmo);
+ Ref<Material> icon = get_material("gi_probe_icon", p_gizmo);
+ Ref<Material> material_internal = get_material("gi_probe_internal_material", p_gizmo);
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ Vector3 extents = probe->get_extents();
+
+ static const int subdivs[GIProbe::SUBDIV_MAX] = { 64, 128, 256, 512 };
+
+ AABB aabb = AABB(-extents, extents * 2);
+ int subdiv = subdivs[probe->get_subdiv()];
+ float cell_size = aabb.get_longest_axis_size() / subdiv;
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+
+ lines.clear();
+
+ for (int i = 1; i < subdiv; i++) {
+
+ for (int j = 0; j < 3; j++) {
+
+ if (cell_size * i > aabb.size[j]) {
+ continue;
+ }
+
+ Vector2 dir;
+ dir[j] = 1.0;
+ Vector2 ta, tb;
+ int j_n1 = (j + 1) % 3;
+ int j_n2 = (j + 2) % 3;
+ ta[j_n1] = 1.0;
+ tb[j_n2] = 1.0;
+
+ for (int k = 0; k < 4; k++) {
+
+ Vector3 from = aabb.position, to = aabb.position;
+ from[j] += cell_size * i;
+ to[j] += cell_size * i;
+
+ if (k & 1) {
+ to[j_n1] += aabb.size[j_n1];
+ } else {
+
+ to[j_n2] += aabb.size[j_n2];
+ }
+
+ if (k & 2) {
+ from[j_n1] += aabb.size[j_n1];
+ from[j_n2] += aabb.size[j_n2];
+ }
+
+ lines.push_back(from);
+ lines.push_back(to);
+ }
+ }
+ }
+
+ p_gizmo->add_lines(lines, material_internal);
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ handles.push_back(ax);
+ }
+
+ if (p_gizmo->is_selected()) {
+ Ref<Material> solid_material = get_material("gi_probe_solid_material", p_gizmo);
+ p_gizmo->add_solid_box(solid_material, aabb.get_size());
+ }
+
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+ p_gizmo->add_handles(handles, get_material("handles"));
+}
+
+////
+
+BakedIndirectLightGizmoPlugin::BakedIndirectLightGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1));
+
+ create_material("baked_indirect_light_material", gizmo_color);
+
+ gizmo_color.a = 0.1;
+ create_material("baked_indirect_light_internal_material", gizmo_color);
+
+ create_icon_material("baked_indirect_light_icon", SpatialEditor::get_singleton()->get_icon("GizmoBakedLightmap", "EditorIcons"));
+ create_handle_material("handles");
+}
+
+String BakedIndirectLightGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ switch (p_idx) {
+ case 0: return "Extents X";
+ case 1: return "Extents Y";
+ case 2: return "Extents Z";
+ }
+
+ return "";
+}
+Variant BakedIndirectLightGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
+ return baker->get_extents();
+}
+void BakedIndirectLightGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+ BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
+
+ Transform gt = baker->get_global_transform();
+ //gt.orthonormalize();
+ Transform gi = gt.affine_inverse();
+
+ Vector3 extents = baker->get_extents();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
+ float d = ra[p_idx];
+ if (d < 0.001)
+ d = 0.001;
+
+ extents[p_idx] = d;
+ baker->set_extents(extents);
+}
+
+void BakedIndirectLightGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
+
+ Vector3 restore = p_restore;
+
+ if (p_cancel) {
+ baker->set_extents(restore);
+ return;
+ }
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Probe Extents"));
+ ur->add_do_method(baker, "set_extents", baker->get_extents());
+ ur->add_undo_method(baker, "set_extents", restore);
+ ur->commit_action();
+}
+
+bool BakedIndirectLightGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<BakedLightmap>(p_spatial) != NULL;
+}
+
+String BakedIndirectLightGizmoPlugin::get_name() const {
+ return "BakedLightmap";
+}
+
+void BakedIndirectLightGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
+
+ Ref<Material> material = get_material("baked_indirect_light_material", p_gizmo);
+ Ref<Material> icon = get_material("baked_indirect_light_icon", p_gizmo);
+ Ref<Material> material_internal = get_material("baked_indirect_light_internal_material", p_gizmo);
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ Vector3 extents = baker->get_extents();
+
+ AABB aabb = AABB(-extents, extents * 2);
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ handles.push_back(ax);
+ }
+
+ if (p_gizmo->is_selected()) {
+ p_gizmo->add_solid_box(material_internal, aabb.get_size());
+ }
+
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+ p_gizmo->add_handles(handles, get_material("handles"));
+}
+
+////
+
+CollisionShapeSpatialGizmoPlugin::CollisionShapeSpatialGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ create_material("shape_material", gizmo_color);
+ create_handle_material("handles");
+}
+
+bool CollisionShapeSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<CollisionShape>(p_spatial) != NULL;
+}
+
+String CollisionShapeSpatialGizmoPlugin::get_name() const {
+ return "CollisionShape";
+}
+
+String CollisionShapeSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ const CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node());
Ref<Shape> s = cs->get_shape();
if (s.is_null())
@@ -2046,7 +2919,10 @@ String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const {
return "";
}
-Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const {
+
+Variant CollisionShapeSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node());
Ref<Shape> s = cs->get_shape();
if (s.is_null())
@@ -2084,7 +2960,10 @@ Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const {
return Variant();
}
-void CollisionShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
+void CollisionShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+ CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node());
+
Ref<Shape> s = cs->get_shape();
if (s.is_null())
return;
@@ -2175,7 +3054,10 @@ void CollisionShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const P
cs->set_height(d * 2.0);
}
}
-void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
+void CollisionShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node());
+
Ref<Shape> s = cs->get_shape();
if (s.is_null())
return;
@@ -2252,7 +3134,11 @@ void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_resto
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
} else {
- ur->create_action(TTR("Change Cylinder Shape Height"));
+ ur->create_action(
+ ///
+
+ ////////
+ TTR("Change Cylinder Shape Height"));
ur->add_do_method(ss.ptr(), "set_height", ss->get_height());
ur->add_undo_method(ss.ptr(), "set_height", p_restore);
}
@@ -2275,16 +3161,18 @@ void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_resto
ur->commit_action();
}
}
-void CollisionShapeSpatialGizmo::redraw() {
+void CollisionShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
- clear();
+ CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
Ref<Shape> s = cs->get_shape();
if (s.is_null())
return;
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
- Ref<Material> material = create_material("shape_material", gizmo_color);
+ Ref<Material> material = get_material("shape_material", p_gizmo);
+ Ref<Material> handles_material = get_material("handles");
if (Object::cast_to<SphereShape>(*s)) {
@@ -2325,11 +3213,11 @@ void CollisionShapeSpatialGizmo::redraw() {
collision_segments.push_back(Vector3(b.x, b.y, 0));
}
- add_lines(points, material);
- add_collision_segments(collision_segments);
+ p_gizmo->add_lines(points, material);
+ p_gizmo->add_collision_segments(collision_segments);
Vector<Vector3> handles;
handles.push_back(Vector3(r, 0, 0));
- add_handles(handles);
+ p_gizmo->add_handles(handles, handles_material);
}
if (Object::cast_to<BoxShape>(*s)) {
@@ -2356,9 +3244,9 @@ void CollisionShapeSpatialGizmo::redraw() {
handles.push_back(ax);
}
- add_lines(lines, material);
- add_collision_segments(lines);
- add_handles(handles);
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+ p_gizmo->add_handles(handles, handles_material);
}
if (Object::cast_to<CapsuleShape>(*s)) {
@@ -2397,7 +3285,7 @@ void CollisionShapeSpatialGizmo::redraw() {
points.push_back(Vector3(b.y, 0, b.x) + dud);
}
- add_lines(points, material);
+ p_gizmo->add_lines(points, material);
Vector<Vector3> collision_segments;
@@ -2428,12 +3316,12 @@ void CollisionShapeSpatialGizmo::redraw() {
collision_segments.push_back(Vector3(b.y, 0, b.x) + dud);
}
- add_collision_segments(collision_segments);
+ p_gizmo->add_collision_segments(collision_segments);
Vector<Vector3> handles;
handles.push_back(Vector3(cs->get_radius(), 0, 0));
handles.push_back(Vector3(0, 0, cs->get_height() * 0.5 + cs->get_radius()));
- add_handles(handles);
+ p_gizmo->add_handles(handles, handles_material);
}
if (Object::cast_to<CylinderShape>(*s)) {
@@ -2465,7 +3353,7 @@ void CollisionShapeSpatialGizmo::redraw() {
}
}
- add_lines(points, material);
+ p_gizmo->add_lines(points, material);
Vector<Vector3> collision_segments;
@@ -2489,12 +3377,12 @@ void CollisionShapeSpatialGizmo::redraw() {
}
}
- add_collision_segments(collision_segments);
+ p_gizmo->add_collision_segments(collision_segments);
Vector<Vector3> handles;
handles.push_back(Vector3(cs->get_radius(), 0, 0));
handles.push_back(Vector3(0, cs->get_height() * 0.5, 0));
- add_handles(handles);
+ p_gizmo->add_handles(handles, handles_material);
}
if (Object::cast_to<PlaneShape>(*s)) {
@@ -2524,8 +3412,8 @@ void CollisionShapeSpatialGizmo::redraw() {
points.push_back(p.normal * p.d);
points.push_back(p.normal * p.d + p.normal * 3);
- add_lines(points, material);
- add_collision_segments(points);
+ p_gizmo->add_lines(points, material);
+ p_gizmo->add_collision_segments(points);
}
if (Object::cast_to<ConvexPolygonShape>(*s)) {
@@ -2546,8 +3434,8 @@ void CollisionShapeSpatialGizmo::redraw() {
points.write[i * 2 + 1] = md.vertices[md.edges[i].b];
}
- add_lines(points, material);
- add_collision_segments(points);
+ p_gizmo->add_lines(points, material);
+ p_gizmo->add_collision_segments(points);
}
}
}
@@ -2559,24 +3447,34 @@ void CollisionShapeSpatialGizmo::redraw() {
Vector<Vector3> points;
points.push_back(Vector3());
points.push_back(Vector3(0, 0, rs->get_length()));
- add_lines(points, material);
- add_collision_segments(points);
+ p_gizmo->add_lines(points, material);
+ p_gizmo->add_collision_segments(points);
Vector<Vector3> handles;
handles.push_back(Vector3(0, 0, rs->get_length()));
- add_handles(handles);
+ p_gizmo->add_handles(handles, handles_material);
}
}
-CollisionShapeSpatialGizmo::CollisionShapeSpatialGizmo(CollisionShape *p_cs) {
- cs = p_cs;
- set_spatial_node(p_cs);
+/////
+
+CollisionPolygonSpatialGizmoPlugin::CollisionPolygonSpatialGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ create_material("shape_material", gizmo_color);
}
-/////
+bool CollisionPolygonSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<CollisionPolygon>(p_spatial) != NULL;
+}
-void CollisionPolygonSpatialGizmo::redraw() {
+String CollisionPolygonSpatialGizmoPlugin::get_name() const {
+ return "CollisionPolygon";
+}
- clear();
+void CollisionPolygonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ CollisionPolygon *polygon = Object::cast_to<CollisionPolygon>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
Vector<Vector2> points = polygon->get_polygon();
float depth = polygon->get_depth() * 0.5;
@@ -2593,695 +3491,39 @@ void CollisionPolygonSpatialGizmo::redraw() {
lines.push_back(Vector3(points[i].x, points[i].y, -depth));
}
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
- Ref<Material> material = create_material("shape_material", gizmo_color);
-
- add_lines(lines, material);
- add_collision_segments(lines);
-}
-
-CollisionPolygonSpatialGizmo::CollisionPolygonSpatialGizmo(CollisionPolygon *p_polygon) {
-
- set_spatial_node(p_polygon);
- polygon = p_polygon;
-}
-///
-
-String VisibilityNotifierGizmo::get_handle_name(int p_idx) const {
-
- switch (p_idx) {
- case 0: return "X";
- case 1: return "Y";
- case 2: return "Z";
- }
-
- return "";
-}
-Variant VisibilityNotifierGizmo::get_handle_value(int p_idx) const {
-
- return notifier->get_aabb();
-}
-void VisibilityNotifierGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- Transform gt = notifier->get_global_transform();
- //gt.orthonormalize();
- Transform gi = gt.affine_inverse();
-
- AABB aabb = notifier->get_aabb();
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
- Vector3 ofs = aabb.position + aabb.size * 0.5;
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb);
- float d = ra[p_idx];
- if (d < 0.001)
- d = 0.001;
-
- aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d;
- aabb.size[p_idx] = d * 2;
- notifier->set_aabb(aabb);
-}
-
-void VisibilityNotifierGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
-
- if (p_cancel) {
- notifier->set_aabb(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Notifier Extents"));
- ur->add_do_method(notifier, "set_aabb", notifier->get_aabb());
- ur->add_undo_method(notifier, "set_aabb", p_restore);
- ur->commit_action();
-}
-
-void VisibilityNotifierGizmo::redraw() {
-
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/visibility_notifier");
- Ref<Material> material = create_material("visibility_notifier_material", gizmo_color);
-
- clear();
-
- Vector<Vector3> lines;
- AABB aabb = notifier->get_aabb();
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- handles.push_back(ax);
- }
-
- add_lines(lines, material);
- //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05);
- add_collision_segments(lines);
- add_handles(handles);
-}
-VisibilityNotifierGizmo::VisibilityNotifierGizmo(VisibilityNotifier *p_notifier) {
-
- notifier = p_notifier;
- set_spatial_node(p_notifier);
-}
-
-////////
-
-///
-
-String ParticlesGizmo::get_handle_name(int p_idx) const {
-
- switch (p_idx) {
- case 0: return "Size X";
- case 1: return "Size Y";
- case 2: return "Size Z";
- case 3: return "Pos X";
- case 4: return "Pos Y";
- case 5: return "Pos Z";
- }
-
- return "";
-}
-Variant ParticlesGizmo::get_handle_value(int p_idx) const {
-
- return particles->get_visibility_aabb();
-}
-void ParticlesGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- Transform gt = particles->get_global_transform();
- //gt.orthonormalize();
- Transform gi = gt.affine_inverse();
-
- bool move = p_idx >= 3;
- p_idx = p_idx % 3;
-
- AABB aabb = particles->get_visibility_aabb();
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
-
- Vector3 ofs = aabb.position + aabb.size * 0.5;
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- if (move) {
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb);
-
- float d = ra[p_idx];
-
- aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5;
- particles->set_visibility_aabb(aabb);
-
- } else {
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb);
-
- float d = ra[p_idx] - ofs[p_idx];
- if (d < 0.001)
- d = 0.001;
- //resize
- aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d;
- aabb.size[p_idx] = d * 2;
- particles->set_visibility_aabb(aabb);
- }
-}
-
-void ParticlesGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
-
- if (p_cancel) {
- particles->set_visibility_aabb(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Particles AABB"));
- ur->add_do_method(particles, "set_custom_aabb", particles->get_visibility_aabb());
- ur->add_undo_method(particles, "set_custom_aabb", p_restore);
- ur->commit_action();
-}
-
-void ParticlesGizmo::redraw() {
-
- clear();
-
- Vector<Vector3> lines;
- AABB aabb = particles->get_visibility_aabb();
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
- ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
- handles.push_back(ax);
- }
-
- Vector3 center = aabb.position + aabb.size * 0.5;
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = 1.0;
- handles.push_back(center + ax);
- lines.push_back(center);
- lines.push_back(center + ax);
- }
-
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/particles");
- Ref<Material> material = create_material("particles_material", gizmo_color);
- Ref<Material> icon = create_icon_material("particles_icon", SpatialEditor::get_singleton()->get_icon("GizmoParticles", "EditorIcons"));
-
- add_lines(lines, material);
- add_collision_segments(lines);
-
- if (is_selected()) {
-
- gizmo_color.a = 0.1;
- Ref<Material> solid_material = create_material("particles_solid_material", gizmo_color);
- add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
- }
-
- //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05);
-
- add_handles(handles);
- add_unscaled_billboard(icon, 0.05);
-}
-ParticlesGizmo::ParticlesGizmo(Particles *p_particles) {
-
- particles = p_particles;
- set_spatial_node(p_particles);
-}
-
-////////
-
-///
-
-String ReflectionProbeGizmo::get_handle_name(int p_idx) const {
-
- switch (p_idx) {
- case 0: return "Extents X";
- case 1: return "Extents Y";
- case 2: return "Extents Z";
- case 3: return "Origin X";
- case 4: return "Origin Y";
- case 5: return "Origin Z";
- }
-
- return "";
-}
-Variant ReflectionProbeGizmo::get_handle_value(int p_idx) const {
-
- return AABB(probe->get_extents(), probe->get_origin_offset());
-}
-void ReflectionProbeGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- Transform gt = probe->get_global_transform();
- //gt.orthonormalize();
- Transform gi = gt.affine_inverse();
-
- if (p_idx < 3) {
- Vector3 extents = probe->get_extents();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_idx];
- if (d < 0.001)
- d = 0.001;
-
- extents[p_idx] = d;
- probe->set_extents(extents);
- } else {
-
- p_idx -= 3;
-
- Vector3 origin = probe->get_origin_offset();
- origin[p_idx] = 0;
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(origin - axis * 16384, origin + axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_idx];
- d += 0.25;
-
- origin[p_idx] = d;
- probe->set_origin_offset(origin);
- }
-}
-
-void ReflectionProbeGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
-
- AABB restore = p_restore;
-
- if (p_cancel) {
- probe->set_extents(restore.position);
- probe->set_origin_offset(restore.size);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Probe Extents"));
- ur->add_do_method(probe, "set_extents", probe->get_extents());
- ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset());
- ur->add_undo_method(probe, "set_extents", restore.position);
- ur->add_undo_method(probe, "set_origin_offset", restore.size);
- ur->commit_action();
-}
-
-void ReflectionProbeGizmo::redraw() {
-
- clear();
-
- Vector<Vector3> lines;
- Vector<Vector3> internal_lines;
- Vector3 extents = probe->get_extents();
-
- AABB aabb;
- aabb.position = -extents;
- aabb.size = extents * 2;
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- for (int i = 0; i < 8; i++) {
- Vector3 ep = aabb.get_endpoint(i);
- internal_lines.push_back(probe->get_origin_offset());
- internal_lines.push_back(ep);
- }
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- handles.push_back(ax);
- }
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 orig_handle = probe->get_origin_offset();
- orig_handle[i] -= 0.25;
- lines.push_back(orig_handle);
- handles.push_back(orig_handle);
-
- orig_handle[i] += 0.5;
- lines.push_back(orig_handle);
- }
-
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/reflection_probe");
- Ref<Material> material = create_material("reflection_probe_material", gizmo_color);
- Ref<Material> icon = create_icon_material("reflection_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoReflectionProbe", "EditorIcons"));
-
- Color gizmo_color_internal = gizmo_color;
- gizmo_color_internal.a = 0.5;
- Ref<Material> material_internal = create_material("reflection_internal_material", gizmo_color_internal);
-
- add_lines(lines, material);
- add_lines(internal_lines, material_internal);
-
- if (is_selected()) {
-
- gizmo_color.a = 0.1;
- Ref<Material> solid_material = create_material("reflection_probe_solid_material", gizmo_color);
- add_solid_box(solid_material, probe->get_extents() * 2.0);
- }
-
- //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05);
- add_unscaled_billboard(icon, 0.05);
- add_collision_segments(lines);
- add_handles(handles);
-}
-ReflectionProbeGizmo::ReflectionProbeGizmo(ReflectionProbe *p_probe) {
-
- probe = p_probe;
- set_spatial_node(p_probe);
-}
-
-////////
-
-///
+ Ref<Material> material = get_material("shape_material", p_gizmo);
-String GIProbeGizmo::get_handle_name(int p_idx) const {
-
- switch (p_idx) {
- case 0: return "Extents X";
- case 1: return "Extents Y";
- case 2: return "Extents Z";
- }
-
- return "";
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
}
-Variant GIProbeGizmo::get_handle_value(int p_idx) const {
- return probe->get_extents();
-}
-void GIProbeGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- Transform gt = probe->get_global_transform();
- //gt.orthonormalize();
- Transform gi = gt.affine_inverse();
-
- Vector3 extents = probe->get_extents();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_idx];
- if (d < 0.001)
- d = 0.001;
-
- extents[p_idx] = d;
- probe->set_extents(extents);
-}
-
-void GIProbeGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
-
- Vector3 restore = p_restore;
-
- if (p_cancel) {
- probe->set_extents(restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Probe Extents"));
- ur->add_do_method(probe, "set_extents", probe->get_extents());
- ur->add_undo_method(probe, "set_extents", restore);
- ur->commit_action();
-}
-
-void GIProbeGizmo::redraw() {
-
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/gi_probe");
- Ref<Material> material = create_material("gi_probe_material", gizmo_color);
- Ref<Material> icon = create_icon_material("gi_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoGIProbe", "EditorIcons"));
- Color gizmo_color_internal = gizmo_color;
- gizmo_color_internal.a = 0.1;
- Ref<Material> material_internal = create_material("gi_probe_internal_material", gizmo_color_internal);
-
- clear();
-
- Vector<Vector3> lines;
- Vector3 extents = probe->get_extents();
-
- static const int subdivs[GIProbe::SUBDIV_MAX] = { 64, 128, 256, 512 };
-
- AABB aabb = AABB(-extents, extents * 2);
- int subdiv = subdivs[probe->get_subdiv()];
- float cell_size = aabb.get_longest_axis_size() / subdiv;
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- add_lines(lines, material);
- add_collision_segments(lines);
-
- lines.clear();
-
- for (int i = 1; i < subdiv; i++) {
-
- for (int j = 0; j < 3; j++) {
-
- if (cell_size * i > aabb.size[j]) {
- continue;
- }
-
- Vector2 dir;
- dir[j] = 1.0;
- Vector2 ta, tb;
- int j_n1 = (j + 1) % 3;
- int j_n2 = (j + 2) % 3;
- ta[j_n1] = 1.0;
- tb[j_n2] = 1.0;
-
- for (int k = 0; k < 4; k++) {
-
- Vector3 from = aabb.position, to = aabb.position;
- from[j] += cell_size * i;
- to[j] += cell_size * i;
-
- if (k & 1) {
- to[j_n1] += aabb.size[j_n1];
- } else {
-
- to[j_n2] += aabb.size[j_n2];
- }
-
- if (k & 2) {
- from[j_n1] += aabb.size[j_n1];
- from[j_n2] += aabb.size[j_n2];
- }
-
- lines.push_back(from);
- lines.push_back(to);
- }
- }
- }
-
- add_lines(lines, material_internal);
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- handles.push_back(ax);
- }
-
- if (is_selected()) {
-
- gizmo_color.a = 0.1;
- Ref<Material> solid_material = create_material("gi_probe_solid_material", gizmo_color);
- add_solid_box(solid_material, aabb.get_size());
- }
-
- add_unscaled_billboard(icon, 0.05);
- add_handles(handles);
-}
-GIProbeGizmo::GIProbeGizmo(GIProbe *p_probe) {
-
- probe = p_probe;
- set_spatial_node(p_probe);
-}
-
-////////
-////////
-
-///
-
-String BakedIndirectLightGizmo::get_handle_name(int p_idx) const {
-
- switch (p_idx) {
- case 0: return "Extents X";
- case 1: return "Extents Y";
- case 2: return "Extents Z";
- }
-
- return "";
-}
-Variant BakedIndirectLightGizmo::get_handle_value(int p_idx) const {
-
- return baker->get_extents();
-}
-void BakedIndirectLightGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- Transform gt = baker->get_global_transform();
- //gt.orthonormalize();
- Transform gi = gt.affine_inverse();
-
- Vector3 extents = baker->get_extents();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_idx];
- if (d < 0.001)
- d = 0.001;
+////
- extents[p_idx] = d;
- baker->set_extents(extents);
+NavigationMeshSpatialGizmoPlugin::NavigationMeshSpatialGizmoPlugin() {
+ create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1)));
+ create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7)));
+ create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4)));
+ create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled", Color(0.7, 0.7, 0.7, 0.4)));
}
-void BakedIndirectLightGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
-
- Vector3 restore = p_restore;
-
- if (p_cancel) {
- baker->set_extents(restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Probe Extents"));
- ur->add_do_method(baker, "set_extents", baker->get_extents());
- ur->add_undo_method(baker, "set_extents", restore);
- ur->commit_action();
+bool NavigationMeshSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<NavigationMeshInstance>(p_spatial) != NULL;
}
-void BakedIndirectLightGizmo::redraw() {
-
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/baked_indirect_light");
- Ref<Material> material = create_material("baked_indirect_light_material", gizmo_color);
- Ref<Material> icon = create_icon_material("baked_indirect_light_icon", SpatialEditor::get_singleton()->get_icon("GizmoBakedLightmap", "EditorIcons"));
- Color gizmo_color_internal = gizmo_color;
- gizmo_color_internal.a = 0.1;
- Ref<Material> material_internal = create_material("baked_indirect_light_internal_material", gizmo_color_internal);
-
- clear();
-
- Vector<Vector3> lines;
- Vector3 extents = baker->get_extents();
-
- AABB aabb = AABB(-extents, extents * 2);
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- add_lines(lines, material);
- add_collision_segments(lines);
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- handles.push_back(ax);
- }
-
- if (is_selected()) {
-
- gizmo_color.a = 0.1;
- Ref<Material> solid_material = create_material("baked_indirect_light_solid_material", gizmo_color);
- add_solid_box(solid_material, aabb.get_size());
- }
-
- add_unscaled_billboard(icon, 0.05);
- add_handles(handles);
+String NavigationMeshSpatialGizmoPlugin::get_name() const {
+ return "NavigationMeshInstance";
}
-BakedIndirectLightGizmo::BakedIndirectLightGizmo(BakedLightmap *p_baker) {
- baker = p_baker;
- set_spatial_node(p_baker);
-}
+void NavigationMeshSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-////////
-void NavigationMeshSpatialGizmo::redraw() {
+ NavigationMeshInstance *navmesh = Object::cast_to<NavigationMeshInstance>(p_gizmo->get_spatial_node());
- Ref<Material> edge_material = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_edge"));
- Ref<Material> edge_material_disabled = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled"));
- Ref<Material> solid_material = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_solid"));
- Ref<Material> solid_material_disabled = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled"));
+ Ref<Material> edge_material = get_material("navigation_material", p_gizmo);
+ Ref<Material> edge_material_disabled = get_material("navigation_material", p_gizmo);
+ Ref<Material> solid_material = get_material("navigation_material", p_gizmo);
+ Ref<Material> solid_material_disabled = get_material("navigation_material", p_gizmo);
- clear();
+ p_gizmo->clear();
Ref<NavigationMesh> navmeshie = navmesh->get_navigation_mesh();
if (navmeshie.is_null())
return;
@@ -3353,28 +3595,19 @@ void NavigationMeshSpatialGizmo::redraw() {
tmesh->create(tmeshfaces);
if (lines.size())
- add_lines(lines, navmesh->is_enabled() ? edge_material : edge_material_disabled);
- add_collision_triangles(tmesh);
+ p_gizmo->add_lines(lines, navmesh->is_enabled() ? edge_material : edge_material_disabled);
+ p_gizmo->add_collision_triangles(tmesh);
Ref<ArrayMesh> m = memnew(ArrayMesh);
Array a;
a.resize(Mesh::ARRAY_MAX);
a[0] = tmeshfaces;
m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
m->surface_set_material(0, navmesh->is_enabled() ? solid_material : solid_material_disabled);
- add_mesh(m);
- add_collision_segments(lines);
-}
-
-NavigationMeshSpatialGizmo::NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh) {
-
- set_spatial_node(p_navmesh);
- navmesh = p_navmesh;
+ p_gizmo->add_mesh(m);
+ p_gizmo->add_collision_segments(lines);
}
//////
-///
-///
-///
#define BODY_A_RADIUS 0.25
#define BODY_B_RADIUS 0.27
@@ -3625,38 +3858,169 @@ void JointGizmosDrawer::draw_cone(const Transform &p_offset, const Basis &p_base
}
}
-void PinJointSpatialGizmo::CreateGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) {
- float cs = 0.25;
+////
- r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin);
- r_cursor_points.push_back(p_offset.translated(Vector3(-cs, 0, 0)).origin);
- r_cursor_points.push_back(p_offset.translated(Vector3(0, +cs, 0)).origin);
- r_cursor_points.push_back(p_offset.translated(Vector3(0, -cs, 0)).origin);
- r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, +cs)).origin);
- r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, -cs)).origin);
+JointSpatialGizmoPlugin::JointSpatialGizmoPlugin() {
+ create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)));
+ create_material("joint_body_a_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1)));
+ create_material("joint_body_b_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1)));
}
-void PinJointSpatialGizmo::redraw() {
+bool JointSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<Joint>(p_spatial) != NULL;
+}
- clear();
- Vector<Vector3> cursor_points;
- CreateGizmo(Transform(), cursor_points);
- add_collision_segments(cursor_points);
+String JointSpatialGizmoPlugin::get_name() const {
+ return "Joints";
+}
- Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
+void JointSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+ Joint *joint = Object::cast_to<Joint>(p_gizmo->get_spatial_node());
- add_lines(cursor_points, material);
-}
+ p_gizmo->clear();
-PinJointSpatialGizmo::PinJointSpatialGizmo(PinJoint *p_p3d) {
+ const Spatial *node_body_a = Object::cast_to<Spatial>(joint->get_node(joint->get_node_a()));
+ const Spatial *node_body_b = Object::cast_to<Spatial>(joint->get_node(joint->get_node_b()));
- p3d = p_p3d;
- set_spatial_node(p3d);
-}
+ Ref<Material> common_material = get_material("joint_material", p_gizmo);
+ Ref<Material> body_a_material = get_material("joint_body_a_material", p_gizmo);
+ Ref<Material> body_b_material = get_material("joint_body_b_material", p_gizmo);
-////
+ Vector<Vector3> points;
+ Vector<Vector3> body_a_points;
+ Vector<Vector3> body_b_points;
-void HingeJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
+ if (Object::cast_to<PinJoint>(joint)) {
+ CreatePinJointGizmo(Transform(), points);
+ p_gizmo->add_collision_segments(points);
+ p_gizmo->add_lines(points, common_material);
+ }
+
+ HingeJoint *hinge = Object::cast_to<HingeJoint>(joint);
+ if (hinge) {
+
+ CreateHingeJointGizmo(
+ Transform(),
+ hinge->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+ hinge->get_param(HingeJoint::PARAM_LIMIT_LOWER),
+ hinge->get_param(HingeJoint::PARAM_LIMIT_UPPER),
+ hinge->get_flag(HingeJoint::FLAG_USE_LIMIT),
+ points,
+ node_body_a ? &body_a_points : NULL,
+ node_body_b ? &body_b_points : NULL);
+
+ p_gizmo->add_collision_segments(points);
+ p_gizmo->add_collision_segments(body_a_points);
+ p_gizmo->add_collision_segments(body_b_points);
+
+ p_gizmo->add_lines(points, common_material);
+ p_gizmo->add_lines(body_a_points, body_a_material);
+ p_gizmo->add_lines(body_b_points, body_b_material);
+ }
+
+ SliderJoint *slider = Object::cast_to<SliderJoint>(joint);
+ if (slider) {
+
+ CreateSliderJointGizmo(
+ Transform(),
+ slider->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+ slider->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER),
+ slider->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER),
+ slider->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER),
+ slider->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER),
+ points,
+ node_body_a ? &body_a_points : NULL,
+ node_body_b ? &body_b_points : NULL);
+
+ p_gizmo->add_collision_segments(points);
+ p_gizmo->add_collision_segments(body_a_points);
+ p_gizmo->add_collision_segments(body_b_points);
+
+ p_gizmo->add_lines(points, common_material);
+ p_gizmo->add_lines(body_a_points, body_a_material);
+ p_gizmo->add_lines(body_b_points, body_b_material);
+ }
+
+ ConeTwistJoint *cone = Object::cast_to<ConeTwistJoint>(joint);
+ if (cone) {
+
+ CreateConeTwistJointGizmo(
+ Transform(),
+ cone->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+ cone->get_param(ConeTwistJoint::PARAM_SWING_SPAN),
+ cone->get_param(ConeTwistJoint::PARAM_TWIST_SPAN),
+ node_body_a ? &body_a_points : NULL,
+ node_body_b ? &body_b_points : NULL);
+
+ p_gizmo->add_collision_segments(body_a_points);
+ p_gizmo->add_collision_segments(body_b_points);
+
+ p_gizmo->add_lines(body_a_points, body_a_material);
+ p_gizmo->add_lines(body_b_points, body_b_material);
+ }
+
+ Generic6DOFJoint *gen = Object::cast_to<Generic6DOFJoint>(joint);
+ if (gen) {
+
+ CreateGeneric6DOFJointGizmo(
+ Transform(),
+ gen->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+
+ gen->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
+ gen->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
+ gen->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
+ gen->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
+ gen->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
+ gen->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
+
+ gen->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
+ gen->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
+ gen->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
+ gen->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
+ gen->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
+ gen->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
+
+ gen->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
+ gen->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
+ gen->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
+ gen->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
+ gen->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
+ gen->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
+
+ points,
+ node_body_a ? &body_a_points : NULL,
+ node_body_a ? &body_b_points : NULL);
+
+ p_gizmo->add_collision_segments(points);
+ p_gizmo->add_collision_segments(body_a_points);
+ p_gizmo->add_collision_segments(body_b_points);
+
+ p_gizmo->add_lines(points, common_material);
+ p_gizmo->add_lines(body_a_points, body_a_material);
+ p_gizmo->add_lines(body_b_points, body_b_material);
+ }
+}
+
+void JointSpatialGizmoPlugin::CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) {
+ float cs = 0.25;
+
+ r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(-cs, 0, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, +cs, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, -cs, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, +cs)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, -cs)).origin);
+}
+
+void JointSpatialGizmoPlugin::CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
r_common_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin);
r_common_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin);
@@ -3688,52 +4052,7 @@ void HingeJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transf
}
}
-void HingeJointSpatialGizmo::redraw() {
-
- const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a()));
- const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b()));
-
- Vector<Vector3> points;
- Vector<Vector3> body_a_points;
- Vector<Vector3> body_b_points;
- CreateGizmo(
- Transform(),
- p3d->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
- p3d->get_param(HingeJoint::PARAM_LIMIT_LOWER),
- p3d->get_param(HingeJoint::PARAM_LIMIT_UPPER),
- p3d->get_flag(HingeJoint::FLAG_USE_LIMIT),
- points,
- node_body_a ? &body_a_points : NULL,
- node_body_b ? &body_b_points : NULL);
-
- clear();
-
- Ref<Material> common_material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
- Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a"));
- Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b"));
-
- add_collision_segments(points);
- add_collision_segments(body_a_points);
- add_collision_segments(body_b_points);
-
- add_lines(points, common_material);
- add_lines(body_a_points, body_a_material);
- add_lines(body_b_points, body_b_material);
-}
-
-HingeJointSpatialGizmo::HingeJointSpatialGizmo(HingeJoint *p_p3d) {
-
- p3d = p_p3d;
- set_spatial_node(p3d);
-}
-
-///////
-///
-////
-
-void SliderJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
+void JointSpatialGizmoPlugin::CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
p_linear_limit_lower = -p_linear_limit_lower;
p_linear_limit_upper = -p_linear_limit_upper;
@@ -3793,53 +4112,7 @@ void SliderJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Trans
true);
}
-void SliderJointSpatialGizmo::redraw() {
-
- const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a()));
- const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b()));
-
- clear();
- Vector<Vector3> cursor_points;
- Vector<Vector3> body_a_points;
- Vector<Vector3> body_b_points;
-
- CreateGizmo(
- Transform(),
- p3d->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
- p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER),
- p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER),
- p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER),
- p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER),
- cursor_points,
- node_body_a ? &body_a_points : NULL,
- node_body_b ? &body_b_points : NULL);
-
- Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
- Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a"));
- Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b"));
-
- add_collision_segments(cursor_points);
- add_collision_segments(body_a_points);
- add_collision_segments(body_b_points);
-
- add_lines(cursor_points, material);
- add_lines(body_a_points, body_a_material);
- add_lines(body_b_points, body_b_material);
-}
-
-SliderJointSpatialGizmo::SliderJointSpatialGizmo(SliderJoint *p_p3d) {
-
- p3d = p_p3d;
- set_spatial_node(p3d);
-}
-
-///////
-///
-////
-
-void ConeTwistJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
+void JointSpatialGizmoPlugin::CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
if (r_body_a_points)
JointGizmosDrawer::draw_cone(
@@ -3858,51 +4131,7 @@ void ConeTwistJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Tr
*r_body_b_points);
}
-void ConeTwistJointSpatialGizmo::redraw() {
-
- const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a()));
- const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b()));
-
- clear();
- Vector<Vector3> points;
- Vector<Vector3> body_a_points;
- Vector<Vector3> body_b_points;
-
- CreateGizmo(
- Transform(),
- p3d->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
- p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN),
- p3d->get_param(ConeTwistJoint::PARAM_TWIST_SPAN),
- points,
- node_body_a ? &body_a_points : NULL,
- node_body_b ? &body_b_points : NULL);
-
- Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
- Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a"));
- Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b"));
-
- add_collision_segments(points);
- add_collision_segments(body_a_points);
- add_collision_segments(body_b_points);
-
- add_lines(points, material);
- add_lines(body_a_points, body_a_material);
- add_lines(body_b_points, body_b_material);
-}
-
-ConeTwistJointSpatialGizmo::ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d) {
-
- p3d = p_p3d;
- set_spatial_node(p3d);
-}
-
-///////
-///
-////
-
-void Generic6DOFJointSpatialGizmo::CreateGizmo(
+void JointSpatialGizmoPlugin::CreateGeneric6DOFJointGizmo(
const Transform &p_offset,
const Transform &p_trs_joint,
const Transform &p_trs_body_a,
@@ -4051,510 +4280,3 @@ void Generic6DOFJointSpatialGizmo::CreateGizmo(
#undef ADD_VTX
}
-
-void Generic6DOFJointSpatialGizmo::redraw() {
-
- const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a()));
- const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b()));
-
- clear();
- Vector<Vector3> cursor_points;
- Vector<Vector3> body_a_points;
- Vector<Vector3> body_b_points;
-
- CreateGizmo(
- Transform(),
- p3d->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
-
- p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
- p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
- p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
- p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
- p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
- p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
-
- p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
- p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
- p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
- p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
- p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
- p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
-
- p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
- p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
- p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
- p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
- p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
- p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
-
- cursor_points,
- node_body_a ? &body_a_points : NULL,
- node_body_a ? &body_b_points : NULL);
-
- Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
- Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a"));
- Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b"));
-
- add_collision_segments(cursor_points);
- add_collision_segments(body_a_points);
- add_collision_segments(body_b_points);
-
- add_lines(cursor_points, material);
- add_lines(body_a_points, body_a_material);
- add_lines(body_b_points, body_b_material);
-}
-
-Generic6DOFJointSpatialGizmo::Generic6DOFJointSpatialGizmo(Generic6DOFJoint *p_p3d) {
-
- p3d = p_p3d;
- set_spatial_node(p3d);
-}
-
-///////
-///
-////
-
-SpatialEditorGizmos *SpatialEditorGizmos::singleton = NULL;
-
-Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) {
-
- if (Object::cast_to<Light>(p_spatial)) {
-
- Ref<LightSpatialGizmo> lsg = memnew(LightSpatialGizmo(Object::cast_to<Light>(p_spatial)));
- return lsg;
- }
-
- if (Object::cast_to<Camera>(p_spatial)) {
-
- Ref<CameraSpatialGizmo> lsg = memnew(CameraSpatialGizmo(Object::cast_to<Camera>(p_spatial)));
- return lsg;
- }
-
- if (Object::cast_to<Skeleton>(p_spatial)) {
-
- Ref<SkeletonSpatialGizmo> lsg = memnew(SkeletonSpatialGizmo(Object::cast_to<Skeleton>(p_spatial)));
- return lsg;
- }
-
- if (Object::cast_to<PhysicalBone>(p_spatial)) {
-
- Ref<PhysicalBoneSpatialGizmo> pbsg = memnew(PhysicalBoneSpatialGizmo(Object::cast_to<PhysicalBone>(p_spatial)));
- return pbsg;
- }
-
- if (Object::cast_to<Position3D>(p_spatial)) {
-
- Ref<Position3DSpatialGizmo> lsg = memnew(Position3DSpatialGizmo(Object::cast_to<Position3D>(p_spatial)));
- return lsg;
- }
-
- if (Object::cast_to<SoftBody>(p_spatial)) {
-
- Ref<SoftBodySpatialGizmo> misg = memnew(SoftBodySpatialGizmo(Object::cast_to<SoftBody>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<MeshInstance>(p_spatial)) {
-
- Ref<MeshInstanceSpatialGizmo> misg = memnew(MeshInstanceSpatialGizmo(Object::cast_to<MeshInstance>(p_spatial)));
- return misg;
- }
-
- /*if (Object::cast_to<Room>(p_spatial)) {
-
- Ref<RoomSpatialGizmo> misg = memnew(RoomSpatialGizmo(Object::cast_to<Room>(p_spatial)));
- return misg;
- }*/
-
- if (Object::cast_to<NavigationMeshInstance>(p_spatial)) {
-
- Ref<NavigationMeshSpatialGizmo> misg = memnew(NavigationMeshSpatialGizmo(Object::cast_to<NavigationMeshInstance>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<RayCast>(p_spatial)) {
-
- Ref<RayCastSpatialGizmo> misg = memnew(RayCastSpatialGizmo(Object::cast_to<RayCast>(p_spatial)));
- return misg;
- }
- /*
- if (Object::cast_to<Portal>(p_spatial)) {
-
- Ref<PortalSpatialGizmo> misg = memnew(PortalSpatialGizmo(Object::cast_to<Portal>(p_spatial)));
- return misg;
- }
-*/
-
- if (Object::cast_to<CollisionShape>(p_spatial)) {
-
- Ref<CollisionShapeSpatialGizmo> misg = memnew(CollisionShapeSpatialGizmo(Object::cast_to<CollisionShape>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<VisibilityNotifier>(p_spatial)) {
-
- Ref<VisibilityNotifierGizmo> misg = memnew(VisibilityNotifierGizmo(Object::cast_to<VisibilityNotifier>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<Particles>(p_spatial)) {
-
- Ref<ParticlesGizmo> misg = memnew(ParticlesGizmo(Object::cast_to<Particles>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<ReflectionProbe>(p_spatial)) {
-
- Ref<ReflectionProbeGizmo> misg = memnew(ReflectionProbeGizmo(Object::cast_to<ReflectionProbe>(p_spatial)));
- return misg;
- }
- if (Object::cast_to<GIProbe>(p_spatial)) {
-
- Ref<GIProbeGizmo> misg = memnew(GIProbeGizmo(Object::cast_to<GIProbe>(p_spatial)));
- return misg;
- }
- if (Object::cast_to<BakedLightmap>(p_spatial)) {
-
- Ref<BakedIndirectLightGizmo> misg = memnew(BakedIndirectLightGizmo(Object::cast_to<BakedLightmap>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<VehicleWheel>(p_spatial)) {
-
- Ref<VehicleWheelSpatialGizmo> misg = memnew(VehicleWheelSpatialGizmo(Object::cast_to<VehicleWheel>(p_spatial)));
- return misg;
- }
- if (Object::cast_to<PinJoint>(p_spatial)) {
-
- Ref<PinJointSpatialGizmo> misg = memnew(PinJointSpatialGizmo(Object::cast_to<PinJoint>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<HingeJoint>(p_spatial)) {
-
- Ref<HingeJointSpatialGizmo> misg = memnew(HingeJointSpatialGizmo(Object::cast_to<HingeJoint>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<SliderJoint>(p_spatial)) {
-
- Ref<SliderJointSpatialGizmo> misg = memnew(SliderJointSpatialGizmo(Object::cast_to<SliderJoint>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<ConeTwistJoint>(p_spatial)) {
-
- Ref<ConeTwistJointSpatialGizmo> misg = memnew(ConeTwistJointSpatialGizmo(Object::cast_to<ConeTwistJoint>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<Generic6DOFJoint>(p_spatial)) {
-
- Ref<Generic6DOFJointSpatialGizmo> misg = memnew(Generic6DOFJointSpatialGizmo(Object::cast_to<Generic6DOFJoint>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<CollisionPolygon>(p_spatial)) {
-
- Ref<CollisionPolygonSpatialGizmo> misg = memnew(CollisionPolygonSpatialGizmo(Object::cast_to<CollisionPolygon>(p_spatial)));
- return misg;
- }
-
- if (Object::cast_to<AudioStreamPlayer3D>(p_spatial)) {
-
- Ref<AudioStreamPlayer3DSpatialGizmo> misg = memnew(AudioStreamPlayer3DSpatialGizmo(Object::cast_to<AudioStreamPlayer3D>(p_spatial)));
- return misg;
- }
-
- return Ref<SpatialEditorGizmo>();
-}
-
-SpatialEditorGizmos::SpatialEditorGizmos() {
-
- singleton = this;
-
- handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
- handle_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- handle_material->set_on_top_of_alpha();
- handle_material->set_albedo(Color(0.8, 0.8, 0.8));
- handle_material_billboard = handle_material->duplicate();
- handle_material_billboard->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
-
- handle2_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
- handle2_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- handle2_material->set_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true);
- handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle", "EditorIcons");
- handle2_material->set_point_size(handle_t->get_width());
- handle2_material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, handle_t);
- handle2_material->set_albedo(Color(1, 1, 1));
- handle2_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- handle2_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- handle2_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
- handle2_material->set_on_top_of_alpha();
- handle2_material_billboard = handle2_material->duplicate();
- handle2_material_billboard->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
- handle2_material_billboard->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
- handle2_material_billboard->set_on_top_of_alpha();
-
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/light", Color(1, 1, 0.2));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled", Color(0.7, 0.7, 0.7, 0.4));
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.5));
-
-#if 0
- light_material = create_line_material(Color(1, 1, 0.2));
- light_material_omni = create_line_material(Color(1, 1, 0.2));
- light_material_omni->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
-
- light_material_omni_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
- light_material_omni_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- light_material_omni_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
- light_material_omni_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
- light_material_omni_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- light_material_omni_icon->set_albedo(Color(1, 1, 1, 0.9));
- light_material_omni_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons"));
- light_material_omni_icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true);
- light_material_omni_icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
-
- light_material_directional_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
- light_material_directional_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- light_material_directional_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
- light_material_directional_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
- light_material_directional_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- light_material_directional_icon->set_albedo(Color(1, 1, 1, 0.9));
- light_material_directional_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons"));
- light_material_directional_icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
- light_material_directional_icon->set_depth_scale(1);
-
- camera_material = create_line_material(Color(1.0, 0.5, 1.0));
-
- navmesh_edge_material = create_line_material(Color(0.1, 0.8, 1.0));
- navmesh_solid_material = create_solid_material(Color(0.1, 0.8, 1.0, 0.4));
- navmesh_edge_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false);
- navmesh_edge_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false);
- navmesh_solid_material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
-
- navmesh_edge_material_disabled = create_line_material(Color(1.0, 0.8, 0.1));
- navmesh_solid_material_disabled = create_solid_material(Color(1.0, 0.8, 0.1, 0.4));
- navmesh_edge_material_disabled->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false);
- navmesh_edge_material_disabled->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false);
- navmesh_solid_material_disabled->set_cull_mode(SpatialMaterial::CULL_DISABLED);
-
- skeleton_material = create_line_material(Color(0.6, 1.0, 0.3));
- skeleton_material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
- skeleton_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- skeleton_material->set_on_top_of_alpha();
- skeleton_material->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
-
- //position 3D Shared mesh
-
- pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
- {
-
- PoolVector<Vector3> cursor_points;
- PoolVector<Color> cursor_colors;
- float cs = 0.25;
- cursor_points.push_back(Vector3(+cs, 0, 0));
- cursor_points.push_back(Vector3(-cs, 0, 0));
- cursor_points.push_back(Vector3(0, +cs, 0));
- cursor_points.push_back(Vector3(0, -cs, 0));
- cursor_points.push_back(Vector3(0, 0, +cs));
- cursor_points.push_back(Vector3(0, 0, -cs));
- cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7));
- cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7));
- cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7));
- cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7));
- cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7));
- cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7));
-
- Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
- mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
- mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- mat->set_line_width(3);
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[Mesh::ARRAY_VERTEX] = cursor_points;
- d[Mesh::ARRAY_COLOR] = cursor_colors;
- pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d);
- pos3d_mesh->surface_set_material(0, mat);
- }
-
- listener_line_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
- {
-
- PoolVector<Vector3> cursor_points;
- PoolVector<Color> cursor_colors;
- cursor_points.push_back(Vector3(0, 0, 0));
- cursor_points.push_back(Vector3(0, 0, -1.0));
- cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7));
- cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7));
-
- Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
- mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
- mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- mat->set_line_width(3);
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[Mesh::ARRAY_VERTEX] = cursor_points;
- d[Mesh::ARRAY_COLOR] = cursor_colors;
- listener_line_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d);
- listener_line_mesh->surface_set_material(0, mat);
- }
-
- room_material = create_line_material(Color(1.0, 0.6, 0.9));
- portal_material = create_line_material(Color(1.0, 0.8, 0.6));
- raycast_material = create_line_material(Color(1.0, 0.8, 0.6));
- car_wheel_material = create_line_material(Color(0.6, 0.8, 1.0));
- visibility_notifier_material = create_line_material(Color(1.0, 0.5, 1.0));
- particles_material = create_line_material(Color(1.0, 1.0, 0.5));
- reflection_probe_material = create_line_material(Color(0.5, 1.0, 0.7));
- reflection_probe_material_internal = create_line_material(Color(0.3, 0.8, 0.5, 0.15));
- gi_probe_material = create_line_material(Color(0.7, 1.0, 0.5));
- gi_probe_material_internal = create_line_material(Color(0.5, 0.8, 0.3, 0.1));
- joint_material = create_line_material(Color(0.6, 0.8, 1.0));
-
- stream_player_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
- stream_player_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- stream_player_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
- stream_player_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
- stream_player_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- stream_player_icon->set_albedo(Color(1, 1, 1, 0.9));
- stream_player_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer", "EditorIcons"));
-
- visibility_notifier_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
- visibility_notifier_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- visibility_notifier_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
- visibility_notifier_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
- visibility_notifier_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- visibility_notifier_icon->set_albedo(Color(1, 1, 1, 0.9));
- visibility_notifier_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("Visible", "EditorIcons"));
-
- listener_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
- listener_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- listener_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
- listener_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
- listener_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- listener_icon->set_albedo(Color(1, 1, 1, 0.9));
- listener_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoListener", "EditorIcons"));
-
- {
-
- PoolVector<Vector3> vertices;
-
-#undef ADD_VTX
-#define ADD_VTX(m_idx) \
- vertices.push_back(face_points[m_idx]);
-
- for (int i = 0; i < 6; i++) {
-
- Vector3 face_points[4];
-
- for (int j = 0; j < 4; j++) {
-
- float v[3];
- v[0] = 1.0;
- v[1] = 1 - 2 * ((j >> 1) & 1);
- v[2] = v[1] * (1 - 2 * (j & 1));
-
- for (int k = 0; k < 3; k++) {
-
- if (i < 3)
- face_points[j][(i + k) % 3] = v[k];
- else
- face_points[3 - j][(i + k) % 3] = -v[k];
- }
- }
- //tri 1
- ADD_VTX(0);
- ADD_VTX(1);
- ADD_VTX(2);
- //tri 2
- ADD_VTX(2);
- ADD_VTX(3);
- ADD_VTX(0);
- }
-
- test_cube_tm = Ref<TriangleMesh>(memnew(TriangleMesh));
- test_cube_tm->create(vertices);
- }
-
- shape_material = create_line_material(Color(0.2, 1, 1.0));
-#endif
-
- pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
- {
-
- PoolVector<Vector3> cursor_points;
- PoolVector<Color> cursor_colors;
- float cs = 0.25;
- cursor_points.push_back(Vector3(+cs, 0, 0));
- cursor_points.push_back(Vector3(-cs, 0, 0));
- cursor_points.push_back(Vector3(0, +cs, 0));
- cursor_points.push_back(Vector3(0, -cs, 0));
- cursor_points.push_back(Vector3(0, 0, +cs));
- cursor_points.push_back(Vector3(0, 0, -cs));
- cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7));
- cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7));
- cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7));
- cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7));
- cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7));
- cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7));
-
- Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
- mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
- mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- mat->set_line_width(3);
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[Mesh::ARRAY_VERTEX] = cursor_points;
- d[Mesh::ARRAY_COLOR] = cursor_colors;
- pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d);
- pos3d_mesh->surface_set_material(0, mat);
- }
-
- listener_line_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
- {
-
- PoolVector<Vector3> cursor_points;
- PoolVector<Color> cursor_colors;
- cursor_points.push_back(Vector3(0, 0, 0));
- cursor_points.push_back(Vector3(0, 0, -1.0));
- cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7));
- cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7));
-
- Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
- mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
- mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
- mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- mat->set_line_width(3);
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[Mesh::ARRAY_VERTEX] = cursor_points;
- d[Mesh::ARRAY_COLOR] = cursor_colors;
- listener_line_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d);
- listener_line_mesh->surface_set_material(0, mat);
- }
-}
diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h
index 198d028516..877590b91d 100644
--- a/editor/spatial_editor_gizmos.h
+++ b/editor/spatial_editor_gizmos.h
@@ -55,187 +55,120 @@
class Camera;
-class EditorSpatialGizmo : public SpatialEditorGizmo {
+class LightSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- GDCLASS(EditorSpatialGizmo, SpatialGizmo);
+ GDCLASS(LightSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
- struct Instance {
-
- RID instance;
- Ref<ArrayMesh> mesh;
- RID skeleton;
- bool billboard;
- bool unscaled;
- bool can_intersect;
- bool extra_margin;
- Instance() {
-
- billboard = false;
- unscaled = false;
- can_intersect = false;
- extra_margin = false;
- }
-
- void create_instance(Spatial *p_base);
- };
-
- Vector<Vector3> collision_segments;
- Ref<TriangleMesh> collision_mesh;
-
- struct Handle {
- Vector3 pos;
- bool billboard;
- };
-
- Vector<Vector3> handles;
- Vector<Vector3> secondary_handles;
- float selectable_icon_size = -1.0f;
- bool billboard_handle;
+public:
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
- bool valid;
- Spatial *base;
- Vector<Instance> instances;
- Spatial *spatial_node;
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+ void redraw(EditorSpatialGizmo *p_gizmo);
- void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Spatial>(p_node)); }
+ LightSpatialGizmoPlugin();
+};
-protected:
- void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false);
- void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID());
- void add_collision_segments(const Vector<Vector3> &p_lines);
- void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh);
- void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1);
- void add_handles(const Vector<Vector3> &p_handles, bool p_billboard = false, bool p_secondary = false);
- void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3());
+class AudioStreamPlayer3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- void set_spatial_node(Spatial *p_node);
- const Spatial *get_spatial_node() const { return spatial_node; }
+ GDCLASS(AudioStreamPlayer3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
- static void _bind_methods();
+public:
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
- Ref<SpatialMaterial> create_material(const String &p_name, const Color &p_color, bool p_billboard = false, bool p_on_top = false, bool p_use_vertex_color = false);
- Ref<SpatialMaterial> create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top = false, const Color &p_albedo = Color(1, 1, 1, 1));
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+ void redraw(EditorSpatialGizmo *p_gizmo);
-public:
- virtual Vector3 get_handle_pos(int p_idx) const;
- virtual bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum);
- virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false);
-
- void clear();
- void create();
- void transform();
- virtual void redraw();
- void free();
- virtual bool is_editable() const;
- virtual bool can_draw() const;
-
- EditorSpatialGizmo();
- ~EditorSpatialGizmo();
+ AudioStreamPlayer3DSpatialGizmoPlugin();
};
-class LightSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(LightSpatialGizmo, EditorSpatialGizmo);
+class CameraSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- Light *light;
+ GDCLASS(CameraSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
- void redraw();
- LightSpatialGizmo(Light *p_light = NULL);
-};
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+ void redraw(EditorSpatialGizmo *p_gizmo);
-class AudioStreamPlayer3DSpatialGizmo : public EditorSpatialGizmo {
+ CameraSpatialGizmoPlugin();
+};
- GDCLASS(AudioStreamPlayer3DSpatialGizmo, EditorSpatialGizmo);
+class MeshInstanceSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- AudioStreamPlayer3D *player;
+ GDCLASS(MeshInstanceSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ bool can_be_hidden() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
- void redraw();
- AudioStreamPlayer3DSpatialGizmo(AudioStreamPlayer3D *p_player = NULL);
+ MeshInstanceSpatialGizmoPlugin();
};
-class CameraSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(CameraSpatialGizmo, EditorSpatialGizmo);
+class Sprite3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- Camera *camera;
+ GDCLASS(Sprite3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ bool can_be_hidden() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
- void redraw();
- CameraSpatialGizmo(Camera *p_camera = NULL);
+ Sprite3DSpatialGizmoPlugin();
};
-class MeshInstanceSpatialGizmo : public EditorSpatialGizmo {
+class Position3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- GDCLASS(MeshInstanceSpatialGizmo, EditorSpatialGizmo);
+ GDCLASS(Position3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
- MeshInstance *mesh;
+ Ref<ArrayMesh> pos3d_mesh;
+ Vector<Vector3> cursor_points;
public:
- virtual bool can_draw() const;
- void redraw();
- MeshInstanceSpatialGizmo(MeshInstance *p_mesh = NULL);
-};
-
-class Sprite3DSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(Sprite3DSpatialGizmo, EditorSpatialGizmo);
-
- SpriteBase3D *sprite;
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
-public:
- virtual bool can_draw() const;
- void redraw();
- Sprite3DSpatialGizmo(SpriteBase3D *p_sprite = NULL);
+ Position3DSpatialGizmoPlugin();
};
-class Position3DSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(Position3DSpatialGizmo, EditorSpatialGizmo);
+class SkeletonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- Position3D *p3d;
+ GDCLASS(SkeletonSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- void redraw();
- Position3DSpatialGizmo(Position3D *p_p3d = NULL);
-};
-
-class SkeletonSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(SkeletonSpatialGizmo, EditorSpatialGizmo);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
- Skeleton *skel;
-
-public:
- void redraw();
- SkeletonSpatialGizmo(Skeleton *p_skel = NULL);
+ SkeletonSpatialGizmoPlugin();
};
-class PhysicalBoneSpatialGizmo : public EditorSpatialGizmo {
- GDCLASS(PhysicalBoneSpatialGizmo, EditorSpatialGizmo);
+class PhysicalBoneSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- PhysicalBone *physical_bone;
+ GDCLASS(PhysicalBoneSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- //virtual Transform get_global_gizmo_transform();
- virtual void redraw();
- PhysicalBoneSpatialGizmo(PhysicalBone *p_pb = NULL);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
+
+ PhysicalBoneSpatialGizmoPlugin();
};
#if 0
@@ -251,154 +184,166 @@ public:
};
#endif
-class VisibilityNotifierGizmo : public EditorSpatialGizmo {
-
- GDCLASS(VisibilityNotifierGizmo, EditorSpatialGizmo);
+class RayCastSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- VisibilityNotifier *notifier;
+ GDCLASS(RayCastSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
- void redraw();
- VisibilityNotifierGizmo(VisibilityNotifier *p_notifier = NULL);
+ RayCastSpatialGizmoPlugin();
};
-class ParticlesGizmo : public EditorSpatialGizmo {
-
- GDCLASS(ParticlesGizmo, EditorSpatialGizmo);
+class VehicleWheelSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- Particles *particles;
+ GDCLASS(VehicleWheelSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
- void redraw();
- ParticlesGizmo(Particles *p_particles = NULL);
+ VehicleWheelSpatialGizmoPlugin();
};
-class ReflectionProbeGizmo : public EditorSpatialGizmo {
-
- GDCLASS(ReflectionProbeGizmo, EditorSpatialGizmo);
+class SoftBodySpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- ReflectionProbe *probe;
+ GDCLASS(SoftBodySpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ bool is_selectable_when_hidden() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
- void redraw();
- ReflectionProbeGizmo(ReflectionProbe *p_probe = NULL);
-};
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel);
+ bool is_gizmo_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const;
-class GIProbeGizmo : public EditorSpatialGizmo {
+ SoftBodySpatialGizmoPlugin();
+};
- GDCLASS(GIProbeGizmo, EditorSpatialGizmo);
+class VisibilityNotifierGizmoPlugin : public EditorSpatialGizmoPlugin {
- GIProbe *probe;
+ GDCLASS(VisibilityNotifierGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
- void redraw();
- GIProbeGizmo(GIProbe *p_probe = NULL);
-};
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
-class BakedIndirectLightGizmo : public EditorSpatialGizmo {
+ VisibilityNotifierGizmoPlugin();
+};
- GDCLASS(BakedIndirectLightGizmo, EditorSpatialGizmo);
+class ParticlesGizmoPlugin : public EditorSpatialGizmoPlugin {
- BakedLightmap *baker;
+ GDCLASS(ParticlesGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ bool is_selectable_when_hidden() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
- void redraw();
- BakedIndirectLightGizmo(BakedLightmap *p_baker = NULL);
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+
+ ParticlesGizmoPlugin();
};
-class SoftBodySpatialGizmo : public EditorSpatialGizmo {
- GDCLASS(SoftBodySpatialGizmo, EditorSpatialGizmo);
+class ReflectionProbeGizmoPlugin : public EditorSpatialGizmoPlugin {
- class SoftBody *soft_body;
- //RID physics_sphere_shape; // Used for raycast that doesn't work, in this moment, with softbody
+ GDCLASS(ReflectionProbeGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- void redraw();
- virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
- virtual bool is_gizmo_handle_highlighted(int idx) const;
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
- SoftBodySpatialGizmo(SoftBody *p_soft_physics_body = NULL);
- ~SoftBodySpatialGizmo();
+ ReflectionProbeGizmoPlugin();
};
-class CollisionShapeSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(CollisionShapeSpatialGizmo, EditorSpatialGizmo);
+class GIProbeGizmoPlugin : public EditorSpatialGizmoPlugin {
- CollisionShape *cs;
+ GDCLASS(GIProbeGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
- void redraw();
- CollisionShapeSpatialGizmo(CollisionShape *p_cs = NULL);
-};
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
+
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
-class CollisionPolygonSpatialGizmo : public EditorSpatialGizmo {
+ GIProbeGizmoPlugin();
+};
- GDCLASS(CollisionPolygonSpatialGizmo, EditorSpatialGizmo);
+class BakedIndirectLightGizmoPlugin : public EditorSpatialGizmoPlugin {
- CollisionPolygon *polygon;
+ GDCLASS(BakedIndirectLightGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- void redraw();
- CollisionPolygonSpatialGizmo(CollisionPolygon *p_polygon = NULL);
-};
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
-class RayCastSpatialGizmo : public EditorSpatialGizmo {
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+
+ BakedIndirectLightGizmoPlugin();
+};
- GDCLASS(RayCastSpatialGizmo, EditorSpatialGizmo);
+class CollisionShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- RayCast *raycast;
+ GDCLASS(CollisionShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- void redraw();
- RayCastSpatialGizmo(RayCast *p_raycast = NULL);
-};
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
+
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
-class VehicleWheelSpatialGizmo : public EditorSpatialGizmo {
+ CollisionShapeSpatialGizmoPlugin();
+};
- GDCLASS(VehicleWheelSpatialGizmo, EditorSpatialGizmo);
+class CollisionPolygonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- VehicleWheel *car_wheel;
+ GDCLASS(CollisionPolygonSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- void redraw();
- VehicleWheelSpatialGizmo(VehicleWheel *p_car_wheel = NULL);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
+
+ CollisionPolygonSpatialGizmoPlugin();
};
-class NavigationMeshSpatialGizmo : public EditorSpatialGizmo {
+class NavigationMeshSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- GDCLASS(NavigationMeshSpatialGizmo, EditorSpatialGizmo);
+ GDCLASS(NavigationMeshSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
struct _EdgeKey {
@@ -408,11 +353,12 @@ class NavigationMeshSpatialGizmo : public EditorSpatialGizmo {
bool operator<(const _EdgeKey &p_with) const { return from == p_with.from ? to < p_with.to : from < p_with.from; }
};
- NavigationMeshInstance *navmesh;
-
public:
- void redraw();
- NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh = NULL);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
+
+ NavigationMeshSpatialGizmoPlugin();
};
class JointGizmosDrawer {
@@ -421,7 +367,7 @@ public:
static Basis look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform);
static Basis look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform);
static Basis look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform);
- /// Special function just used for physics joints, it that returns a basis constrained toward Joint Z axis
+ /// Special function just used for physics joints, it returns a basis constrained toward Joint Z axis
/// with axis X and Y that are looking toward the body and oriented toward up
static Basis look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform);
@@ -430,66 +376,20 @@ public:
static void draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points);
};
-class PinJointSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(PinJointSpatialGizmo, EditorSpatialGizmo);
-
- PinJoint *p3d;
-
-public:
- static void CreateGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points);
-
- void redraw();
- PinJointSpatialGizmo(PinJoint *p_p3d = NULL);
-};
-
-class HingeJointSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(HingeJointSpatialGizmo, EditorSpatialGizmo);
-
- HingeJoint *p3d;
-
-public:
- static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
-
- void redraw();
- HingeJointSpatialGizmo(HingeJoint *p_p3d = NULL);
-};
-
-class SliderJointSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(SliderJointSpatialGizmo, EditorSpatialGizmo);
-
- SliderJoint *p3d;
-
-public:
- static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
-
- void redraw();
- SliderJointSpatialGizmo(SliderJoint *p_p3d = NULL);
-};
-
-class ConeTwistJointSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(ConeTwistJointSpatialGizmo, EditorSpatialGizmo);
+class JointSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- ConeTwistJoint *p3d;
+ GDCLASS(JointSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
-
- void redraw();
- ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d = NULL);
-};
-
-class Generic6DOFJointSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(Generic6DOFJointSpatialGizmo, EditorSpatialGizmo);
-
- Generic6DOFJoint *p3d;
-
-public:
- static void CreateGizmo(
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
+
+ static void CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points);
+ static void CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
+ static void CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
+ static void CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
+ static void CreateGeneric6DOFJointGizmo(
const Transform &p_offset,
const Transform &p_trs_joint,
const Transform &p_trs_body_a,
@@ -516,26 +416,7 @@ public:
Vector<Vector3> *r_body_a_points,
Vector<Vector3> *r_body_b_points);
- void redraw();
- Generic6DOFJointSpatialGizmo(Generic6DOFJoint *p_p3d = NULL);
+ JointSpatialGizmoPlugin();
};
-class SpatialEditorGizmos {
-
-public:
- HashMap<String, Ref<SpatialMaterial> > material_cache;
-
- Ref<SpatialMaterial> handle2_material;
- Ref<SpatialMaterial> handle2_material_billboard;
- Ref<SpatialMaterial> handle_material;
- Ref<SpatialMaterial> handle_material_billboard;
- Ref<Texture> handle_t;
- Ref<ArrayMesh> pos3d_mesh;
- Ref<ArrayMesh> listener_line_mesh;
- static SpatialEditorGizmos *singleton;
-
- Ref<SpatialEditorGizmo> get_gizmo(Spatial *p_spatial);
-
- SpatialEditorGizmos();
-};
#endif // SPATIAL_EDITOR_GIZMOS_H
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 9263a9ba6d..0857635492 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -644,20 +644,6 @@ float BulletPhysicsServer::body_get_param(RID p_body, BodyParameter p_param) con
return body->get_param(p_param);
}
-void BulletPhysicsServer::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) {
- RigidBodyBullet *body = rigid_body_owner.get(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_combine_mode(p_param, p_mode);
-}
-
-PhysicsServer::CombineMode BulletPhysicsServer::body_get_combine_mode(RID p_body, BodyParameter p_param) const {
- RigidBodyBullet *body = rigid_body_owner.get(p_body);
- ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT);
-
- return body->get_combine_mode(p_param);
-}
-
void BulletPhysicsServer::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
RigidBodyBullet *body = rigid_body_owner.get(p_body);
ERR_FAIL_COND(!body);
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 2c5b7e51cf..0e858ff311 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -213,9 +213,6 @@ public:
virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value);
virtual float body_get_param(RID p_body, BodyParameter p_param) const;
- virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode);
- virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const;
-
virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin);
virtual real_t body_get_kinematic_safe_margin(RID p_body) const;
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 81a62edba6..9c0e802be5 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -265,8 +265,6 @@ RigidBodyBullet::RigidBodyBullet() :
angularDamp(0),
can_sleep(true),
omit_forces_integration(false),
- restitution_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT),
- friction_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT),
force_integration_callback(NULL),
isTransformChanged(false),
previousActiveState(true),
@@ -761,22 +759,6 @@ Vector3 RigidBodyBullet::get_angular_velocity() const {
return gVec;
}
-void RigidBodyBullet::set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode) {
- if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) {
- restitution_combine_mode = p_mode;
- } else {
- friction_combine_mode = p_mode;
- }
-}
-
-PhysicsServer::CombineMode RigidBodyBullet::get_combine_mode(PhysicsServer::BodyParameter p_param) const {
- if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) {
- return restitution_combine_mode;
- } else {
- return friction_combine_mode;
- }
-}
-
void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transform) {
if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
// The kinematic use MotionState class
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index 35af3b90d8..f03009bce9 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -203,9 +203,6 @@ private:
bool can_sleep;
bool omit_forces_integration;
- PhysicsServer::CombineMode restitution_combine_mode;
- PhysicsServer::CombineMode friction_combine_mode;
-
Vector<CollisionData> collisions;
// these parameters are used to avoid vector resize
int maxCollisionsDetection;
@@ -301,12 +298,6 @@ public:
void set_angular_velocity(const Vector3 &p_velocity);
Vector3 get_angular_velocity() const;
- void set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode);
- PhysicsServer::CombineMode get_combine_mode(PhysicsServer::BodyParameter p_param) const;
-
- _FORCE_INLINE_ PhysicsServer::CombineMode get_restitution_combine_mode() const { return restitution_combine_mode; }
- _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; }
-
virtual void set_transform__bullet(const btTransform &p_global_transform);
virtual const btTransform &get_transform__bullet() const;
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index 8454bea4eb..97228a972f 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -554,42 +554,12 @@ BulletPhysicsDirectSpaceState *SpaceBullet::get_direct_state() {
btScalar calculateGodotCombinedRestitution(const btCollisionObject *body0, const btCollisionObject *body1) {
- const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_restitution_combine_mode();
-
- switch (cm) {
- case PhysicsServer::COMBINE_MODE_INHERIT:
- if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_restitution_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT)
- return calculateGodotCombinedRestitution(body1, body0);
- // else use MAX [This is used when the two bodies doesn't use physical material]
- case PhysicsServer::COMBINE_MODE_MAX:
- return MAX(body0->getRestitution(), body1->getRestitution());
- case PhysicsServer::COMBINE_MODE_MIN:
- return MIN(body0->getRestitution(), body1->getRestitution());
- case PhysicsServer::COMBINE_MODE_MULTIPLY:
- return body0->getRestitution() * body1->getRestitution();
- default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE:
- return (body0->getRestitution() + body1->getRestitution()) / 2;
- }
+ return CLAMP(body0->getRestitution() + body1->getRestitution(), 0, 1);
}
btScalar calculateGodotCombinedFriction(const btCollisionObject *body0, const btCollisionObject *body1) {
- const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_friction_combine_mode();
-
- switch (cm) {
- case PhysicsServer::COMBINE_MODE_INHERIT:
- if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_friction_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT)
- return calculateGodotCombinedFriction(body1, body0);
- // else use MULTIPLY [This is used when the two bodies doesn't use physical material]
- case PhysicsServer::COMBINE_MODE_MULTIPLY:
- return body0->getFriction() * body1->getFriction();
- case PhysicsServer::COMBINE_MODE_MAX:
- return MAX(body0->getFriction(), body1->getFriction());
- case PhysicsServer::COMBINE_MODE_MIN:
- return MIN(body0->getFriction(), body1->getFriction());
- default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE:
- return (body0->getFriction() * body1->getFriction()) / 2;
- }
+ return ABS(MIN(body0->getFriction(), body1->getFriction()));
}
void SpaceBullet::create_empty_world(bool p_create_soft_world) {
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp
index 3b1ddfe4c0..f9744c72af 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/csg_gizmos.cpp
@@ -32,7 +32,16 @@
///////////
-String CSGShapeSpatialGizmo::get_handle_name(int p_idx) const {
+CSGShapeSpatialGizmoPlugin::CSGShapeSpatialGizmoPlugin() {
+
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.2, 0.5, 1, 0.1));
+ create_material("shape_material", gizmo_color);
+ create_handle_material("handles");
+}
+
+String CSGShapeSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
if (Object::cast_to<CSGSphere>(cs)) {
@@ -57,7 +66,9 @@ String CSGShapeSpatialGizmo::get_handle_name(int p_idx) const {
return "";
}
-Variant CSGShapeSpatialGizmo::get_handle_value(int p_idx) const {
+Variant CSGShapeSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
if (Object::cast_to<CSGSphere>(cs)) {
@@ -89,10 +100,12 @@ Variant CSGShapeSpatialGizmo::get_handle_value(int p_idx) const {
return Variant();
}
-void CSGShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
+void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+ CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
Transform gt = cs->get_global_transform();
- gt.orthonormalize();
+ //gt.orthonormalize();
Transform gi = gt.affine_inverse();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
@@ -170,7 +183,9 @@ void CSGShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2
s->set_outer_radius(d);
}
}
-void CSGShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
+void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
if (Object::cast_to<CSGSphere>(cs)) {
CSGSphere *s = Object::cast_to<CSGSphere>(cs);
@@ -260,12 +275,26 @@ void CSGShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bo
ur->commit_action();
}
}
-void CSGShapeSpatialGizmo::redraw() {
+bool CSGShapeSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<CSGSphere>(p_spatial) || Object::cast_to<CSGBox>(p_spatial) || Object::cast_to<CSGCylinder>(p_spatial) || Object::cast_to<CSGTorus>(p_spatial) || Object::cast_to<CSGMesh>(p_spatial) || Object::cast_to<CSGPolygon>(p_spatial);
+}
- clear();
+String CSGShapeSpatialGizmoPlugin::get_name() const {
+ return "CSGShapes";
+}
+
+bool CSGShapeSpatialGizmoPlugin::is_selectable_when_hidden() const {
+ return true;
+}
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/csg");
- Ref<Material> material = create_material("shape_material", gizmo_color);
+void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Ref<Material> material = get_material("shape_material", p_gizmo);
+ Ref<Material> handles_material = get_material("handles");
PoolVector<Vector3> faces = cs->get_brush_faces();
@@ -284,8 +313,8 @@ void CSGShapeSpatialGizmo::redraw() {
}
}
- add_lines(lines, material);
- add_collision_segments(lines);
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
if (Object::cast_to<CSGSphere>(cs)) {
CSGSphere *s = Object::cast_to<CSGSphere>(cs);
@@ -293,7 +322,7 @@ void CSGShapeSpatialGizmo::redraw() {
float r = s->get_radius();
Vector<Vector3> handles;
handles.push_back(Vector3(r, 0, 0));
- add_handles(handles);
+ p_gizmo->add_handles(handles, handles_material);
}
if (Object::cast_to<CSGBox>(cs)) {
@@ -303,7 +332,7 @@ void CSGShapeSpatialGizmo::redraw() {
handles.push_back(Vector3(s->get_width(), 0, 0));
handles.push_back(Vector3(0, s->get_height(), 0));
handles.push_back(Vector3(0, 0, s->get_depth()));
- add_handles(handles);
+ p_gizmo->add_handles(handles, handles_material);
}
if (Object::cast_to<CSGCylinder>(cs)) {
@@ -312,7 +341,7 @@ void CSGShapeSpatialGizmo::redraw() {
Vector<Vector3> handles;
handles.push_back(Vector3(s->get_radius(), 0, 0));
handles.push_back(Vector3(0, s->get_height() * 0.5, 0));
- add_handles(handles);
+ p_gizmo->add_handles(handles, handles_material);
}
if (Object::cast_to<CSGTorus>(cs)) {
@@ -321,25 +350,11 @@ void CSGShapeSpatialGizmo::redraw() {
Vector<Vector3> handles;
handles.push_back(Vector3(s->get_inner_radius(), 0, 0));
handles.push_back(Vector3(s->get_outer_radius(), 0, 0));
- add_handles(handles);
- }
-}
-CSGShapeSpatialGizmo::CSGShapeSpatialGizmo(CSGShape *p_cs) {
-
- cs = p_cs;
- set_spatial_node(p_cs);
-}
-
-Ref<SpatialEditorGizmo> EditorPluginCSG::create_spatial_gizmo(Spatial *p_spatial) {
- if (Object::cast_to<CSGSphere>(p_spatial) || Object::cast_to<CSGBox>(p_spatial) || Object::cast_to<CSGCylinder>(p_spatial) || Object::cast_to<CSGTorus>(p_spatial) || Object::cast_to<CSGMesh>(p_spatial) || Object::cast_to<CSGPolygon>(p_spatial)) {
- Ref<CSGShapeSpatialGizmo> csg = memnew(CSGShapeSpatialGizmo(Object::cast_to<CSGShape>(p_spatial)));
- return csg;
+ p_gizmo->add_handles(handles, handles_material);
}
-
- return Ref<SpatialEditorGizmo>();
}
EditorPluginCSG::EditorPluginCSG(EditorNode *p_editor) {
-
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.2, 0.5, 1, 0.1));
+ Ref<CSGShapeSpatialGizmoPlugin> gizmo_plugin = Ref<CSGShapeSpatialGizmoPlugin>(memnew(CSGShapeSpatialGizmoPlugin));
+ SpatialEditor::get_singleton()->register_gizmo_plugin(gizmo_plugin);
}
diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h
index 68e916823b..d65d1f58c1 100644
--- a/modules/csg/csg_gizmos.h
+++ b/modules/csg/csg_gizmos.h
@@ -35,25 +35,27 @@
#include "editor/editor_plugin.h"
#include "editor/spatial_editor_gizmos.h"
-class CSGShapeSpatialGizmo : public EditorSpatialGizmo {
+class CSGShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- GDCLASS(CSGShapeSpatialGizmo, EditorSpatialGizmo);
-
- CSGShape *cs;
+ GDCLASS(CSGShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
- void redraw();
- CSGShapeSpatialGizmo(CSGShape *p_cs = NULL);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ bool is_selectable_when_hidden() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
+
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel);
+
+ CSGShapeSpatialGizmoPlugin();
};
class EditorPluginCSG : public EditorPlugin {
GDCLASS(EditorPluginCSG, EditorPlugin)
public:
- virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial);
EditorPluginCSG(EditorNode *p_editor);
};
diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_etc.cpp
index 8a674bc8c1..ddfa7af771 100644
--- a/modules/etc/image_etc.cpp
+++ b/modules/etc/image_etc.cpp
@@ -98,6 +98,33 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
Image::Format img_format = p_img->get_format();
Image::DetectChannels detected_channels = p_img->get_detected_channels();
+ if (p_source == Image::COMPRESS_SOURCE_LAYERED) {
+ //keep what comes in
+ switch (p_img->get_format()) {
+ case Image::FORMAT_L8: {
+ detected_channels = Image::DETECTED_L;
+ } break;
+ case Image::FORMAT_LA8: {
+ detected_channels = Image::DETECTED_LA;
+ } break;
+ case Image::FORMAT_R8: {
+ detected_channels = Image::DETECTED_R;
+ } break;
+ case Image::FORMAT_RG8: {
+ detected_channels = Image::DETECTED_RG;
+ } break;
+ case Image::FORMAT_RGB8: {
+ detected_channels = Image::DETECTED_RGB;
+ } break;
+ case Image::FORMAT_RGBA8:
+ case Image::FORMAT_RGBA4444:
+ case Image::FORMAT_RGBA5551: {
+ detected_channels = Image::DETECTED_RGBA;
+ } break;
+ default: {}
+ }
+ }
+
if (p_source == Image::COMPRESS_SOURCE_SRGB && (detected_channels == Image::DETECTED_R || detected_channels == Image::DETECTED_RG)) {
//R and RG do not support SRGB
detected_channels = Image::DETECTED_RGB;
@@ -147,7 +174,7 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
PoolVector<uint8_t>::Read r = img->get_data().read();
- int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps() ? -1 : 0);
+ int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps());
int mmc = 1 + (p_img->has_mipmaps() ? Image::get_image_required_mipmaps(imgw, imgh, etc_format) : 0);
PoolVector<uint8_t> dst_data;
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 23747af86b..0f3b497c94 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -1060,7 +1060,7 @@ Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const
s->set_class_name(p_class_name);
return Ref<NativeScript>(s);
}
-bool NativeScriptLanguage::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, Set<int> *r_safe_lines) const {
+bool NativeScriptLanguage::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 {
return true;
}
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index 1b39b63ad9..688ed295db 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -295,7 +295,7 @@ public:
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
- virtual bool 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, Set<int> *r_safe_lines = NULL) const;
+ virtual bool 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 = NULL, Set<int> *r_safe_lines = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp
index 816b0f0cab..2b538c4a36 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_language.cpp
@@ -108,7 +108,7 @@ Ref<Script> PluginScriptLanguage::get_template(const String &p_class_name, const
return script;
}
-bool PluginScriptLanguage::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, Set<int> *r_safe_lines) const {
+bool PluginScriptLanguage::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 {
PoolStringArray functions;
if (_desc.validate) {
bool ret = _desc.validate(
diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h
index 2443e31361..c4df6f3a33 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.h
+++ b/modules/gdnative/pluginscript/pluginscript_language.h
@@ -74,7 +74,7 @@ public:
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
- virtual bool 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 = NULL, Set<int> *r_safe_lines = NULL) const;
+ virtual bool 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 = NULL, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index cff3be76ae..ef6a42f145 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -596,6 +596,13 @@ Error GDScript::reload(bool p_keep_state) {
return err;
}
}
+#if DEBUG_ENABLED
+ for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) {
+ String msg = "Script warning: " + E->get().get_name() + " (" + path + ") line " + itos(E->get().line) + ": ";
+ msg += E->get().get_message();
+ WARN_PRINTS(msg);
+ }
+#endif
valid = true;
@@ -1867,6 +1874,162 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
return String();
}
+#ifdef DEBUG_ENABLED
+String GDScriptWarning::get_message() const {
+
+#define CHECK_SYMBOLS(m_amount) ERR_FAIL_COND_V(symbols.size() < m_amount, String());
+
+ switch (code) {
+ case UNASSIGNED_VARIABLE_OP_ASSIGN: {
+ CHECK_SYMBOLS(1);
+ return "Using assignment with operation but the variable '" + symbols[0] + "' was not previously assigned a value.";
+ } break;
+ case UNASSIGNED_VARIABLE: {
+ CHECK_SYMBOLS(1);
+ return "The variable '" + symbols[0] + "' was used but never assigned a value.";
+ } break;
+ case UNUSED_VARIABLE: {
+ CHECK_SYMBOLS(1);
+ return "The local variable '" + symbols[0] + "' is declared but never used in the block.";
+ } break;
+ case UNUSED_CLASS_VARIABLE: {
+ CHECK_SYMBOLS(1);
+ return "The class variable '" + symbols[0] + "' is declared but never used in the script.";
+ } break;
+ case UNUSED_ARGUMENT: {
+ CHECK_SYMBOLS(2);
+ return "The argument '" + symbols[1] + "' is never used in the function '" + symbols[0] + "'.";
+ } break;
+ case UNREACHABLE_CODE: {
+ CHECK_SYMBOLS(1);
+ return "Unreachable code (statement after return) in function '" + symbols[0] + "()'.";
+ } break;
+ case STANDALONE_EXPRESSION: {
+ return "Standalone expression (the line has no effect).";
+ } break;
+ case VOID_ASSIGNMENT: {
+ CHECK_SYMBOLS(1);
+ return "Assignment operation, but the function '" + symbols[0] + "()' returns void.";
+ } break;
+ case NARROWING_CONVERSION: {
+ return "Narrowing coversion (float is converted to int and lose precision).";
+ } break;
+ case FUNCTION_MAY_YIELD: {
+ CHECK_SYMBOLS(1);
+ return "Assigned variable is typed but the function '" + symbols[0] + "()' may yield and return a GDScriptFunctionState instead.";
+ } break;
+ case VARIABLE_CONFLICTS_FUNCTION: {
+ CHECK_SYMBOLS(1);
+ return "Variable declaration of '" + symbols[0] + "' conflicts with a function of the same name.";
+ } break;
+ case FUNCTION_CONFLICTS_VARIABLE: {
+ CHECK_SYMBOLS(1);
+ return "Function declaration of '" + symbols[0] + "()' conflicts with a variable of the same name.";
+ } break;
+ case FUNCTION_CONFLICTS_CONSTANT: {
+ CHECK_SYMBOLS(1);
+ return "Function declaration of '" + symbols[0] + "()' conflicts with a constant of the same name.";
+ } break;
+ case INCOMPATIBLE_TERNARY: {
+ return "Values of the ternary conditional are not mutually compatible.";
+ } break;
+ case UNUSED_SIGNAL: {
+ CHECK_SYMBOLS(1);
+ return "The signal '" + symbols[0] + "' is declared but never emitted.";
+ } break;
+ case RETURN_VALUE_DISCARDED: {
+ CHECK_SYMBOLS(1);
+ return "The function '" + symbols[0] + "()' returns a value, but this value is never used.";
+ } break;
+ case PROPERTY_USED_AS_FUNCTION: {
+ CHECK_SYMBOLS(2);
+ return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a property with the same name. Did you mean to access it?";
+ } break;
+ case CONSTANT_USED_AS_FUNCTION: {
+ CHECK_SYMBOLS(2);
+ return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a constant with the same name. Did you mean to access it?";
+ } break;
+ case FUNCTION_USED_AS_PROPERTY: {
+ CHECK_SYMBOLS(2);
+ return "The property '" + symbols[0] + "' was not found in base '" + symbols[1] + "' but there's a method with the same name. Did you mean to call it?";
+ } break;
+ case INTEGER_DIVISION: {
+ return "Integer division, decimal part will be discarded.";
+ } break;
+ case UNSAFE_PROPERTY_ACCESS: {
+ CHECK_SYMBOLS(2);
+ return "The property '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
+ } break;
+ case UNSAFE_METHOD_ACCESS: {
+ CHECK_SYMBOLS(2);
+ return "The method '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
+ } break;
+ case UNSAFE_CAST: {
+ CHECK_SYMBOLS(1);
+ return "The value is cast to '" + symbols[0] + "' but has an unkown type.";
+ } break;
+ case UNSAFE_CALL_ARGUMENT: {
+ CHECK_SYMBOLS(4);
+ return "The argument '" + symbols[0] + "' of the function '" + symbols[1] + "' requires a the subtype '" + symbols[2] + "' but the supertype '" + symbols[3] + "' was provided";
+ } break;
+ }
+ ERR_EXPLAIN("Invalid GDScript waring code: " + get_name_from_code(code));
+ ERR_FAIL_V(String());
+
+#undef CHECK_SYMBOLS
+}
+
+String GDScriptWarning::get_name() const {
+ return get_name_from_code(code);
+}
+
+String GDScriptWarning::get_name_from_code(Code p_code) {
+ ERR_FAIL_COND_V(p_code < 0 || p_code >= WARNING_MAX, String());
+
+ static const char *names[] = {
+ "UNASSIGNED_VARIABLE",
+ "UNASSIGNED_VARIABLE_OP_ASSIGN",
+ "UNUSED_VARIABLE",
+ "UNUSED_CLASS_VARIABLE",
+ "UNUSED_ARGUMENT",
+ "UNREACHABLE_CODE",
+ "STANDALONE_EXPRESSION",
+ "VOID_ASSIGNMENT",
+ "NARROWING_CONVERSION",
+ "FUNCTION_MAY_YIELD",
+ "VARIABLE_CONFLICTS_FUNCTION",
+ "FUNCTION_CONFLICTS_VARIABLE",
+ "FUNCTION_CONFLICTS_CONSTANT",
+ "INCOMPATIBLE_TERNARY",
+ "UNUSED_SIGNAL",
+ "RETURN_VALUE_DISCARDED",
+ "PROPERTY_USED_AS_FUNCTION",
+ "CONSTANT_USED_AS_FUNCTION",
+ "FUNCTION_USED_AS_PROPERTY",
+ "INTEGER_DIVISION",
+ "UNSAFE_PROPERTY_ACCESS",
+ "UNSAFE_METHOD_ACCESS",
+ "UNSAFE_CAST",
+ "UNSAFE_CALL_ARGUMENT",
+ NULL
+ };
+
+ return names[(int)p_code];
+}
+
+GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) {
+ for (int i = 0; i < WARNING_MAX; i++) {
+ if (get_name_from_code((Code)i) == p_name) {
+ return (Code)i;
+ }
+ }
+
+ ERR_EXPLAIN("Invalid GDScript waring name: " + p_name);
+ ERR_FAIL_V(WARNING_MAX);
+}
+
+#endif // DEBUG_ENABLED
+
GDScriptLanguage::GDScriptLanguage() {
calls = 0;
@@ -1903,6 +2066,15 @@ GDScriptLanguage::GDScriptLanguage() {
_debug_max_call_stack = 0;
_call_stack = NULL;
}
+
+#ifdef DEBUG_ENABLED
+ GLOBAL_DEF("debug/gdscript/warnings/enable", true);
+ GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false);
+ for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
+ String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
+ GLOBAL_DEF("debug/gdscript/warnings/" + warning, !warning.begins_with("unsafe_"));
+ }
+#endif // DEBUG_ENABLED
}
GDScriptLanguage::~GDScriptLanguage() {
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 79ac9ed413..edad12f1f3 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -261,6 +261,49 @@ public:
~GDScriptInstance();
};
+#ifdef DEBUG_ENABLED
+struct GDScriptWarning {
+ enum Code {
+ UNASSIGNED_VARIABLE, // Variable used but never assigned
+ UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc)
+ UNUSED_VARIABLE, // Local variable is declared but never used
+ UNUSED_CLASS_VARIABLE, // Class variable is declared but never used in the file
+ UNUSED_ARGUMENT, // Function argument is never used
+ UNREACHABLE_CODE, // Code after a return statement
+ STANDALONE_EXPRESSION, // Expression not assigned to a variable
+ VOID_ASSIGNMENT, // Function returns void but it's assigned to a variable
+ NARROWING_CONVERSION, // Float value into an integer slot, precision is lost
+ FUNCTION_MAY_YIELD, // Typed assign of function call that yields (it may return a function state)
+ VARIABLE_CONFLICTS_FUNCTION, // Variable has the same name of a function
+ FUNCTION_CONFLICTS_VARIABLE, // Function has the same name of a variable
+ FUNCTION_CONFLICTS_CONSTANT, // Function has the same name of a constant
+ INCOMPATIBLE_TERNARY, // Possible values of a ternary if are not mutually compatible
+ UNUSED_SIGNAL, // Signal is defined but never emitted
+ RETURN_VALUE_DISCARDED, // Function call returns something but the value isn't used
+ PROPERTY_USED_AS_FUNCTION, // Function not found, but there's a property with the same name
+ CONSTANT_USED_AS_FUNCTION, // Function not found, but there's a constant with the same name
+ FUNCTION_USED_AS_PROPERTY, // Property not found, but there's a function with the same name
+ INTEGER_DIVISION, // Integer divide by integer, decimal part is discarded
+ UNSAFE_PROPERTY_ACCESS, // Property not found in the detected type (but can be in subtypes)
+ UNSAFE_METHOD_ACCESS, // Fucntion not found in the detected type (but can be in subtypes)
+ UNSAFE_CAST, // Cast used in an unknown type
+ UNSAFE_CALL_ARGUMENT, // Function call argument is of a supertype of the require argument
+ WARNING_MAX,
+ } code;
+ Vector<String> symbols;
+ int line;
+
+ String get_name() const;
+ String get_message() const;
+ static String get_name_from_code(Code p_code);
+ static Code get_code_from_name(const String &p_name);
+
+ GDScriptWarning() :
+ line(-1),
+ code(WARNING_MAX) {}
+};
+#endif // DEBUG_ENABLED
+
class GDScriptLanguage : public ScriptLanguage {
static GDScriptLanguage *singleton;
@@ -397,7 +440,7 @@ public:
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);
- virtual bool 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 = NULL, Set<int> *r_safe_lines = NULL) const;
+ virtual bool 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 = NULL, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 2a42524ba7..abd56d2757 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -116,11 +116,24 @@ void GDScriptLanguage::make_template(const String &p_class_name, const String &p
p_script->set_source_code(src);
}
-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, Set<int> *r_safe_lines) const {
+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 {
GDScriptParser parser;
Error err = parser.parse(p_script, p_path.get_base_dir(), true, p_path, false, r_safe_lines);
+#ifdef DEBUG_ENABLED
+ if (r_warnings) {
+ for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) {
+ const GDScriptWarning &warn = E->get();
+ ScriptLanguage::Warning w;
+ w.line = warn.line;
+ w.code = (int)warn.code;
+ w.string_code = GDScriptWarning::get_name_from_code(warn.code);
+ w.message = warn.get_message();
+ r_warnings->push_back(w);
+ }
+ }
+#endif
if (err) {
r_line_error = parser.get_error_line();
r_col_error = parser.get_error_column();
@@ -2442,7 +2455,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
} break;
case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
List<StringName> constants;
- Variant::get_numeric_constants_for_type(parser.get_completion_built_in_constant(), &constants);
+ Variant::get_constants_for_type(parser.get_completion_built_in_constant(), &constants);
for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
options.insert(E->get().operator String());
}
@@ -3065,7 +3078,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
case GDScriptParser::DataType::BUILTIN: {
base_type.has_type = false;
- if (Variant::has_numeric_constant(base_type.builtin_type, p_symbol)) {
+ if (Variant::has_constant(base_type.builtin_type, p_symbol)) {
r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
r_result.class_name = Variant::get_type_name(base_type.builtin_type);
r_result.class_member = p_symbol;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 852d465206..177e245986 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -38,6 +38,7 @@
#include "io/resource_loader.h"
#include "os/file_access.h"
#include "print_string.h"
+#include "project_settings.h"
#include "script_language.h"
template <class T>
@@ -56,6 +57,8 @@ T *GDScriptParser::alloc_node() {
return t;
}
+static String _find_function_name(const GDScriptParser::OperatorNode *p_call);
+
bool GDScriptParser::_end_statement() {
if (tokenizer->get_token() == GDScriptTokenizer::TK_SEMICOLON) {
@@ -607,7 +610,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
_set_error("Built-in type constant or static function expected after '.'");
return NULL;
}
- if (!Variant::has_numeric_constant(bi_type, identifier)) {
+ if (!Variant::has_constant(bi_type, identifier)) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN &&
Variant::is_method_const(bi_type, identifier) &&
@@ -642,7 +645,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
} else {
ConstantNode *cn = alloc_node<ConstantNode>();
- cn->value = Variant::get_numeric_constant_value(bi_type, identifier);
+ cn->value = Variant::get_constant_value(bi_type, identifier);
cn->datatype = _type_from_variant(cn->value);
expr = cn;
}
@@ -726,7 +729,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
BlockNode *b = current_block;
- while (b) {
+ while (!bfn && b) {
if (b->variables.has(identifier)) {
IdentifierNode *id = alloc_node<IdentifierNode>();
LocalVarNode *lv = b->variables[identifier];
@@ -736,6 +739,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
expr = id;
bfn = true;
+#ifdef DEBUG_ENABLED
switch (tokenizer->get_token()) {
case GDScriptTokenizer::TK_OP_ASSIGN_ADD:
case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND:
@@ -747,15 +751,23 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT:
case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT:
case GDScriptTokenizer::TK_OP_ASSIGN_SUB: {
- if (lv->assignments == 0 && !lv->datatype.has_type) {
- _set_error("Using assignment with operation on a variable that was never assigned.");
- return NULL;
+ if (lv->assignments == 0) {
+ if (!lv->datatype.has_type) {
+ _set_error("Using assignment with operation on a variable that was never assigned.");
+ return NULL;
+ }
+ _add_warning(GDScriptWarning::UNASSIGNED_VARIABLE_OP_ASSIGN, -1, identifier.operator String());
}
} // fallthrough
case GDScriptTokenizer::TK_OP_ASSIGN: {
lv->assignments += 1;
+ lv->usages--; // Assignment is not really usage
+ } break;
+ default: {
+ lv->usages++;
}
}
+#endif // DEBUG_ENABLED
break;
}
b = b->parent_block;
@@ -785,6 +797,32 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
if (!bfn) {
+#ifdef DEBUG_ENABLED
+ if (current_function) {
+ int arg_idx = current_function->arguments.find(identifier);
+ if (arg_idx != -1) {
+ switch (tokenizer->get_token()) {
+ case GDScriptTokenizer::TK_OP_ASSIGN_ADD:
+ case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND:
+ case GDScriptTokenizer::TK_OP_ASSIGN_BIT_OR:
+ case GDScriptTokenizer::TK_OP_ASSIGN_BIT_XOR:
+ case GDScriptTokenizer::TK_OP_ASSIGN_DIV:
+ case GDScriptTokenizer::TK_OP_ASSIGN_MOD:
+ case GDScriptTokenizer::TK_OP_ASSIGN_MUL:
+ case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT:
+ case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT:
+ case GDScriptTokenizer::TK_OP_ASSIGN_SUB:
+ case GDScriptTokenizer::TK_OP_ASSIGN: {
+ // Assignment is not really usage
+ current_function->arguments_usage.write[arg_idx] = current_function->arguments_usage[arg_idx] - 1;
+ } break;
+ default: {
+ current_function->arguments_usage.write[arg_idx] = current_function->arguments_usage[arg_idx] + 1;
+ }
+ }
+ }
+ }
+#endif // DEBUG_ENABLED
IdentifierNode *id = alloc_node<IdentifierNode>();
id->name = identifier;
id->line = id_line;
@@ -2601,6 +2639,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
pending_newline = -1;
}
+#ifdef DEBUG_ENABLED
switch (token) {
case GDScriptTokenizer::TK_EOF:
case GDScriptTokenizer::TK_ERROR:
@@ -2609,13 +2648,13 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
// will check later
} break;
default: {
- // TODO: Make this a warning
- /*if (p_block->has_return) {
- _set_error("Unreacheable code.");
- return;
- }*/
+ if (p_block->has_return && !current_function->has_unreachable_code) {
+ _add_warning(GDScriptWarning::UNREACHABLE_CODE, -1, current_function->name.operator String());
+ current_function->has_unreachable_code = true;
+ }
} break;
}
+#endif // DEBUG_ENABLED
switch (token) {
case GDScriptTokenizer::TK_EOF:
p_block->end_line = tokenizer->get_token_line();
@@ -2728,6 +2767,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
c->line = var_line;
assigned = c;
}
+ lv->assign = assigned;
//must be added later, to avoid self-referencing.
p_block->variables.insert(n, lv);
@@ -2745,6 +2785,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
lv->assign_op = op;
lv->assign = assigned;
+ lv->assign_op = op;
+
if (!_end_statement()) {
_set_error("Expected end of statement (var)");
return;
@@ -3513,6 +3555,17 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
}
+#ifdef DEBUG_ENABLED
+ if (p_class->constant_expressions.has(name)) {
+ _add_warning(GDScriptWarning::FUNCTION_CONFLICTS_CONSTANT, -1, name);
+ }
+ for (int i = 0; i < p_class->variables.size(); i++) {
+ if (p_class->variables[i].identifier == name) {
+ _add_warning(GDScriptWarning::FUNCTION_CONFLICTS_VARIABLE, -1, name);
+ }
+ }
+#endif // DEBUG_ENABLED
+
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
_set_error("Expected '(' after identifier (syntax: 'func <identifier>([arguments]):' ).");
@@ -3524,6 +3577,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
Vector<StringName> arguments;
Vector<DataType> argument_types;
Vector<Node *> default_values;
+#ifdef DEBUG_ENABLED
+ Vector<int> arguments_usage;
+#endif // DEBUG_ENABLED
int fnline = tokenizer->get_token_line();
@@ -3550,6 +3606,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
StringName argname = tokenizer->get_token_identifier();
arguments.push_back(argname);
+#ifdef DEBUG_ENABLED
+ arguments_usage.push_back(0);
+#endif // DEBUG_ENABLED
tokenizer->advance();
@@ -3703,7 +3762,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
function->default_values = default_values;
function->_static = _static;
function->line = fnline;
-
+#ifdef DEBUG_ENABLED
+ function->arguments_usage = arguments_usage;
+#endif // DEBUG_ENABLED
function->rpc_mode = rpc_mode;
rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
@@ -3730,6 +3791,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
ClassNode::Signal sig;
sig.name = tokenizer->get_token_identifier();
+ sig.emissions = 0;
+ sig.line = tokenizer->get_token_line();
tokenizer->advance();
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
@@ -4413,6 +4476,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
member.expression = NULL;
member._export.name = member.identifier;
member.line = tokenizer->get_token_line();
+ member.usages = 0;
member.rpc_mode = rpc_mode;
if (current_class->constant_expressions.has(member.identifier)) {
@@ -4428,7 +4492,20 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
}
-
+#ifdef DEBUG_ENABLED
+ for (int i = 0; i < current_class->functions.size(); i++) {
+ if (current_class->functions[i]->name == member.identifier) {
+ _add_warning(GDScriptWarning::VARIABLE_CONFLICTS_FUNCTION, member.line, member.identifier);
+ break;
+ }
+ }
+ for (int i = 0; i < current_class->static_functions.size(); i++) {
+ if (current_class->static_functions[i]->name == member.identifier) {
+ _add_warning(GDScriptWarning::VARIABLE_CONFLICTS_FUNCTION, member.line, member.identifier);
+ break;
+ }
+ }
+#endif // DEBUG_ENABLED
tokenizer->advance();
rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
@@ -5689,11 +5766,26 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
node_type.has_type = true;
node_type.kind = DataType::BUILTIN;
node_type.builtin_type = Variant::ARRAY;
+#ifdef DEBUG_ENABLED
+ // Check stuff inside the array
+ ArrayNode *an = static_cast<ArrayNode *>(p_node);
+ for (int i = 0; i < an->elements.size(); i++) {
+ _reduce_node_type(an->elements[i]);
+ }
+#endif // DEBUG_ENABLED
} break;
case Node::TYPE_DICTIONARY: {
node_type.has_type = true;
node_type.kind = DataType::BUILTIN;
node_type.builtin_type = Variant::DICTIONARY;
+#ifdef DEBUG_ENABLED
+ // Check stuff inside the dictionarty
+ DictionaryNode *dn = static_cast<DictionaryNode *>(p_node);
+ for (int i = 0; i < dn->elements.size(); i++) {
+ _reduce_node_type(dn->elements[i].key);
+ _reduce_node_type(dn->elements[i].value);
+ }
+#endif // DEBUG_ENABLED
} break;
case Node::TYPE_SELF: {
node_type.has_type = true;
@@ -5704,6 +5796,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
IdentifierNode *id = static_cast<IdentifierNode *>(p_node);
if (id->declared_block) {
node_type = id->declared_block->variables[id->name]->get_datatype();
+ id->declared_block->variables[id->name]->usages += 1;
+ print_line("var " + id->name + " line " + itos(id->line) + " usages " + itos(id->declared_block->variables[id->name]->usages));
} else if (id->name == "#match_value") {
// It's a special id just for the match statetement, ignore
break;
@@ -5738,6 +5832,9 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
}
}
} else {
+#ifdef DEBUG_ENABLED
+ _add_warning(GDScriptWarning::UNSAFE_CAST, cn->line, cn->cast_type.to_string());
+#endif // DEBUG_ENABLED
_mark_line_as_unsafe(cn->line);
}
@@ -5864,6 +5961,12 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
op->line, op->column);
return DataType();
}
+#ifdef DEBUG_ENABLED
+ if (var_op == Variant::OP_DIVIDE && argument_a_type.has_type && argument_a_type.kind == DataType::BUILTIN && argument_a_type.builtin_type == Variant::INT &&
+ argument_b_type.has_type && argument_b_type.kind == DataType::BUILTIN && argument_b_type.builtin_type == Variant::INT) {
+ _add_warning(GDScriptWarning::INTEGER_DIVISION, op->line);
+ }
+#endif // DEBUG_ENABLED
} break;
// Ternary operators
@@ -5882,10 +5985,11 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
node_type = true_type;
} else if (_is_type_compatible(false_type, true_type)) {
node_type = false_type;
+ } else {
+#ifdef DEBUG_ENABLED
+ _add_warning(GDScriptWarning::INCOMPATIBLE_TERNARY, op->line);
+#endif // DEBUG_ENABLED
}
-
- // TODO: Warn if types aren't compatible
-
} break;
// Assignment should never happen within an expression
case OperatorNode::OP_ASSIGN:
@@ -5948,6 +6052,11 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
node_type = result;
} else {
node_type = _reduce_identifier_type(&base_type, member_id->name, op->line);
+#ifdef DEBUG_ENABLED
+ if (!node_type.has_type) {
+ _add_warning(GDScriptWarning::UNSAFE_PROPERTY_ACCESS, op->line, member_id->name.operator String(), base_type.to_string());
+ }
+#endif // DEBUG_ENABLED
}
} else {
_mark_line_as_unsafe(op->line);
@@ -6367,6 +6476,15 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
if (!_is_type_compatible(arg_type, par_types[i], true)) {
types_match = false;
break;
+ } else {
+#ifdef DEBUG_ENABLED
+ if (arg_type.kind == DataType::BUILTIN && arg_type.builtin_type == Variant::INT && par_types[i].kind == DataType::BUILTIN && par_types[i].builtin_type == Variant::REAL) {
+ _add_warning(GDScriptWarning::NARROWING_CONVERSION, p_call->line, Variant::get_type_name(tn->vtype));
+ }
+ if (par_types[i].may_yield && p_call->arguments[i + 1]->type == Node::TYPE_OPERATOR) {
+ _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, p_call->line, _find_function_name(static_cast<OperatorNode *>(p_call->arguments[i + 1])));
+ }
+#endif // DEBUG_ENABLED
}
}
@@ -6400,6 +6518,13 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
return_type = _type_from_property(mi.return_val, false);
+#ifdef DEBUG_ENABLED
+ // Check all arguments beforehand to solve warnings
+ for (int i = 1; i < p_call->arguments.size(); i++) {
+ _reduce_node_type(p_call->arguments[i]);
+ }
+#endif // DEBUG_ENABLED
+
// Check arguments
is_vararg = mi.flags & METHOD_FLAG_VARARG;
@@ -6426,6 +6551,13 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
ERR_FAIL_V(DataType());
}
+#ifdef DEBUG_ENABLED
+ // Check all arguments beforehand to solve warnings
+ for (int i = arg_id + 1; i < p_call->arguments.size(); i++) {
+ _reduce_node_type(p_call->arguments[i]);
+ }
+#endif // DEBUG_ENABLED
+
IdentifierNode *func_id = static_cast<IdentifierNode *>(p_call->arguments[arg_id]);
callee_name = func_id->name;
arg_count -= 1 + arg_id;
@@ -6505,8 +6637,18 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
_set_error("Method '" + callee_name + "' is not declared in the current class.", p_call->line);
return DataType();
}
+ DataType tmp_type;
+ valid = _get_member_type(original_type, func_id->name, tmp_type);
+ if (valid) {
+ if (tmp_type.is_constant) {
+ _add_warning(GDScriptWarning::CONSTANT_USED_AS_FUNCTION, p_call->line, callee_name, original_type.to_string());
+ } else {
+ _add_warning(GDScriptWarning::PROPERTY_USED_AS_FUNCTION, p_call->line, callee_name, original_type.to_string());
+ }
+ }
+ _add_warning(GDScriptWarning::UNSAFE_METHOD_ACCESS, p_call->line, callee_name, original_type.to_string());
_mark_line_as_unsafe(p_call->line);
-#endif
+#endif // DEBUG_ENABLED
return DataType();
}
@@ -6522,7 +6664,19 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
_set_error("Non-static function '" + String(callee_name) + "' can only be called from an instance.", p_call->line);
return DataType();
}
-#endif
+
+ // Check signal emission for warnings
+ if (callee_name == "emit_signal" && p_call->op == OperatorNode::OP_CALL && p_call->arguments[0]->type == Node::TYPE_SELF && p_call->arguments.size() >= 3 && p_call->arguments[2]->type == Node::TYPE_CONSTANT) {
+ ConstantNode *sig = static_cast<ConstantNode *>(p_call->arguments[2]);
+ String emitted = sig->value.get_type() == Variant::STRING ? sig->value.operator String() : "";
+ for (int i = 0; i < current_class->_signals.size(); i++) {
+ if (current_class->_signals[i].name == emitted) {
+ current_class->_signals.write[i].emissions += 1;
+ break;
+ }
+ }
+ }
+#endif // DEBUG_ENABLED
} break;
}
@@ -6547,8 +6701,15 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
continue;
}
+ DataType arg_type = arg_types[i - arg_diff];
+
if (!par_type.has_type) {
_mark_line_as_unsafe(p_call->line);
+#ifdef DEBUG_ENABLED
+ if (par_type.may_yield && p_call->arguments[i]->type == Node::TYPE_OPERATOR) {
+ _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, p_call->line, _find_function_name(static_cast<OperatorNode *>(p_call->arguments[i])));
+ }
+#endif // DEBUG_ENABLED
} else if (!_is_type_compatible(arg_types[i - arg_diff], par_type, true)) {
// Supertypes are acceptable for dynamic compliance
if (!_is_type_compatible(par_type, arg_types[i - arg_diff])) {
@@ -6560,6 +6721,12 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
} else {
_mark_line_as_unsafe(p_call->line);
}
+ } else {
+#ifdef DEBUG_ENABLED
+ if (arg_type.kind == DataType::BUILTIN && arg_type.builtin_type == Variant::INT && par_type.kind == DataType::BUILTIN && par_type.builtin_type == Variant::REAL) {
+ _add_warning(GDScriptWarning::NARROWING_CONVERSION, p_call->line, callee_name);
+ }
+#endif // DEBUG_ENABLED
}
}
@@ -6795,6 +6962,15 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
DataType member_type;
+ for (int i = 0; i < current_class->variables.size(); i++) {
+ ClassNode::Member m = current_class->variables[i];
+ if (current_class->variables[i].identifier == p_identifier) {
+ member_type = current_class->variables[i].data_type;
+ current_class->variables.write[i].usages += 1;
+ return member_type;
+ }
+ }
+
if (_get_member_type(base_type, p_identifier, member_type)) {
return member_type;
}
@@ -6922,6 +7098,19 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
_set_error("Identifier '" + p_identifier.operator String() + "' is not declared in the current scope.", p_line);
}
+#ifdef DEBUG_ENABLED
+ {
+ DataType tmp_type;
+ List<DataType> arg_types;
+ int argcount;
+ bool _static;
+ bool vararg;
+ if (_get_function_signature(base_type, p_identifier, tmp_type, arg_types, argcount, _static, vararg)) {
+ _add_warning(GDScriptWarning::FUNCTION_USED_AS_PROPERTY, p_line, p_identifier.operator String(), base_type.to_string());
+ }
+ }
+#endif // DEBUG_ENABLED
+
_mark_line_as_unsafe(p_line);
return DataType();
}
@@ -7174,6 +7363,11 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
}
}
}
+#ifdef DEBUG_ENABLED
+ if (p_function->arguments_usage[i] == 0) {
+ _add_warning(GDScriptWarning::UNUSED_ARGUMENT, p_function->line, p_function->name, p_function->arguments[i].operator String());
+ }
+#endif // DEBUG_ENABLED
}
if (!(p_function->name == "_init")) {
@@ -7244,6 +7438,7 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
if (p_function->has_yield) {
// yield() will make the function return a GDScriptFunctionState, so the type is ambiguous
p_function->return_type.has_type = false;
+ p_function->return_type.may_yield = true;
}
}
@@ -7270,6 +7465,20 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) {
if (error_set) return;
}
+#ifdef DEBUG_ENABLED
+ // Warnings
+ for (int i = 0; i < p_class->variables.size(); i++) {
+ if (p_class->variables[i].usages == 0) {
+ _add_warning(GDScriptWarning::UNUSED_CLASS_VARIABLE, p_class->variables[i].line, p_class->variables[i].identifier);
+ }
+ }
+ for (int i = 0; i < p_class->_signals.size(); i++) {
+ if (p_class->_signals[i].emissions == 0) {
+ _add_warning(GDScriptWarning::UNUSED_SIGNAL, p_class->_signals[i].line, p_class->_signals[i].name);
+ }
+ }
+#endif // DEBUG_ENABLED
+
// Inner classes
for (int i = 0; i < p_class->subclasses.size(); i++) {
current_class = p_class->subclasses[i];
@@ -7279,6 +7488,26 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) {
}
}
+#ifdef DEBUG_ENABLED
+static String _find_function_name(const GDScriptParser::OperatorNode *p_call) {
+ switch (p_call->arguments[0]->type) {
+ case GDScriptParser::Node::TYPE_TYPE: {
+ return Variant::get_type_name(static_cast<GDScriptParser::TypeNode *>(p_call->arguments[0])->vtype);
+ } break;
+ case GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION: {
+ return GDScriptFunctions::get_func_name(static_cast<GDScriptParser::BuiltInFunctionNode *>(p_call->arguments[0])->function);
+ } break;
+ default: {
+ int id_index = p_call->op == GDScriptParser::OperatorNode::OP_PARENT_CALL ? 0 : 1;
+ if (p_call->arguments.size() > id_index && p_call->arguments[id_index]->type == GDScriptParser::Node::TYPE_IDENTIFIER) {
+ return static_cast<GDScriptParser::IdentifierNode *>(p_call->arguments[id_index])->name;
+ }
+ } break;
+ }
+ return String();
+}
+#endif // DEBUG_ENABLED
+
void GDScriptParser::_check_block_types(BlockNode *p_block) {
Node *last_var_assign = NULL;
@@ -7297,8 +7526,23 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
lv->datatype = _resolve_type(lv->datatype, lv->line);
_mark_line_as_safe(lv->line);
+ last_var_assign = lv->assign;
if (lv->assign) {
DataType assign_type = _reduce_node_type(lv->assign);
+#ifdef DEBUG_ENABLED
+ if (assign_type.has_type && assign_type.kind == DataType::BUILTIN && assign_type.builtin_type == Variant::NIL) {
+ if (lv->assign->type == Node::TYPE_OPERATOR) {
+ OperatorNode *call = static_cast<OperatorNode *>(lv->assign);
+ if (call->op == OperatorNode::OP_CALL || call->op == OperatorNode::OP_PARENT_CALL) {
+ _add_warning(GDScriptWarning::VOID_ASSIGNMENT, lv->line, _find_function_name(call));
+ }
+ }
+ }
+ if (lv->datatype.has_type && assign_type.may_yield && lv->assign->type == Node::TYPE_OPERATOR) {
+ _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, lv->line, _find_function_name(static_cast<OperatorNode *>(lv->assign)));
+ }
+#endif // DEBUG_ENABLED
+
if (!_is_type_compatible(lv->datatype, assign_type)) {
// Try supertype test
if (_is_type_compatible(assign_type, lv->datatype)) {
@@ -7329,6 +7573,11 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
lv->assign = convert_call;
lv->assign_op->arguments.write[1] = convert_call;
+#ifdef DEBUG_ENABLED
+ if (lv->datatype.builtin_type == Variant::INT && assign_type.builtin_type == Variant::REAL) {
+ _add_warning(GDScriptWarning::NARROWING_CONVERSION, lv->line);
+ }
+#endif // DEBUG_ENABLED
}
}
if (lv->datatype.infer_type) {
@@ -7343,15 +7592,6 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
_mark_line_as_unsafe(lv->line);
}
}
- last_var_assign = lv->assign;
-
- // TODO: Make a warning
- /*
- if (lv->assignments == 0) {
- _set_error("Variable '" + String(lv->name) + "' is never assigned.", lv->line);
- return;
- }
- */
} break;
case Node::TYPE_OPERATOR: {
OperatorNode *op = static_cast<OperatorNode *>(statement);
@@ -7417,6 +7657,19 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
} else {
rh_type = _reduce_node_type(op->arguments[1]);
}
+#ifdef DEBUG_ENABLED
+ if (rh_type.has_type && rh_type.kind == DataType::BUILTIN && rh_type.builtin_type == Variant::NIL) {
+ if (op->arguments[1]->type == Node::TYPE_OPERATOR) {
+ OperatorNode *call = static_cast<OperatorNode *>(op->arguments[1]);
+ if (call->op == OperatorNode::OP_CALL || call->op == OperatorNode::OP_PARENT_CALL) {
+ _add_warning(GDScriptWarning::VOID_ASSIGNMENT, op->line, _find_function_name(call));
+ }
+ }
+ }
+ if (lh_type.has_type && rh_type.may_yield && op->arguments[1]->type == Node::TYPE_OPERATOR) {
+ _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, op->line, _find_function_name(static_cast<OperatorNode *>(op->arguments[1])));
+ }
+#endif // DEBUG_ENABLED
if (!_is_type_compatible(lh_type, rh_type)) {
// Try supertype test
@@ -7447,6 +7700,11 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
convert_call->arguments.push_back(tgt_type);
op->arguments.write[1] = convert_call;
+#ifdef DEBUG_ENABLED
+ if (lh_type.builtin_type == Variant::INT && rh_type.builtin_type == Variant::REAL) {
+ _add_warning(GDScriptWarning::NARROWING_CONVERSION, op->line);
+ }
+#endif // DEBUG_ENABLED
}
}
if (!rh_type.has_type && (op->op != OperatorNode::OP_ASSIGN || lh_type.has_type || op->arguments[0]->type == Node::TYPE_OPERATOR)) {
@@ -7456,15 +7714,29 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
case OperatorNode::OP_CALL:
case OperatorNode::OP_PARENT_CALL: {
_mark_line_as_safe(op->line);
- _reduce_function_call_type(op);
+ DataType func_type = _reduce_function_call_type(op);
+#ifdef DEBUG_ENABLED
+ if (func_type.has_type && (func_type.kind != DataType::BUILTIN || func_type.builtin_type != Variant::NIL)) {
+ // Figure out function name for warning
+ String func_name = _find_function_name(op);
+ if (func_name.empty()) {
+ func_name == "<undetected name>";
+ }
+ _add_warning(GDScriptWarning::RETURN_VALUE_DISCARDED, op->line, func_name);
+ }
+#endif // DEBUG_ENABLED
if (error_set) return;
} break;
+ case OperatorNode::OP_YIELD: {
+ _mark_line_as_safe(op->line);
+ _reduce_node_type(op);
+ } break;
default: {
_mark_line_as_safe(op->line);
_reduce_node_type(op); // Test for safety anyway
- // TODO: Make this a warning
- /*_set_error("Standalone expression, nothing is done in this line.", statement->line);
- return; */
+#ifdef DEBUG_ENABLED
+ _add_warning(GDScriptWarning::STANDALONE_EXPRESSION, statement->line);
+#endif // DEBUG_ENABLED
}
}
} break;
@@ -7531,9 +7803,9 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
default: {
_mark_line_as_safe(statement->line);
_reduce_node_type(statement); // Test for safety anyway
- // TODO: Make this a warning
- /* _set_error("Standalone expression, nothing is done in this line.", statement->line);
- return; */
+#ifdef DEBUG_ENABLED
+ _add_warning(GDScriptWarning::STANDALONE_EXPRESSION, statement->line);
+#endif // DEBUG_ENABLED
}
}
}
@@ -7545,6 +7817,18 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
current_block = p_block;
if (error_set) return;
}
+
+#ifdef DEBUG_ENABLED
+ // Warnings check
+ for (Map<StringName, LocalVarNode *>::Element *E = p_block->variables.front(); E; E = E->next()) {
+ LocalVarNode *lv = E->get();
+ if (lv->usages == 0) {
+ _add_warning(GDScriptWarning::UNUSED_VARIABLE, lv->line, lv->name);
+ } else if (lv->assignments == 0) {
+ _add_warning(GDScriptWarning::UNASSIGNED_VARIABLE, lv->line, lv->name);
+ }
+ }
+#endif // DEBUG_ENABLED
}
void GDScriptParser::_set_error(const String &p_error, int p_line, int p_column) {
@@ -7558,6 +7842,56 @@ void GDScriptParser::_set_error(const String &p_error, int p_line, int p_column)
error_set = true;
}
+#ifdef DEBUG_ENABLED
+void GDScriptParser::_add_warning(int p_code, int p_line, const String &p_symbol1, const String &p_symbol2, const String &p_symbol3, const String &p_symbol4) {
+ Vector<String> symbols;
+ if (!p_symbol1.empty()) {
+ symbols.push_back(p_symbol1);
+ }
+ if (!p_symbol2.empty()) {
+ symbols.push_back(p_symbol2);
+ }
+ if (!p_symbol3.empty()) {
+ symbols.push_back(p_symbol3);
+ }
+ if (!p_symbol4.empty()) {
+ symbols.push_back(p_symbol4);
+ }
+ _add_warning(p_code, p_line, symbols);
+}
+
+void GDScriptParser::_add_warning(int p_code, int p_line, const Vector<String> &p_symbols) {
+ if (tokenizer->is_ignoring_warnings() || !GLOBAL_GET("debug/gdscript/warnings/enable").booleanize()) {
+ return;
+ }
+ String warn_name = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)p_code).to_lower();
+ if (tokenizer->get_warning_global_skips().has(warn_name)) {
+ return;
+ }
+ if (!GLOBAL_GET("debug/gdscript/warnings/" + warn_name)) {
+ return;
+ }
+
+ GDScriptWarning warn;
+ warn.code = (GDScriptWarning::Code)p_code;
+ warn.symbols = p_symbols;
+ warn.line = p_line == -1 ? tokenizer->get_token_line() : p_line;
+
+ List<GDScriptWarning>::Element *before = NULL;
+ for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) {
+ if (E->get().line > warn.line) {
+ break;
+ }
+ before = E;
+ }
+ if (before) {
+ warnings.insert_after(before, warn);
+ } else {
+ warnings.push_front(warn);
+ }
+}
+#endif // DEBUG_ENABLED
+
String GDScriptParser::get_error() const {
return error;
@@ -7624,6 +7958,37 @@ Error GDScriptParser::_parse(const String &p_base_path) {
return ERR_PARSE_ERROR;
}
+#ifdef DEBUG_ENABLED
+ // Resolve warning ignores
+ Vector<Pair<int, String> > warning_skips = tokenizer->get_warning_skips();
+ bool warning_is_error = GLOBAL_GET("debug/gdscript/warnings/treat_warnings_as_errors").booleanize();
+ for (List<GDScriptWarning>::Element *E = warnings.front(); E;) {
+ GDScriptWarning &w = E->get();
+ int skip_index = -1;
+ for (int i = 0; i < warning_skips.size(); i++) {
+ if (warning_skips[i].first >= w.line) {
+ break;
+ }
+ skip_index = i;
+ }
+ List<GDScriptWarning>::Element *next = E->next();
+ bool erase = false;
+ if (skip_index != -1) {
+ if (warning_skips[skip_index].second == GDScriptWarning::get_name_from_code(w.code).to_lower()) {
+ erase = true;
+ }
+ warning_skips.remove(skip_index);
+ }
+ if (erase) {
+ warnings.erase(E);
+ } else if (warning_is_error) {
+ _set_error(w.get_message() + " (warning treated as error)", w.line);
+ return ERR_PARSE_ERROR;
+ }
+ E = next;
+ }
+#endif // DEBUG_ENABLED
+
return OK;
}
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 48f256b4c6..d8ee4e8159 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -38,6 +38,7 @@
#include "script_language.h"
struct GDScriptDataType;
+struct GDScriptWarning;
class GDScriptParser {
public:
@@ -57,6 +58,7 @@ public:
bool is_constant;
bool is_meta_type; // Whether the value can be used as a type
bool infer_type;
+ bool may_yield; // For function calls
Variant::Type builtin_type;
StringName native_type;
@@ -95,6 +97,7 @@ public:
is_constant(false),
is_meta_type(false),
infer_type(false),
+ may_yield(false),
builtin_type(Variant::NIL),
class_type(NULL) {}
};
@@ -160,6 +163,7 @@ public:
Node *expression;
OperatorNode *initial_assignment;
MultiplayerAPI::RPCMode rpc_mode;
+ int usages;
};
struct Constant {
Node *expression;
@@ -169,6 +173,8 @@ public:
struct Signal {
StringName name;
Vector<StringName> arguments;
+ int emissions;
+ int line;
};
Vector<ClassNode *> subclasses;
@@ -197,12 +203,16 @@ public:
bool _static;
MultiplayerAPI::RPCMode rpc_mode;
bool has_yield;
+ bool has_unreachable_code;
StringName name;
DataType return_type;
Vector<StringName> arguments;
Vector<DataType> argument_types;
Vector<Node *> default_values;
BlockNode *body;
+#ifdef DEBUG_ENABLED
+ Vector<int> arguments_usage;
+#endif // DEBUG_ENABLED
virtual DataType get_datatype() const { return return_type; }
virtual void set_datatype(const DataType &p_datatype) { return_type = p_datatype; }
@@ -212,6 +222,7 @@ public:
_static = false;
rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
has_yield = false;
+ has_unreachable_code = false;
}
};
@@ -267,6 +278,7 @@ public:
Node *assign;
OperatorNode *assign_op;
int assignments;
+ int usages;
DataType datatype;
virtual DataType get_datatype() const { return datatype; }
virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; }
@@ -275,6 +287,7 @@ public:
assign = NULL;
assign_op = NULL;
assignments = 0;
+ usages = 0;
}
};
@@ -518,6 +531,10 @@ private:
Set<int> *safe_lines;
#endif // DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
+ List<GDScriptWarning> warnings;
+#endif // DEBUG_ENABLED
+
int pending_newline;
List<int> tab_level;
@@ -550,6 +567,10 @@ private:
MultiplayerAPI::RPCMode rpc_mode;
void _set_error(const String &p_error, int p_line = -1, int p_column = -1);
+#ifdef DEBUG_ENABLED
+ void _add_warning(int p_code, int p_line = -1, const String &p_symbol1 = String(), const String &p_symbol2 = String(), const String &p_symbol3 = String(), const String &p_symbol4 = String());
+ void _add_warning(int p_code, int p_line, const Vector<String> &p_symbols);
+#endif // DEBUG_ENABLED
bool _recover_from_completion();
bool _parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete = false);
@@ -605,6 +626,9 @@ public:
String get_error() const;
int get_error_line() const;
int get_error_column() const;
+#ifdef DEBUG_ENABLED
+ const List<GDScriptWarning> &get_warnings() const { return warnings; }
+#endif // DEBUG_ENABLED
Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = NULL);
Error parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path = "", const String &p_self_path = "");
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 7ae7c72ed3..537a0c5eaf 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -526,8 +526,13 @@ void GDScriptTokenizerText::_advance() {
return;
}
case '#': { // line comment skip
-
+#ifdef DEBUG_ENABLED
+ String comment;
+#endif // DEBUG_ENABLED
while (GETCHAR(0) != '\n') {
+#ifdef DEBUG_ENABLED
+ comment += GETCHAR(0);
+#endif // DEBUG_ENABLED
code_pos++;
if (GETCHAR(0) == 0) { //end of file
//_make_error("Unterminated Comment");
@@ -535,6 +540,17 @@ void GDScriptTokenizerText::_advance() {
return;
}
}
+#ifdef DEBUG_ENABLED
+ if (comment.begins_with("#warning-ignore:")) {
+ String code = comment.get_slice(":", 1);
+ warning_skips.push_back(Pair<int, String>(line, code.strip_edges().to_lower()));
+ } else if (comment.begins_with("#warning-ignore-all:")) {
+ String code = comment.get_slice(":", 1);
+ warning_global_skips.insert(code.strip_edges().to_lower());
+ } else if (comment.strip_edges() == "#warnings-disable") {
+ ignore_warnings = true;
+ }
+#endif // DEBUG_ENABLED
INCPOS(1);
column = 1;
line++;
@@ -1045,6 +1061,9 @@ void GDScriptTokenizerText::set_code(const String &p_code) {
column = 1; //the same holds for columns
tk_rb_pos = 0;
error_flag = false;
+#ifdef DEBUG_ENABLED
+ ignore_warnings = false;
+#endif // DEBUG_ENABLED
last_error = "";
for (int i = 0; i < MAX_LOOKAHEAD + 1; i++)
_advance();
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 5bd303224c..28a08bfaf8 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -31,6 +31,7 @@
#ifndef GDSCRIPT_TOKENIZER_H
#define GDSCRIPT_TOKENIZER_H
+#include "core/pair.h"
#include "gdscript_functions.h"
#include "string_db.h"
#include "ustring.h"
@@ -171,6 +172,11 @@ public:
virtual int get_token_line_indent(int p_offset = 0) const = 0;
virtual String get_token_error(int p_offset = 0) const = 0;
virtual void advance(int p_amount = 1) = 0;
+#ifdef DEBUG_ENABLED
+ virtual const Vector<Pair<int, String> > &get_warning_skips() const = 0;
+ virtual const Set<String> &get_warning_global_skips() const = 0;
+ virtual const bool is_ignoring_warnings() const = 0;
+#endif // DEBUG_ENABLED
virtual ~GDScriptTokenizer(){};
};
@@ -190,6 +196,7 @@ class GDScriptTokenizerText : public GDScriptTokenizer {
union {
Variant::Type vtype; //for type types
GDScriptFunctions::Function func; //function for built in functions
+ int warning_code; //for warning skip
};
int line, col;
TokenData() {
@@ -217,6 +224,11 @@ class GDScriptTokenizerText : public GDScriptTokenizer {
int tk_rb_pos;
String last_error;
bool error_flag;
+#ifdef DEBUG_ENABLED
+ Vector<Pair<int, String> > warning_skips;
+ Set<String> warning_global_skips;
+ bool ignore_warnings;
+#endif // DEBUG_ENABLED
void _advance();
@@ -232,6 +244,11 @@ public:
virtual const Variant &get_token_constant(int p_offset = 0) const;
virtual String get_token_error(int p_offset = 0) const;
virtual void advance(int p_amount = 1);
+#ifdef DEBUG_ENABLED
+ virtual const Vector<Pair<int, String> > &get_warning_skips() const { return warning_skips; }
+ virtual const Set<String> &get_warning_global_skips() const { return warning_global_skips; }
+ virtual const bool is_ignoring_warnings() const { return ignore_warnings; }
+#endif // DEBUG_ENABLED
};
class GDScriptTokenizerBuffer : public GDScriptTokenizer {
@@ -265,6 +282,11 @@ public:
virtual const Variant &get_token_constant(int p_offset = 0) const;
virtual String get_token_error(int p_offset = 0) const;
virtual void advance(int p_amount = 1);
+#ifdef DEBUG_ENABLED
+ virtual const Vector<Pair<int, String> > &get_warning_skips() const { return Vector<Pair<int, String> >(); }
+ virtual const Set<String> &get_warning_global_skips() const { return Set<String>(); }
+ virtual const bool is_ignoring_warnings() const { return true; }
+#endif // DEBUG_ENABLED
GDScriptTokenizerBuffer();
};
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 7f9732c297..363ae59d22 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -292,7 +292,7 @@ public:
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);
- /* TODO */ virtual bool 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, Set<int> *r_safe_lines = NULL) const { return true; }
+ /* TODO */ virtual bool 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 = NULL, Set<int> *r_safe_lines = NULL) const { return true; }
virtual String validate_path(const String &p_path) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp
index 0cf24dd8d8..f6be537413 100644
--- a/modules/squish/image_compress_squish.cpp
+++ b/modules/squish/image_compress_squish.cpp
@@ -46,7 +46,7 @@ void image_decompress_squish(Image *p_image) {
Image::Format target_format = Image::FORMAT_RGBA8;
PoolVector<uint8_t> data;
- int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps() ? -1 : 0);
+ int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
int mm_count = p_image->get_mipmap_count();
data.resize(target_size);
@@ -96,6 +96,33 @@ void image_compress_squish(Image *p_image, Image::CompressSource p_source) {
Image::DetectChannels dc = p_image->get_detected_channels();
+ if (p_source == Image::COMPRESS_SOURCE_LAYERED) {
+ //keep what comes in
+ switch (p_image->get_format()) {
+ case Image::FORMAT_L8: {
+ dc = Image::DETECTED_L;
+ } break;
+ case Image::FORMAT_LA8: {
+ dc = Image::DETECTED_LA;
+ } break;
+ case Image::FORMAT_R8: {
+ dc = Image::DETECTED_R;
+ } break;
+ case Image::FORMAT_RG8: {
+ dc = Image::DETECTED_RG;
+ } break;
+ case Image::FORMAT_RGB8: {
+ dc = Image::DETECTED_RGB;
+ } break;
+ case Image::FORMAT_RGBA8:
+ case Image::FORMAT_RGBA4444:
+ case Image::FORMAT_RGBA5551: {
+ dc = Image::DETECTED_RGBA;
+ } break;
+ default: {}
+ }
+ }
+
p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
if (p_source == Image::COMPRESS_SOURCE_SRGB && (dc == Image::DETECTED_R || dc == Image::DETECTED_RG)) {
@@ -148,7 +175,7 @@ void image_compress_squish(Image *p_image, Image::CompressSource p_source) {
}
PoolVector<uint8_t> data;
- int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps() ? -1 : 0);
+ int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0;
data.resize(target_size);
int shift = Image::get_format_pixel_rshift(target_format);
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index de9b3d5a91..bbdec7195f 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -2415,7 +2415,7 @@ void VisualScriptLanguage::make_template(const String &p_class_name, const Strin
script->set_instance_base_type(p_base_class_name);
}
-bool VisualScriptLanguage::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, Set<int> *r_safe_lines) const {
+bool VisualScriptLanguage::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 {
return false;
}
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index 2ad72a40c0..13a8b909b0 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -564,7 +564,7 @@ public:
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);
- virtual bool 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 = NULL, Set<int> *r_safe_lines = NULL) const;
+ virtual bool 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 = NULL, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index a6ec36d364..d499512d93 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -1663,7 +1663,7 @@ Variant::Type VisualScriptBasicTypeConstant::get_basic_type() const {
class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstance {
public:
- int value;
+ Variant value;
bool valid;
//virtual int get_working_memory_size() const { return 0; }
@@ -1682,7 +1682,7 @@ public:
VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instance(VisualScriptInstance *p_instance) {
VisualScriptNodeInstanceBasicTypeConstant *instance = memnew(VisualScriptNodeInstanceBasicTypeConstant);
- instance->value = Variant::get_numeric_constant_value(type, name, &instance->valid);
+ instance->value = Variant::get_constant_value(type, name, &instance->valid);
return instance;
}
@@ -1691,7 +1691,7 @@ void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &property) c
if (property.name == "constant") {
List<StringName> constants;
- Variant::get_numeric_constants_for_type(type, &constants);
+ Variant::get_constants_for_type(type, &constants);
if (constants.size() == 0) {
property.usage = 0;
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index b3ff21457d..8758ffef9f 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -197,9 +197,9 @@ void StaticBody2D::set_friction(real_t p_friction) {
if (physics_material_override.is_null()) {
physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
}
physics_material_override->set_friction(p_friction);
- _reload_physics_characteristics();
}
real_t StaticBody2D::get_friction() const {
@@ -223,9 +223,9 @@ void StaticBody2D::set_bounce(real_t p_bounce) {
if (physics_material_override.is_null()) {
physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
}
physics_material_override->set_bounce(p_bounce);
- _reload_physics_characteristics();
}
real_t StaticBody2D::get_bounce() const {
@@ -243,7 +243,8 @@ real_t StaticBody2D::get_bounce() const {
void StaticBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"))
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
}
physics_material_override = p_physics_material_override;
@@ -300,13 +301,9 @@ void StaticBody2D::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0);
Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1);
- Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, Physics2DServer::COMBINE_MODE_INHERIT);
- Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, Physics2DServer::COMBINE_MODE_INHERIT);
} else {
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce());
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->get_friction());
- Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, (Physics2DServer::CombineMode)physics_material_override->get_bounce_combine_mode());
- Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, (Physics2DServer::CombineMode)physics_material_override->get_friction_combine_mode());
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
}
}
@@ -625,9 +622,9 @@ void RigidBody2D::set_friction(real_t p_friction) {
if (physics_material_override.is_null()) {
physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
}
physics_material_override->set_friction(p_friction);
- _reload_physics_characteristics();
}
real_t RigidBody2D::get_friction() const {
@@ -650,9 +647,9 @@ void RigidBody2D::set_bounce(real_t p_bounce) {
if (physics_material_override.is_null()) {
physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
}
physics_material_override->set_bounce(p_bounce);
- _reload_physics_characteristics();
}
real_t RigidBody2D::get_bounce() const {
@@ -669,7 +666,8 @@ real_t RigidBody2D::get_bounce() const {
void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"))
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
}
physics_material_override = p_physics_material_override;
@@ -1116,13 +1114,9 @@ void RigidBody2D::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0);
Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1);
- Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, Physics2DServer::COMBINE_MODE_INHERIT);
- Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, Physics2DServer::COMBINE_MODE_INHERIT);
} else {
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce());
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->get_friction());
- Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, (Physics2DServer::CombineMode)physics_material_override->get_bounce_combine_mode());
- Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, (Physics2DServer::CombineMode)physics_material_override->get_friction_combine_mode());
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
}
}
@@ -1210,6 +1204,9 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_
return colliding;
}
+//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45.
+#define FLOOR_ANGLE_THRESHOLD 0.01
+
Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_infinite_inertia, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) {
Vector2 floor_motion = floor_velocity;
@@ -1263,7 +1260,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
//all is a wall
on_wall = true;
} else {
- if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor
+ if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor
on_floor = true;
on_floor_body = collision.collider_rid;
@@ -1278,7 +1275,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
set_global_transform(gt);
return Vector2();
}
- } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling
+ } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling
on_ceiling = true;
} else {
on_wall = true;
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 78637cc097..ee7058d4a6 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -368,7 +368,7 @@ void TileMap::update_dirty_quadrants() {
}
Rect2 r = tile_set->tile_get_region(c.id);
- if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) {
+ if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) {
int spacing = tile_set->autotile_get_spacing(c.id);
r.size = tile_set->autotile_get_size(c.id);
r.position += (r.size + Vector2(spacing, spacing)) * Vector2(c.autotile_coord_x, c.autotile_coord_y);
@@ -491,7 +491,7 @@ void TileMap::update_dirty_quadrants() {
if (navigation) {
Ref<NavigationPolygon> navpoly;
Vector2 npoly_ofs;
- if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) {
+ if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) {
navpoly = tile_set->autotile_get_navigation_polygon(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y));
npoly_ofs = Vector2();
} else {
@@ -563,7 +563,7 @@ void TileMap::update_dirty_quadrants() {
}
Ref<OccluderPolygon2D> occluder;
- if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) {
+ if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) {
occluder = tile_set->autotile_get_light_occluder(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y));
} else {
occluder = tile_set->tile_get_light_occluder(c.id);
@@ -840,7 +840,7 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) {
Map<PosKey, Cell>::Element *E = tile_map.find(p);
if (E != NULL) {
int id = get_cell(p_x, p_y);
- if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE) {
+ if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) {
uint16_t mask = 0;
if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_2X2) {
if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index 0fe427d5fc..2176b45faf 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -74,10 +74,7 @@ void Camera::_update_camera() {
if (!is_inside_tree())
return;
- Transform tr = get_camera_transform();
- tr.origin += tr.basis.get_axis(1) * v_offset;
- tr.origin += tr.basis.get_axis(0) * h_offset;
- VisualServer::get_singleton()->camera_set_transform(camera, tr);
+ VisualServer::get_singleton()->camera_set_transform(camera, get_camera_transform());
// here goes listener stuff
/*
@@ -143,7 +140,10 @@ void Camera::_notification(int p_what) {
Transform Camera::get_camera_transform() const {
- return get_global_transform().orthonormalized();
+ Transform tr = get_global_transform().orthonormalized();
+ tr.origin += tr.basis.get_axis(1) * v_offset;
+ tr.origin += tr.basis.get_axis(0) * h_offset;
+ return tr;
}
void Camera::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 4b3a4add4a..84a0fb9b1d 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -189,9 +189,10 @@ void StaticBody::set_friction(real_t p_friction) {
if (physics_material_override.is_null()) {
physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
}
+
physics_material_override->set_friction(p_friction);
- _reload_physics_characteristics();
}
real_t StaticBody::get_friction() const {
@@ -215,9 +216,9 @@ void StaticBody::set_bounce(real_t p_bounce) {
if (physics_material_override.is_null()) {
physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
}
physics_material_override->set_bounce(p_bounce);
- _reload_physics_characteristics();
}
real_t StaticBody::get_bounce() const {
@@ -235,7 +236,8 @@ real_t StaticBody::get_bounce() const {
void StaticBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"))
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
}
physics_material_override = p_physics_material_override;
@@ -313,13 +315,9 @@ void StaticBody::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0);
PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1);
- PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, PhysicsServer::COMBINE_MODE_INHERIT);
- PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, PhysicsServer::COMBINE_MODE_INHERIT);
} else {
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce());
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction());
- PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce_combine_mode());
- PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction_combine_mode());
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
}
}
@@ -626,9 +624,9 @@ void RigidBody::set_friction(real_t p_friction) {
if (physics_material_override.is_null()) {
physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
}
physics_material_override->set_friction(p_friction);
- _reload_physics_characteristics();
}
real_t RigidBody::get_friction() const {
@@ -648,9 +646,9 @@ void RigidBody::set_bounce(real_t p_bounce) {
if (physics_material_override.is_null()) {
physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
}
physics_material_override->set_bounce(p_bounce);
- _reload_physics_characteristics();
}
real_t RigidBody::get_bounce() const {
ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material")
@@ -665,7 +663,8 @@ real_t RigidBody::get_bounce() const {
void RigidBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"))
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
}
physics_material_override = p_physics_material_override;
@@ -1070,13 +1069,9 @@ void RigidBody::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0);
PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1);
- PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, PhysicsServer::COMBINE_MODE_INHERIT);
- PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, PhysicsServer::COMBINE_MODE_INHERIT);
} else {
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce());
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction());
- PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce_combine_mode());
- PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction_combine_mode());
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
}
}
@@ -1130,6 +1125,9 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
return colliding;
}
+//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45.
+#define FLOOR_ANGLE_THRESHOLD 0.01
+
Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
Vector3 lv = p_linear_velocity;
@@ -1162,7 +1160,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
//all is a wall
on_wall = true;
} else {
- if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor
+ if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor
on_floor = true;
floor_velocity = collision.collider_vel;
@@ -1176,7 +1174,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
set_global_transform(gt);
return floor_velocity - p_floor_direction * p_floor_direction.dot(floor_velocity);
}
- } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling
+ } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling
on_ceiling = true;
} else {
on_wall = true;
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index f45cb02211..c796e47f25 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -131,7 +131,7 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
String prep = "bones/" + itos(i) + "/";
p_list->push_back(PropertyInfo(Variant::STRING, prep + "name"));
- p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(i - 1) + ",1"));
+ p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest"));
p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
@@ -139,6 +139,59 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
+void Skeleton::_update_process_order() {
+
+ if (!process_order_dirty)
+ return;
+
+ Bone *bonesptr = bones.ptrw();
+ int len = bones.size();
+
+ process_order.resize(len);
+ int *order = process_order.ptrw();
+ for (int i = 0; i < len; i++) {
+
+ if (bonesptr[i].parent >= len) {
+ //validate this just in case
+ ERR_PRINTS("Bone " + itos(i) + " has invalid parent: " + itos(bonesptr[i].parent));
+ bonesptr[i].parent = -1;
+ }
+ order[i] = i;
+ bonesptr[i].sort_index = i;
+ }
+ //now check process order
+ int pass_count = 0;
+ while (pass_count < len * len) {
+ //using bubblesort because of simplicity, it wont run every frame though.
+ //bublesort worst case is O(n^2), and this may be an infinite loop if cyclic
+ bool swapped = false;
+ for (int i = 0; i < len; i++) {
+ int parent_idx = bonesptr[order[i]].parent;
+ if (parent_idx < 0)
+ continue; //do nothing because it has no parent
+ //swap indices
+ int parent_order = bonesptr[parent_idx].sort_index;
+ if (parent_order > i) {
+ bonesptr[order[i]].sort_index = parent_order;
+ bonesptr[parent_idx].sort_index = i;
+ //swap order
+ SWAP(order[i], order[parent_order]);
+ swapped = true;
+ }
+ }
+
+ if (!swapped)
+ break;
+ pass_count++;
+ }
+
+ if (pass_count == len * len) {
+ ERR_PRINT("Skeleton parenthood graph is cyclic");
+ }
+
+ process_order_dirty = false;
+}
+
void Skeleton::_notification(int p_what) {
switch (p_what) {
@@ -181,19 +234,23 @@ void Skeleton::_notification(int p_what) {
vs->skeleton_allocate(skeleton, len); // if same size, nothin really happens
+ _update_process_order();
+
+ const int *order = process_order.ptr();
+
// pose changed, rebuild cache of inverses
if (rest_global_inverse_dirty) {
// calculate global rests and invert them
for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[i];
+ Bone &b = bonesptr[order[i]];
if (b.parent >= 0)
b.rest_global_inverse = bonesptr[b.parent].rest_global_inverse * b.rest;
else
b.rest_global_inverse = b.rest;
}
for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[i];
+ Bone &b = bonesptr[order[i]];
b.rest_global_inverse.affine_invert();
}
@@ -205,7 +262,7 @@ void Skeleton::_notification(int p_what) {
for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[i];
+ Bone &b = bonesptr[order[i]];
if (b.disable_rest) {
if (b.enabled) {
@@ -319,12 +376,13 @@ void Skeleton::add_bone(const String &p_name) {
for (int i = 0; i < bones.size(); i++) {
- ERR_FAIL_COND(bones[i].name == "p_name");
+ ERR_FAIL_COND(bones[i].name == p_name);
}
Bone b;
b.name = p_name;
bones.push_back(b);
+ process_order_dirty = true;
rest_global_inverse_dirty = true;
_make_dirty();
@@ -368,10 +426,11 @@ int Skeleton::get_bone_count() const {
void Skeleton::set_bone_parent(int p_bone, int p_parent) {
ERR_FAIL_INDEX(p_bone, bones.size());
- ERR_FAIL_COND(p_parent != -1 && (p_parent < 0 || p_parent >= p_bone));
+ ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));
bones.write[p_bone].parent = p_parent;
rest_global_inverse_dirty = true;
+ process_order_dirty = true;
_make_dirty();
}
@@ -379,6 +438,8 @@ void Skeleton::unparent_bone_and_rest(int p_bone) {
ERR_FAIL_INDEX(p_bone, bones.size());
+ _update_process_order();
+
int parent = bones[p_bone].parent;
while (parent >= 0) {
bones.write[p_bone].rest = bones[parent].rest * bones[p_bone].rest;
@@ -387,6 +448,7 @@ void Skeleton::unparent_bone_and_rest(int p_bone) {
bones.write[p_bone].parent = -1;
bones.write[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing
+ process_order_dirty = true;
_make_dirty();
}
@@ -489,6 +551,8 @@ void Skeleton::clear_bones() {
bones.clear();
rest_global_inverse_dirty = true;
+ process_order_dirty = true;
+
_make_dirty();
}
@@ -538,12 +602,21 @@ void Skeleton::_make_dirty() {
dirty = true;
}
+int Skeleton::get_process_order(int p_idx) {
+ ERR_FAIL_INDEX_V(p_idx, bones.size(), -1);
+ _update_process_order();
+ return process_order[p_idx];
+}
+
void Skeleton::localize_rests() {
- for (int i = bones.size() - 1; i >= 0; i--) {
+ _update_process_order();
- if (bones[i].parent >= 0)
- set_bone_rest(i, bones[bones[i].parent].rest.affine_inverse() * bones[i].rest);
+ for (int i = bones.size() - 1; i >= 0; i--) {
+ int idx = process_order[i];
+ if (bones[idx].parent >= 0) {
+ set_bone_rest(idx, bones[bones[idx].parent].rest.affine_inverse() * bones[idx].rest);
+ }
}
}
@@ -752,6 +825,7 @@ Skeleton::Skeleton() {
rest_global_inverse_dirty = true;
dirty = false;
+ process_order_dirty = true;
skeleton = VisualServer::get_singleton()->skeleton_create();
set_notify_transform(true);
}
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index a8413ebaf2..e044e08437 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -54,6 +54,7 @@ class Skeleton : public Spatial {
bool enabled;
int parent;
+ int sort_index; //used for re-sorting process order
bool ignore_animation;
@@ -92,6 +93,8 @@ class Skeleton : public Spatial {
bool rest_global_inverse_dirty;
Vector<Bone> bones;
+ Vector<int> process_order;
+ bool process_order_dirty;
RID skeleton;
@@ -112,6 +115,8 @@ class Skeleton : public Spatial {
return bound;
}
+ void _update_process_order();
+
protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
@@ -172,6 +177,7 @@ public:
Transform get_bone_custom_pose(int p_bone) const;
void localize_rests(); // used for loaders and tools
+ int get_process_order(int p_idx);
#ifndef _3D_DISABLED
// Physical bone API
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index 64cb9ec4ca..3f494264e7 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -202,6 +202,7 @@ void Spatial::_notification(int p_what) {
#ifdef TOOLS_ENABLED
if (data.gizmo.is_valid()) {
data.gizmo->free();
+ data.gizmo.unref();
}
#endif
@@ -793,13 +794,13 @@ void Spatial::_bind_methods() {
//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ;
ADD_GROUP("Transform", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
-
+ ADD_GROUP("Matrix", "");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
ADD_GROUP("Visibility", "");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo");
diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h
index 653714dc98..bc054a8763 100644
--- a/scene/3d/spatial.h
+++ b/scene/3d/spatial.h
@@ -51,6 +51,7 @@ public:
virtual bool can_draw() const = 0;
SpatialGizmo();
+ virtual ~SpatialGizmo() {}
};
class Spatial : public Node {
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 4d73ee2d56..6258f32bf3 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -642,7 +642,7 @@ void LineEdit::_notification(int p_what) {
int char_ofs = window_pos;
int y_area = height - style->get_minimum_size().height;
- int y_ofs = style->get_offset().y;
+ int y_ofs = style->get_offset().y + (y_area - font->get_height()) / 2;
int font_ascent = font->get_ascent();
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index c9dcf058aa..d3de68ee24 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -6410,7 +6410,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int
}
// check for dot or underscore or 'x' for hex notation in floating point number
- if ((str[j] == '.' || str[j] == 'x' || str[j] == '_') && !in_word && prev_is_number && !is_number) {
+ if ((str[j] == '.' || str[j] == 'x' || str[j] == '_' || str[j] == 'f') && !in_word && prev_is_number && !is_number) {
is_number = true;
is_symbol = false;
is_char = false;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index ffac166453..382bddfb4e 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -217,6 +217,7 @@ static ResourceFormatLoaderText *resource_loader_text = NULL;
static ResourceFormatLoaderDynamicFont *resource_loader_dynamic_font = NULL;
static ResourceFormatLoaderStreamTexture *resource_loader_stream_texture = NULL;
+static ResourceFormatLoaderTextureLayered *resource_loader_texture_layered = NULL;
static ResourceFormatLoaderBMFont *resource_loader_bmfont = NULL;
@@ -237,6 +238,9 @@ void register_scene_types() {
resource_loader_stream_texture = memnew(ResourceFormatLoaderStreamTexture);
ResourceLoader::add_resource_format_loader(resource_loader_stream_texture);
+ resource_loader_texture_layered = memnew(ResourceFormatLoaderTextureLayered);
+ ResourceLoader::add_resource_format_loader(resource_loader_texture_layered);
+
resource_loader_theme = memnew(ResourceFormatLoaderTheme);
ResourceLoader::add_resource_format_loader(resource_loader_theme);
@@ -615,6 +619,9 @@ void register_scene_types() {
ClassDB::register_class<ProxyTexture>();
ClassDB::register_class<AnimatedTexture>();
ClassDB::register_class<CubeMap>();
+ ClassDB::register_virtual_class<TextureLayered>();
+ ClassDB::register_class<Texture3D>();
+ ClassDB::register_class<TextureArray>();
ClassDB::register_class<Animation>();
ClassDB::register_virtual_class<Font>();
ClassDB::register_class<BitmapFont>();
@@ -728,6 +735,7 @@ void unregister_scene_types() {
memdelete(resource_loader_dynamic_font);
memdelete(resource_loader_stream_texture);
+ memdelete(resource_loader_texture_layered);
memdelete(resource_loader_theme);
DynamicFont::finish_dynamic_fonts();
diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp
index 85e36abf4e..ec1aa7ec46 100644
--- a/scene/resources/bit_mask.cpp
+++ b/scene/resources/bit_mask.cpp
@@ -418,31 +418,91 @@ static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect,
return result;
}
+struct FillBitsStackEntry {
+ Point2i pos;
+ int i;
+ int j;
+};
+
static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_pos, const Rect2i &rect) {
- for (int i = p_pos.x - 1; i <= p_pos.x + 1; i++) {
- for (int j = p_pos.y - 1; j <= p_pos.y + 1; j++) {
+ // Using a custom stack to work iteratively to avoid stack overflow on big bitmaps
+ PoolVector<FillBitsStackEntry> stack;
+ // Tracking size since we won't be shrinking the stack vector
+ int stack_size = 0;
- if (i < rect.position.x || i >= rect.position.x + rect.size.x)
- continue;
- if (j < rect.position.y || j >= rect.position.y + rect.size.y)
- continue;
+ Point2i pos = p_pos;
+ int next_i;
+ int next_j;
- if (p_map->get_bit(Vector2(i, j)))
- continue;
+ bool reenter = true;
+ bool popped = false;
+ do {
+ if (reenter) {
+ next_i = pos.x - 1;
+ next_j = pos.y - 1;
+ reenter = false;
+ }
+
+ for (int i = next_i; i <= pos.x + 1; i++) {
+ for (int j = next_j; j <= pos.y + 1; j++) {
+ if (popped) {
+ // The next loop over j must start normally
+ next_j = pos.y;
+ popped = false;
+ // Skip because an iteration was already executed with current counter values
+ continue;
+ }
- else if (p_src->get_bit(Vector2(i, j))) {
- p_map->set_bit(Vector2(i, j), true);
- fill_bits(p_src, p_map, Point2i(i, j), rect);
+ if (i < rect.position.x || i >= rect.position.x + rect.size.x)
+ continue;
+ if (j < rect.position.y || j >= rect.position.y + rect.size.y)
+ continue;
+
+ if (p_map->get_bit(Vector2(i, j)))
+ continue;
+
+ else if (p_src->get_bit(Vector2(i, j))) {
+ p_map->set_bit(Vector2(i, j), true);
+
+ FillBitsStackEntry se = { pos, i, j };
+ stack.resize(MAX(stack_size + 1, stack.size()));
+ stack.set(stack_size, se);
+ stack_size++;
+
+ pos = Point2i(i, j);
+ reenter = true;
+ break;
+ }
+ }
+ if (reenter) {
+ break;
}
}
- }
+ if (!reenter) {
+ if (stack_size) {
+ FillBitsStackEntry se = stack.get(stack_size - 1);
+ stack_size--;
+ pos = se.pos;
+ next_i = se.i;
+ next_j = se.j;
+ popped = true;
+ }
+ }
+ } while (reenter || popped);
+
+#ifdef DEBUG_ENABLED
+ print_line("max stack size: " + itos(stack.size()));
+#endif
}
+
Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const {
Rect2i r = Rect2i(0, 0, width, height).clip(p_rect);
+#ifdef DEBUG_ENABLED
print_line("Rect: " + r);
+#endif
Point2i from;
Ref<BitMap> fill;
fill.instance();
@@ -454,9 +514,13 @@ Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, fl
if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) {
Vector<Vector2> polygon = _march_square(r, Point2i(j, i));
+#ifdef DEBUG_ENABLED
print_line("pre reduce: " + itos(polygon.size()));
+#endif
polygon = reduce(polygon, r, p_epsilon);
+#ifdef DEBUG_ENABLED
print_line("post reduce: " + itos(polygon.size()));
+#endif
polygons.push_back(polygon);
fill_bits(this, fill, Point2i(j, i), r);
}
@@ -510,6 +574,34 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
}
}
+Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const {
+
+ Vector<Vector<Vector2> > result = clip_opaque_to_polygons(p_rect, p_epsilon);
+
+ // Convert result to bindable types
+
+ Array result_array;
+ result_array.resize(result.size());
+ for (int i = 0; i < result.size(); i++) {
+
+ const Vector<Vector2> &polygon = result[i];
+
+ PoolVector2Array polygon_array;
+ polygon_array.resize(polygon.size());
+
+ {
+ PoolVector2Array::Write w = polygon_array.write();
+ for (int j = 0; j < polygon.size(); j++) {
+ w[j] = polygon[j];
+ }
+ }
+
+ result_array[i] = polygon_array;
+ }
+
+ return result_array;
+}
+
void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create);
@@ -526,6 +618,9 @@ void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_data"), &BitMap::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &BitMap::_get_data);
+ ClassDB::bind_method(D_METHOD("grow_mask", "pixels", "rect"), &BitMap::grow_mask);
+ ClassDB::bind_method(D_METHOD("opaque_to_polygons", "rect", "epsilon"), &BitMap::_opaque_to_polygons_bind, DEFVAL(2.0));
+
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
}
diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h
index dcd5edb4fb..40f0bfb04a 100644
--- a/scene/resources/bit_mask.h
+++ b/scene/resources/bit_mask.h
@@ -46,6 +46,8 @@ class BitMap : public Resource {
Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const;
+ Array _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const;
+
protected:
void _set_data(const Dictionary &p_d);
Dictionary _get_data() const;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index df5bbe9e6c..875b72159a 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -2106,10 +2106,10 @@ void SpatialMaterial::_bind_methods() {
SpatialMaterial::SpatialMaterial() :
element(this) {
- //initialize to right values
+ // Initialize to the same values as the shader
set_albedo(Color(1.0, 1.0, 1.0, 1.0));
set_specular(0.5);
- set_roughness(0.0);
+ set_roughness(1.0);
set_metallic(0.0);
set_emission(Color(0, 0, 0));
set_emission_energy(1.0);
diff --git a/scene/resources/physics_material.cpp b/scene/resources/physics_material.cpp
index de3cfd1371..dc5ca1aef6 100644
--- a/scene/resources/physics_material.cpp
+++ b/scene/resources/physics_material.cpp
@@ -29,66 +29,48 @@
/*************************************************************************/
#include "physics_material.h"
-bool PhysicsMaterial::_set(const StringName &p_name, const Variant &p_value) {
- if (p_name == "bounce") {
- set_bounce(p_value);
- } else if (p_name == "bounce_combine_mode") {
- set_bounce_combine_mode(static_cast<PhysicsServer::CombineMode>(int(p_value)));
- } else if (p_name == "friction") {
- set_friction(p_value);
- } else if (p_name == "friction_combine_mode") {
- set_friction_combine_mode(static_cast<PhysicsServer::CombineMode>(int(p_value)));
- } else {
- return false;
- }
+void PhysicsMaterial::_bind_methods() {
- emit_changed();
- return true;
-}
+ ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicsMaterial::set_friction);
+ ClassDB::bind_method(D_METHOD("get_friction"), &PhysicsMaterial::get_friction);
-bool PhysicsMaterial::_get(const StringName &p_name, Variant &r_ret) const {
- if (p_name == "bounce") {
- r_ret = bounce;
- } else if (p_name == "bounce_combine_mode") {
- r_ret = int(bounce_combine_mode);
- } else if (p_name == "friction") {
- r_ret = friction;
- } else if (p_name == "friction_combine_mode") {
- r_ret = int(friction_combine_mode);
- } else {
- return false;
- }
+ ClassDB::bind_method(D_METHOD("set_rough", "rough"), &PhysicsMaterial::set_rough);
+ ClassDB::bind_method(D_METHOD("is_rough"), &PhysicsMaterial::is_rough);
- return true;
-}
+ ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &PhysicsMaterial::set_bounce);
+ ClassDB::bind_method(D_METHOD("get_bounce"), &PhysicsMaterial::get_bounce);
-void PhysicsMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::REAL, "bounce"));
- p_list->push_back(PropertyInfo(Variant::INT, "bounce_combine_mode", PROPERTY_HINT_ENUM, "Max,Min,Multiply,Average"));
- p_list->push_back(PropertyInfo(Variant::REAL, "friction"));
- p_list->push_back(PropertyInfo(Variant::INT, "friction_combine_mode", PROPERTY_HINT_ENUM, "Max,Min,Multiply,Average"));
-}
+ ClassDB::bind_method(D_METHOD("set_absorbent", "absorbent"), &PhysicsMaterial::set_absorbent);
+ ClassDB::bind_method(D_METHOD("is_absorbent"), &PhysicsMaterial::is_absorbent);
-void PhysicsMaterial::_bind_methods() {}
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction"), "set_friction", "get_friction");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rough"), "set_rough", "is_rough");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce"), "set_bounce", "get_bounce");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "absorbent"), "set_absorbent", "is_absorbent");
+}
-void PhysicsMaterial::set_bounce(real_t p_val) {
- bounce = p_val;
+void PhysicsMaterial::set_friction(real_t p_val) {
+ friction = p_val;
+ emit_changed();
}
-void PhysicsMaterial::set_bounce_combine_mode(PhysicsServer::CombineMode p_val) {
- bounce_combine_mode = p_val;
+void PhysicsMaterial::set_rough(bool p_val) {
+ rough = p_val;
+ emit_changed();
}
-void PhysicsMaterial::set_friction(real_t p_val) {
- friction = p_val;
+void PhysicsMaterial::set_bounce(real_t p_val) {
+ bounce = p_val;
+ emit_changed();
}
-void PhysicsMaterial::set_friction_combine_mode(PhysicsServer::CombineMode p_val) {
- friction_combine_mode = p_val;
+void PhysicsMaterial::set_absorbent(bool p_val) {
+ absorbent = p_val;
+ emit_changed();
}
PhysicsMaterial::PhysicsMaterial() :
+ friction(1),
+ rough(false),
bounce(0),
- bounce_combine_mode(PhysicsServer::COMBINE_MODE_MAX),
- friction(0),
- friction_combine_mode(PhysicsServer::COMBINE_MODE_MULTIPLY) {}
+ absorbent(false) {}
diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h
index a6cb8c288e..dfe48d94cf 100644
--- a/scene/resources/physics_material.h
+++ b/scene/resources/physics_material.h
@@ -39,30 +39,34 @@ class PhysicsMaterial : public Resource {
OBJ_SAVE_TYPE(PhysicsMaterial);
RES_BASE_EXTENSION("PhyMat");
- real_t bounce;
- PhysicsServer::CombineMode bounce_combine_mode;
real_t friction;
- PhysicsServer::CombineMode friction_combine_mode;
+ bool rough;
+ real_t bounce;
+ bool absorbent;
protected:
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
static void _bind_methods();
public:
+ void set_friction(real_t p_val);
+ _FORCE_INLINE_ real_t get_friction() const { return friction; }
+
+ void set_rough(bool p_val);
+ _FORCE_INLINE_ bool is_rough() const { return rough; }
+
+ _FORCE_INLINE_ real_t computed_friction() const {
+ return rough ? -friction : friction;
+ }
+
void set_bounce(real_t p_val);
_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
- void set_bounce_combine_mode(PhysicsServer::CombineMode p_val);
- _FORCE_INLINE_ PhysicsServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; }
-
- void set_friction(real_t p_val);
- _FORCE_INLINE_ real_t get_friction() const { return friction; }
+ void set_absorbent(bool p_val);
+ _FORCE_INLINE_ bool is_absorbent() const { return absorbent; }
- void set_friction_combine_mode(PhysicsServer::CombineMode p_val);
- _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; }
+ _FORCE_INLINE_ real_t computed_bounce() const {
+ return absorbent ? -bounce : bounce;
+ }
PhysicsMaterial();
};
diff --git a/scene/resources/sky_box.cpp b/scene/resources/sky_box.cpp
index f2d5cb3516..4176aed4d8 100644
--- a/scene/resources/sky_box.cpp
+++ b/scene/resources/sky_box.cpp
@@ -405,7 +405,7 @@ void ProceduralSky::_update_sky() {
} else {
Ref<Image> image = _generate_sky();
- VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), Image::FORMAT_RGBE9995, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT);
+ VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, Image::FORMAT_RGBE9995, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT);
VS::get_singleton()->texture_set_data(texture, image);
_radiance_changed();
}
@@ -422,7 +422,7 @@ void ProceduralSky::_queue_update() {
void ProceduralSky::_thread_done(const Ref<Image> &p_image) {
- VS::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), Image::FORMAT_RGBE9995, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT);
+ VS::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, Image::FORMAT_RGBE9995, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT);
VS::get_singleton()->texture_set_data(texture, p_image);
_radiance_changed();
Thread::wait_to_finish(sky_thread);
@@ -532,14 +532,14 @@ ProceduralSky::ProceduralSky() {
texture = VS::get_singleton()->texture_create();
update_queued = false;
- sky_top_color = Color::hex(0x0c74f9ff);
- sky_horizon_color = Color::hex(0x8ed2e8ff);
- sky_curve = 0.25;
+ sky_top_color = Color::hex(0xa5d6f1ff);
+ sky_horizon_color = Color::hex(0xd6eafaff);
+ sky_curve = 0.09;
sky_energy = 1;
- ground_bottom_color = Color::hex(0x1a2530ff);
- ground_horizon_color = Color::hex(0x7bc9f3ff);
- ground_curve = 0.01;
+ ground_bottom_color = Color::hex(0x282f36ff);
+ ground_horizon_color = Color::hex(0x6c655fff);
+ ground_curve = 0.02;
ground_energy = 1;
sun_color = Color(1, 1, 1);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index c8d12b88fc..536c653a0c 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -124,7 +124,7 @@ bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
Size2 s = p_value;
w = s.width;
h = s.height;
- VisualServer::get_singleton()->texture_set_size_override(texture, w, h);
+ VisualServer::get_singleton()->texture_set_size_override(texture, w, h, 0);
} else if (p_name == "_data") {
_set_data(p_value);
} else
@@ -151,13 +151,6 @@ bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
- PropertyHint img_hint = PROPERTY_HINT_NONE;
- if (storage == STORAGE_COMPRESS_LOSSY) {
- img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY;
- } else if (storage == STORAGE_COMPRESS_LOSSLESS) {
- img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS;
- }
-
p_list->push_back(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic,sRGB,Mirrored Repeat"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "image", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
p_list->push_back(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, ""));
@@ -183,7 +176,7 @@ void ImageTexture::_reload_hook(const RID &p_hook) {
void ImageTexture::create(int p_width, int p_height, Image::Format p_format, uint32_t p_flags) {
flags = p_flags;
- VisualServer::get_singleton()->texture_allocate(texture, p_width, p_height, p_format, p_flags);
+ VisualServer::get_singleton()->texture_allocate(texture, p_width, p_height, 0, p_format, VS::TEXTURE_TYPE_2D, p_flags);
format = p_format;
w = p_width;
h = p_height;
@@ -196,7 +189,7 @@ void ImageTexture::create_from_image(const Ref<Image> &p_image, uint32_t p_flags
h = p_image->get_height();
format = p_image->get_format();
- VisualServer::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), p_flags);
+ VisualServer::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_flags);
VisualServer::get_singleton()->texture_set_data(texture, p_image);
_change_notify();
}
@@ -301,7 +294,7 @@ void ImageTexture::set_size_override(const Size2 &p_size) {
w = s.x;
if (s.y != 0)
h = s.y;
- VisualServer::get_singleton()->texture_set_size_override(texture, w, h);
+ VisualServer::get_singleton()->texture_set_size_override(texture, w, h, 0);
}
void ImageTexture::set_path(const String &p_path, bool p_take_over) {
@@ -592,7 +585,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
int sh = th;
int mipmaps = Image::get_image_required_mipmaps(tw, th, format);
- int total_size = Image::get_image_data_size(tw, th, format, mipmaps);
+ int total_size = Image::get_image_data_size(tw, th, format, true);
int idx = 0;
int ofs = 0;
@@ -648,7 +641,7 @@ Error StreamTexture::load(const String &p_path) {
if (err)
return err;
- VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), image->get_format(), lflags);
+ VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, image->get_format(), VS::TEXTURE_TYPE_2D, lflags);
VS::get_singleton()->texture_set_data(texture, image);
w = lw;
@@ -1155,7 +1148,6 @@ void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile
Size2 scale = p_rect.size / size;
- RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
for (int i = 0; i < pieces.size(); i++) {
// TODO
@@ -1170,7 +1162,6 @@ void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
Size2 scale = p_rect.size / p_src_rect.size;
- RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
for (int i = 0; i < pieces.size(); i++) {
// TODO
@@ -1195,7 +1186,7 @@ void CubeMap::set_flags(uint32_t p_flags) {
flags = p_flags;
if (_is_valid())
- VS::get_singleton()->texture_set_flags(cubemap, flags | VS::TEXTURE_FLAG_CUBEMAP);
+ VS::get_singleton()->texture_set_flags(cubemap, flags);
}
uint32_t CubeMap::get_flags() const {
@@ -1211,7 +1202,7 @@ void CubeMap::set_side(Side p_side, const Ref<Image> &p_image) {
format = p_image->get_format();
w = p_image->get_width();
h = p_image->get_height();
- VS::get_singleton()->texture_allocate(cubemap, w, h, p_image->get_format(), flags | VS::TEXTURE_FLAG_CUBEMAP);
+ VS::get_singleton()->texture_allocate(cubemap, w, h, 0, p_image->get_format(), VS::TEXTURE_TYPE_CUBEMAP, flags);
}
VS::get_singleton()->texture_set_data(cubemap, p_image, VS::CubeMapSide(p_side));
@@ -1322,13 +1313,6 @@ bool CubeMap::_get(const StringName &p_name, Variant &r_ret) const {
void CubeMap::_get_property_list(List<PropertyInfo> *p_list) const {
- PropertyHint img_hint = PROPERTY_HINT_NONE;
- if (storage == STORAGE_COMPRESS_LOSSY) {
- img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY;
- } else if (storage == STORAGE_COMPRESS_LOSSLESS) {
- img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS;
- }
-
p_list->push_back(PropertyInfo(Variant::OBJECT, "side/left", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "side/right", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "side/bottom", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
@@ -1474,7 +1458,7 @@ void CurveTexture::_update() {
Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RF, data));
- VS::get_singleton()->texture_allocate(_texture, _width, 1, Image::FORMAT_RF, VS::TEXTURE_FLAG_FILTER);
+ VS::get_singleton()->texture_allocate(_texture, _width, 1, 0, Image::FORMAT_RF, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
VS::get_singleton()->texture_set_data(_texture, image);
emit_changed();
@@ -1583,7 +1567,7 @@ void GradientTexture::_update() {
Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBA8, data));
- VS::get_singleton()->texture_allocate(texture, width, 1, Image::FORMAT_RGBA8, VS::TEXTURE_FLAG_FILTER);
+ VS::get_singleton()->texture_allocate(texture, width, 1, 0, Image::FORMAT_RGBA8, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
VS::get_singleton()->texture_set_data(texture, image);
emit_changed();
@@ -1876,3 +1860,327 @@ AnimatedTexture::AnimatedTexture() {
AnimatedTexture::~AnimatedTexture() {
VS::get_singleton()->free(proxy);
}
+///////////////////////////////
+
+void TextureLayered::set_flags(uint32_t p_flags) {
+ flags = p_flags;
+
+ if (texture.is_valid()) {
+ VS::get_singleton()->texture_set_flags(texture, flags);
+ }
+}
+
+uint32_t TextureLayered::get_flags() const {
+ return flags;
+}
+
+Image::Format TextureLayered::get_format() const {
+ return format;
+}
+
+uint32_t TextureLayered::get_width() const {
+ return width;
+}
+
+uint32_t TextureLayered::get_height() const {
+ return height;
+}
+
+uint32_t TextureLayered::get_depth() const {
+ return depth;
+}
+
+void TextureLayered::_set_data(const Dictionary &p_data) {
+ ERR_FAIL_COND(!p_data.has("width"));
+ ERR_FAIL_COND(!p_data.has("height"));
+ ERR_FAIL_COND(!p_data.has("depth"));
+ ERR_FAIL_COND(!p_data.has("format"));
+ ERR_FAIL_COND(!p_data.has("flags"));
+ ERR_FAIL_COND(!p_data.has("layers"));
+ int w = p_data["width"];
+ int h = p_data["height"];
+ int d = p_data["depth"];
+ Image::Format format = Image::Format(int(p_data["format"]));
+ int flags = p_data["flags"];
+ Array layers = p_data["layers"];
+ ERR_FAIL_COND(layers.size() != d);
+
+ create(w, h, d, format, flags);
+
+ for (int i = 0; i < layers.size(); i++) {
+ Ref<Image> img = layers[i];
+ ERR_CONTINUE(!img.is_valid());
+ ERR_CONTINUE(img->get_format() != format);
+ ERR_CONTINUE(img->get_width() != w);
+ ERR_CONTINUE(img->get_height() != h);
+ set_layer_data(img, i);
+ }
+}
+
+Dictionary TextureLayered::_get_data() const {
+ Dictionary d;
+ d["width"] = width;
+ d["height"] = height;
+ d["depth"] = depth;
+ d["flags"] = flags;
+ d["format"] = format;
+
+ Array layers;
+ for (int i = 0; i < depth; i++) {
+ layers.push_back(get_layer_data(i));
+ }
+ d["layers"] = layers;
+ return d;
+}
+
+void TextureLayered::create(uint32_t p_width, uint32_t p_height, uint32_t p_depth, Image::Format p_format, uint32_t p_flags) {
+ VS::get_singleton()->texture_allocate(texture, p_width, p_height, p_depth, p_format, is_3d ? VS::TEXTURE_TYPE_3D : VS::TEXTURE_TYPE_2D_ARRAY, p_flags);
+
+ width = p_width;
+ height = p_height;
+ depth = p_depth;
+
+ flags = p_flags;
+}
+
+void TextureLayered::set_layer_data(const Ref<Image> &p_image, int p_layer) {
+ ERR_FAIL_COND(!texture.is_valid());
+ VS::get_singleton()->texture_set_data(texture, p_image, p_layer);
+}
+
+Ref<Image> TextureLayered::get_layer_data(int p_layer) const {
+
+ ERR_FAIL_COND_V(!texture.is_valid(), Ref<Image>());
+ return VS::get_singleton()->texture_get_data(texture, p_layer);
+}
+
+void TextureLayered::set_data_partial(const Ref<Image> &p_image, int p_x_ofs, int p_y_ofs, int p_z, int p_mipmap) {
+ ERR_FAIL_COND(!texture.is_valid());
+ VS::get_singleton()->texture_set_data_partial(texture, p_image, 0, 0, p_image->get_width(), p_image->get_height(), p_x_ofs, p_y_ofs, p_mipmap, p_z);
+}
+
+RID TextureLayered::get_rid() const {
+ return texture;
+}
+
+void TextureLayered::set_path(const String &p_path, bool p_take_over) {
+ if (texture.is_valid()) {
+ VS::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ Resource::set_path(p_path, p_take_over);
+}
+
+void TextureLayered::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextureLayered::set_flags);
+ ClassDB::bind_method(D_METHOD("get_flags"), &TextureLayered::get_flags);
+
+ ClassDB::bind_method(D_METHOD("get_format"), &TextureLayered::get_format);
+
+ ClassDB::bind_method(D_METHOD("get_width"), &TextureLayered::get_width);
+ ClassDB::bind_method(D_METHOD("get_height"), &TextureLayered::get_height);
+ ClassDB::bind_method(D_METHOD("get_depth"), &TextureLayered::get_depth);
+
+ ClassDB::bind_method(D_METHOD("create", "width", "height", "depth", "format", "flags"), &TextureLayered::create, DEFVAL(FLAGS_DEFAULT));
+ ClassDB::bind_method(D_METHOD("set_layer_data", "image", "layer"), &TextureLayered::set_layer_data);
+ ClassDB::bind_method(D_METHOD("get_layer_data", "layer"), &TextureLayered::set_layer_data);
+ ClassDB::bind_method(D_METHOD("set_data_partial", "image", "x_offset", "y_offset", "layer", "mipmap"), &TextureLayered::set_data_partial, DEFVAL(0));
+
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &TextureLayered::_set_data);
+ ClassDB::bind_method(D_METHOD("_get_data"), &TextureLayered::_get_data);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter"), "set_flags", "get_flags");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
+
+ BIND_ENUM_CONSTANT(FLAG_MIPMAPS);
+ BIND_ENUM_CONSTANT(FLAG_REPEAT);
+ BIND_ENUM_CONSTANT(FLAG_FILTER);
+ BIND_ENUM_CONSTANT(FLAGS_DEFAULT);
+}
+
+TextureLayered::TextureLayered(bool p_3d) {
+ is_3d = p_3d;
+ format = Image::FORMAT_MAX;
+ flags = FLAGS_DEFAULT;
+
+ width = 0;
+ height = 0;
+ depth = 0;
+
+ texture = VS::get_singleton()->texture_create();
+}
+
+TextureLayered::~TextureLayered() {
+ if (texture.is_valid()) {
+ VS::get_singleton()->free(texture);
+ }
+}
+
+RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error) {
+
+ if (r_error) {
+ *r_error = ERR_CANT_OPEN;
+ }
+
+ Ref<TextureLayered> lt;
+ Ref<Texture3D> tex3d;
+ Ref<TextureArray> texarr;
+
+ if (p_path.ends_with("tex3d")) {
+ tex3d.instance();
+ lt = tex3d;
+ } else if (p_path.ends_with("texarr")) {
+ texarr.instance();
+ lt = texarr;
+ } else {
+ ERR_EXPLAIN("Unrecognized layered texture extension");
+ ERR_FAIL_V(RES());
+ }
+
+ FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V(!f, RES());
+
+ uint8_t header[5] = { 0, 0, 0, 0, 0 };
+ f->get_buffer(header, 4);
+
+ if (header[0] == 'G' && header[1] == 'D' && header[2] == '3' && header[3] == 'T') {
+ if (tex3d.is_null()) {
+ memdelete(f);
+ ERR_FAIL_COND_V(tex3d.is_null(), RES())
+ }
+ } else if (header[0] == 'G' && header[1] == 'D' && header[2] == 'A' && header[3] == 'T') {
+ if (texarr.is_null()) {
+ memdelete(f);
+ ERR_FAIL_COND_V(texarr.is_null(), RES())
+ }
+ } else {
+
+ ERR_EXPLAIN("Unrecognized layered texture file format: " + String((const char *)header));
+ ERR_FAIL_V(RES());
+ }
+
+ int tw = f->get_32();
+ int th = f->get_32();
+ int td = f->get_32();
+ int flags = f->get_32(); //texture flags!
+ Image::Format format = Image::Format(f->get_32());
+ uint32_t compression = f->get_32(); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed
+
+ lt->create(tw, th, td, format, flags);
+
+ for (int layer = 0; layer < td; layer++) {
+
+ Ref<Image> image;
+ image.instance();
+
+ if (compression == COMPRESSION_LOSSLESS) {
+ //look for a PNG file inside
+
+ int mipmaps = f->get_32();
+ Vector<Ref<Image> > mipmap_images;
+
+ for (int i = 0; i < mipmaps; i++) {
+ uint32_t size = f->get_32();
+
+ PoolVector<uint8_t> pv;
+ pv.resize(size);
+ {
+ PoolVector<uint8_t>::Write w = pv.write();
+ f->get_buffer(w.ptr(), size);
+ }
+
+ Ref<Image> img = Image::lossless_unpacker(pv);
+
+ if (img.is_null() || img->empty() || format != img->get_format()) {
+ if (r_error) {
+ *r_error = ERR_FILE_CORRUPT;
+ }
+ memdelete(f);
+ ERR_FAIL_V(RES());
+ }
+
+ mipmap_images.push_back(img);
+ }
+
+ if (mipmap_images.size() == 1) {
+
+ image = mipmap_images[0];
+
+ } else {
+ int total_size = Image::get_image_data_size(tw, th, format, true);
+ PoolVector<uint8_t> img_data;
+ img_data.resize(total_size);
+
+ {
+ PoolVector<uint8_t>::Write w = img_data.write();
+
+ int ofs = 0;
+ for (int i = 0; i < mipmap_images.size(); i++) {
+
+ PoolVector<uint8_t> id = mipmap_images[i]->get_data();
+ int len = id.size();
+ PoolVector<uint8_t>::Read r = id.read();
+ copymem(&w[ofs], r.ptr(), len);
+ ofs += len;
+ }
+ }
+
+ image->create(tw, th, true, format, img_data);
+ if (image->empty()) {
+ if (r_error) {
+ *r_error = ERR_FILE_CORRUPT;
+ }
+ memdelete(f);
+ ERR_FAIL_V(RES());
+ }
+ }
+
+ } else {
+
+ //look for regular format
+ bool mipmaps = (flags & Texture::FLAG_MIPMAPS);
+ int total_size = Image::get_image_data_size(tw, th, format, mipmaps);
+
+ PoolVector<uint8_t> img_data;
+ img_data.resize(total_size);
+
+ {
+ PoolVector<uint8_t>::Write w = img_data.write();
+ int bytes = f->get_buffer(w.ptr(), total_size);
+ if (bytes != total_size) {
+ if (r_error) {
+ *r_error = ERR_FILE_CORRUPT;
+ memdelete(f);
+ }
+ ERR_FAIL_V(RES());
+ }
+ }
+
+ image->create(tw, th, mipmaps, format, img_data);
+ }
+
+ lt->set_layer_data(image, layer);
+ }
+
+ if (r_error)
+ *r_error = OK;
+
+ return lt;
+}
+
+void ResourceFormatLoaderTextureLayered::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("tex3d");
+ p_extensions->push_back("texarr");
+}
+bool ResourceFormatLoaderTextureLayered::handles_type(const String &p_type) const {
+ return p_type == "Texture3D" || p_type == "TextureArray";
+}
+String ResourceFormatLoaderTextureLayered::get_resource_type(const String &p_path) const {
+
+ if (p_path.get_extension().to_lower() == "tex3d")
+ return "Texture3D";
+ if (p_path.get_extension().to_lower() == "texarr")
+ return "TextureArray";
+ return "";
+}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index c994bdad5f..1c18189b2c 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -401,6 +401,88 @@ VARIANT_ENUM_CAST(CubeMap::Flags)
VARIANT_ENUM_CAST(CubeMap::Side)
VARIANT_ENUM_CAST(CubeMap::Storage)
+class TextureLayered : public Resource {
+
+ GDCLASS(TextureLayered, Resource)
+
+public:
+ enum Flags {
+ FLAG_MIPMAPS = VisualServer::TEXTURE_FLAG_MIPMAPS,
+ FLAG_REPEAT = VisualServer::TEXTURE_FLAG_REPEAT,
+ FLAG_FILTER = VisualServer::TEXTURE_FLAG_FILTER,
+ FLAG_CONVERT_TO_LINEAR = VisualServer::TEXTURE_FLAG_CONVERT_TO_LINEAR,
+ FLAGS_DEFAULT = FLAG_FILTER,
+ };
+
+private:
+ bool is_3d;
+ RID texture;
+ Image::Format format;
+ uint32_t flags;
+
+ int width;
+ int height;
+ int depth;
+
+ void _set_data(const Dictionary &p_data);
+ Dictionary _get_data() const;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_flags(uint32_t p_flags);
+ uint32_t get_flags() const;
+
+ Image::Format get_format() const;
+ uint32_t get_width() const;
+ uint32_t get_height() const;
+ uint32_t get_depth() const;
+
+ void create(uint32_t p_width, uint32_t p_height, uint32_t p_depth, Image::Format p_format, uint32_t p_flags = FLAGS_DEFAULT);
+ void set_layer_data(const Ref<Image> &p_image, int p_layer);
+ Ref<Image> get_layer_data(int p_layer) const;
+ void set_data_partial(const Ref<Image> &p_image, int p_x_ofs, int p_y_ofs, int p_z, int p_mipmap = 0);
+
+ virtual RID get_rid() const;
+ virtual void set_path(const String &p_path, bool p_take_over = false);
+
+ TextureLayered(bool p_3d = false);
+ ~TextureLayered();
+};
+
+VARIANT_ENUM_CAST(TextureLayered::Flags)
+
+class Texture3D : public TextureLayered {
+
+ GDCLASS(Texture3D, TextureLayered)
+public:
+ Texture3D() :
+ TextureLayered(true) {}
+};
+
+class TextureArray : public TextureLayered {
+
+ GDCLASS(TextureArray, TextureLayered)
+public:
+ TextureArray() :
+ TextureLayered(false) {}
+};
+
+class ResourceFormatLoaderTextureLayered : public ResourceFormatLoader {
+public:
+ enum Compression {
+ COMPRESSION_LOSSLESS,
+ COMPRESSION_VRAM,
+ COMPRESSION_UNCOMPRESSED
+ };
+
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
class CurveTexture : public Texture {
GDCLASS(CurveTexture, Texture)
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index dd50671fa0..3d2b6c36de 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -262,7 +262,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"));
p_list->push_back(PropertyInfo(Variant::COLOR, pre + "modulate"));
p_list->push_back(PropertyInfo(Variant::RECT2, pre + "region"));
- p_list->push_back(PropertyInfo(Variant::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE"));
+ p_list->push_back(PropertyInfo(Variant::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE,ATLAS_TILE"));
if (tile_get_tile_mode(id) == AUTO_TILE) {
p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3 (minimal),3X3", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/bitmask_flags", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
@@ -272,6 +272,12 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/priority_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ } else if (tile_get_tile_mode(id) == ATLAS_TILE) {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/icon_coordinate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/spacing", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "occluder_offset"));
p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D"));
@@ -494,8 +500,21 @@ uint16_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) {
const Map<Vector2, uint16_t> &TileSet::autotile_get_bitmask_map(int p_id) {
static Map<Vector2, uint16_t> dummy;
+ static Map<Vector2, uint16_t> dummy_atlas;
ERR_FAIL_COND_V(!tile_map.has(p_id), dummy);
- return tile_map[p_id].autotile_data.flags;
+ if (tile_get_tile_mode(p_id) == ATLAS_TILE) {
+ dummy_atlas = Map<Vector2, uint16_t>();
+ Rect2 region = tile_get_region(p_id);
+ Size2 size = autotile_get_size(p_id);
+ float spacing = autotile_get_spacing(p_id);
+ for (int x = 0; x < (region.size.x / (size.x + spacing)); x++) {
+ for (int y = 0; y < (region.size.y / (size.y + spacing)); y++) {
+ dummy_atlas.insert(Vector2(x, y), 0);
+ }
+ }
+ return dummy_atlas;
+ } else
+ return tile_map[p_id].autotile_data.flags;
}
Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node, const Vector2 &p_tile_location) {
@@ -976,7 +995,7 @@ void TileSet::_bind_methods() {
BIND_ENUM_CONSTANT(SINGLE_TILE);
BIND_ENUM_CONSTANT(AUTO_TILE);
- BIND_ENUM_CONSTANT(ANIMATED_TILE);
+ BIND_ENUM_CONSTANT(ATLAS_TILE);
}
TileSet::TileSet() {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index ec635ee5cc..40eee2700d 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -75,7 +75,7 @@ public:
enum TileMode {
SINGLE_TILE,
AUTO_TILE,
- ANIMATED_TILE
+ ATLAS_TILE
};
struct AutotileData {
diff --git a/servers/physics/body_pair_sw.cpp b/servers/physics/body_pair_sw.cpp
index 5a41b621eb..0ce38e4486 100644
--- a/servers/physics/body_pair_sw.cpp
+++ b/servers/physics/body_pair_sw.cpp
@@ -212,41 +212,11 @@ bool BodyPairSW::_test_ccd(real_t p_step, BodySW *p_A, int p_shape_A, const Tran
}
real_t combine_bounce(BodySW *A, BodySW *B) {
- const PhysicsServer::CombineMode cm = A->get_bounce_combine_mode();
-
- switch (cm) {
- case PhysicsServer::COMBINE_MODE_INHERIT:
- if (B->get_bounce_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT)
- return combine_bounce(B, A);
- // else use MAX [This is used when the two bodies doesn't use physical material]
- case PhysicsServer::COMBINE_MODE_MAX:
- return MAX(A->get_bounce(), B->get_bounce());
- case PhysicsServer::COMBINE_MODE_MIN:
- return MIN(A->get_bounce(), B->get_bounce());
- case PhysicsServer::COMBINE_MODE_MULTIPLY:
- return A->get_bounce() * B->get_bounce();
- default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE:
- return (A->get_bounce() + B->get_bounce()) / 2;
- }
+ return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1);
}
real_t combine_friction(BodySW *A, BodySW *B) {
- const PhysicsServer::CombineMode cm = A->get_friction_combine_mode();
-
- switch (cm) {
- case PhysicsServer::COMBINE_MODE_INHERIT:
- if (B->get_friction_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT)
- return combine_friction(B, A);
- // else use Multiply [This is used when the two bodies doesn't use physical material]
- case PhysicsServer::COMBINE_MODE_MULTIPLY:
- return A->get_friction() * B->get_friction();
- case PhysicsServer::COMBINE_MODE_MAX:
- return MAX(A->get_friction(), B->get_friction());
- case PhysicsServer::COMBINE_MODE_MIN:
- return MIN(A->get_friction(), B->get_friction());
- default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE:
- return (A->get_friction() + B->get_friction()) / 2;
- }
+ return ABS(MIN(A->get_friction(), B->get_friction()));
}
bool BodyPairSW::setup(real_t p_step) {
diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp
index 59f987fc17..cc9681193c 100644
--- a/servers/physics/body_sw.cpp
+++ b/servers/physics/body_sw.cpp
@@ -423,22 +423,6 @@ void BodySW::_compute_area_gravity_and_dampenings(const AreaSW *p_area) {
area_angular_damp += p_area->get_angular_damp();
}
-void BodySW::set_combine_mode(PhysicsServer::BodyParameter p_param, PhysicsServer::CombineMode p_mode) {
- if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) {
- bounce_combine_mode = p_mode;
- } else {
- friction_combine_mode = p_mode;
- }
-}
-
-PhysicsServer::CombineMode BodySW::get_combine_mode(PhysicsServer::BodyParameter p_param) const {
- if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) {
- return bounce_combine_mode;
- } else {
- return friction_combine_mode;
- }
-}
-
void BodySW::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock) {
if (lock) {
locked_axis |= p_axis;
diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h
index 5df270f679..9d7b147fd6 100644
--- a/servers/physics/body_sw.h
+++ b/servers/physics/body_sw.h
@@ -49,8 +49,6 @@ class BodySW : public CollisionObjectSW {
real_t mass;
real_t bounce;
real_t friction;
- PhysicsServer::CombineMode bounce_combine_mode;
- PhysicsServer::CombineMode friction_combine_mode;
real_t linear_damp;
real_t angular_damp;
@@ -304,12 +302,6 @@ public:
_FORCE_INLINE_ Vector3 get_gravity() const { return gravity; }
_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
- void set_combine_mode(PhysicsServer::BodyParameter p_param, PhysicsServer::CombineMode p_mode);
- PhysicsServer::CombineMode get_combine_mode(PhysicsServer::BodyParameter p_param) const;
-
- _FORCE_INLINE_ PhysicsServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; }
- _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; }
-
void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock);
bool is_axis_locked(PhysicsServer::BodyAxis p_axis) const;
diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp
index 8f2b147460..b059c20c95 100644
--- a/servers/physics/collision_solver_sat.cpp
+++ b/servers/physics/collision_solver_sat.cpp
@@ -560,6 +560,12 @@ static void _collision_sphere_capsule(const ShapeSW *p_a, const Transform &p_tra
}
template <bool withMargin>
+static void _collision_sphere_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+
+ return;
+}
+
+template <bool withMargin>
static void _collision_sphere_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW *>(p_a);
@@ -851,6 +857,12 @@ static void _collision_box_capsule(const ShapeSW *p_a, const Transform &p_transf
}
template <bool withMargin>
+static void _collision_box_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+
+ return;
+}
+
+template <bool withMargin>
static void _collision_box_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
const BoxShapeSW *box_A = static_cast<const BoxShapeSW *>(p_a);
@@ -1127,6 +1139,12 @@ static void _collision_capsule_capsule(const ShapeSW *p_a, const Transform &p_tr
}
template <bool withMargin>
+static void _collision_capsule_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+
+ return;
+}
+
+template <bool withMargin>
static void _collision_capsule_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
const CapsuleShapeSW *capsule_A = static_cast<const CapsuleShapeSW *>(p_a);
@@ -1247,6 +1265,24 @@ static void _collision_capsule_face(const ShapeSW *p_a, const Transform &p_trans
}
template <bool withMargin>
+static void _collision_cylinder_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+
+ return;
+}
+
+template <bool withMargin>
+static void _collision_cylinder_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+
+ return;
+}
+
+template <bool withMargin>
+static void _collision_cylinder_face(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+
+ return;
+}
+
+template <bool withMargin>
static void _collision_convex_polygon_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
const ConvexPolygonShapeSW *convex_polygon_A = static_cast<const ConvexPolygonShapeSW *>(p_a);
@@ -1475,59 +1511,81 @@ bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform &p_tran
ERR_FAIL_COND_V(type_B == PhysicsServer::SHAPE_RAY, false);
ERR_FAIL_COND_V(p_shape_B->is_concave(), false);
- static const CollisionFunc collision_table[5][5] = {
+ static const CollisionFunc collision_table[6][6] = {
{ _collision_sphere_sphere<false>,
_collision_sphere_box<false>,
_collision_sphere_capsule<false>,
+ _collision_sphere_cylinder<false>,
_collision_sphere_convex_polygon<false>,
_collision_sphere_face<false> },
{ 0,
_collision_box_box<false>,
_collision_box_capsule<false>,
+ _collision_box_cylinder<false>,
_collision_box_convex_polygon<false>,
_collision_box_face<false> },
{ 0,
0,
_collision_capsule_capsule<false>,
+ _collision_capsule_cylinder<false>,
_collision_capsule_convex_polygon<false>,
_collision_capsule_face<false> },
{ 0,
0,
0,
+ _collision_cylinder_cylinder<false>,
+ _collision_cylinder_convex_polygon<false>,
+ _collision_cylinder_face<false> },
+ { 0,
+ 0,
+ 0,
+ 0,
_collision_convex_polygon_convex_polygon<false>,
_collision_convex_polygon_face<false> },
{ 0,
0,
0,
0,
+ 0,
0 },
};
- static const CollisionFunc collision_table_margin[5][5] = {
+ static const CollisionFunc collision_table_margin[6][6] = {
{ _collision_sphere_sphere<true>,
_collision_sphere_box<true>,
_collision_sphere_capsule<true>,
+ _collision_sphere_cylinder<true>,
_collision_sphere_convex_polygon<true>,
_collision_sphere_face<true> },
{ 0,
_collision_box_box<true>,
_collision_box_capsule<true>,
+ _collision_box_cylinder<true>,
_collision_box_convex_polygon<true>,
_collision_box_face<true> },
{ 0,
0,
_collision_capsule_capsule<true>,
+ _collision_capsule_cylinder<true>,
_collision_capsule_convex_polygon<true>,
_collision_capsule_face<true> },
{ 0,
0,
0,
+ _collision_cylinder_cylinder<true>,
+ _collision_cylinder_convex_polygon<true>,
+ _collision_cylinder_face<true> },
+ { 0,
+ 0,
+ 0,
+ 0,
_collision_convex_polygon_convex_polygon<true>,
_collision_convex_polygon_face<true> },
{ 0,
0,
0,
0,
+ 0,
0 },
};
diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp
index a06942cb2a..3a32c46a9b 100644
--- a/servers/physics/physics_server_sw.cpp
+++ b/servers/physics/physics_server_sw.cpp
@@ -701,20 +701,6 @@ real_t PhysicsServerSW::body_get_param(RID p_body, BodyParameter p_param) const
return body->get_param(p_param);
};
-void PhysicsServerSW::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) {
- BodySW *body = body_owner.get(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_combine_mode(p_param, p_mode);
-}
-
-PhysicsServer::CombineMode PhysicsServerSW::body_get_combine_mode(RID p_body, BodyParameter p_param) const {
- BodySW *body = body_owner.get(p_body);
- ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT);
-
- return body->get_combine_mode(p_param);
-}
-
void PhysicsServerSW::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
BodySW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h
index 57037fb325..1c5754124d 100644
--- a/servers/physics/physics_server_sw.h
+++ b/servers/physics/physics_server_sw.h
@@ -188,10 +188,6 @@ public:
virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value);
virtual real_t body_get_param(RID p_body, BodyParameter p_param) const;
- /// p_param accept only Bounce and Friction
- virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode);
- virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const;
-
virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin);
virtual real_t body_get_kinematic_safe_margin(RID p_body) const;
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index fcd2a65ee7..aa063d6c1e 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -405,22 +405,6 @@ void Body2DSW::_compute_area_gravity_and_dampenings(const Area2DSW *p_area) {
area_angular_damp += p_area->get_angular_damp();
}
-void Body2DSW::set_combine_mode(Physics2DServer::BodyParameter p_param, Physics2DServer::CombineMode p_mode) {
- if (p_param == Physics2DServer::BODY_PARAM_BOUNCE) {
- bounce_combine_mode = p_mode;
- } else {
- friction_combine_mode = p_mode;
- }
-}
-
-Physics2DServer::CombineMode Body2DSW::get_combine_mode(Physics2DServer::BodyParameter p_param) const {
- if (p_param == Physics2DServer::BODY_PARAM_BOUNCE) {
- return bounce_combine_mode;
- } else {
- return friction_combine_mode;
- }
-}
-
void Body2DSW::integrate_forces(real_t p_step) {
if (mode == Physics2DServer::BODY_MODE_STATIC)
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index fef233a72b..69184ad484 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/body_2d_sw.h
@@ -54,8 +54,6 @@ class Body2DSW : public CollisionObject2DSW {
real_t mass;
real_t bounce;
real_t friction;
- Physics2DServer::CombineMode bounce_combine_mode;
- Physics2DServer::CombineMode friction_combine_mode;
real_t _inv_mass;
real_t _inv_inertia;
@@ -274,12 +272,6 @@ public:
_FORCE_INLINE_ real_t get_linear_damp() const { return linear_damp; }
_FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; }
- void set_combine_mode(Physics2DServer::BodyParameter p_param, Physics2DServer::CombineMode p_mode);
- Physics2DServer::CombineMode get_combine_mode(Physics2DServer::BodyParameter p_param) const;
-
- _FORCE_INLINE_ Physics2DServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; }
- _FORCE_INLINE_ Physics2DServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; }
-
void integrate_forces(real_t p_step);
void integrate_velocities(real_t p_step);
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index be8dcf6fa8..2633edf7bb 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/body_pair_2d_sw.cpp
@@ -220,41 +220,11 @@ bool BodyPair2DSW::_test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const
}
real_t combine_bounce(Body2DSW *A, Body2DSW *B) {
- const Physics2DServer::CombineMode cm = A->get_bounce_combine_mode();
-
- switch (cm) {
- case Physics2DServer::COMBINE_MODE_INHERIT:
- if (B->get_bounce_combine_mode() != Physics2DServer::COMBINE_MODE_INHERIT)
- return combine_bounce(B, A);
- // else use MAX [This is used when the two bodies doesn't use physical material]
- case Physics2DServer::COMBINE_MODE_MAX:
- return MAX(A->get_bounce(), B->get_bounce());
- case Physics2DServer::COMBINE_MODE_MIN:
- return MIN(A->get_bounce(), B->get_bounce());
- case Physics2DServer::COMBINE_MODE_MULTIPLY:
- return A->get_bounce() * B->get_bounce();
- default: // Is always Physics2DServer::COMBINE_MODE_AVERAGE:
- return (A->get_bounce() + B->get_bounce()) / 2;
- }
+ return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1);
}
real_t combine_friction(Body2DSW *A, Body2DSW *B) {
- const Physics2DServer::CombineMode cm = A->get_friction_combine_mode();
-
- switch (cm) {
- case Physics2DServer::COMBINE_MODE_INHERIT:
- if (B->get_friction_combine_mode() != Physics2DServer::COMBINE_MODE_INHERIT)
- return combine_friction(B, A);
- // else use Multiply [This is used when the two bodies doesn't use physical material]
- case Physics2DServer::COMBINE_MODE_MULTIPLY:
- return A->get_friction() * B->get_friction();
- case Physics2DServer::COMBINE_MODE_MAX:
- return MAX(A->get_friction(), B->get_friction());
- case Physics2DServer::COMBINE_MODE_MIN:
- return MIN(A->get_friction(), B->get_friction());
- default: // Is always Physics2DServer::COMBINE_MODE_AVERAGE:
- return (A->get_friction() + B->get_friction()) / 2;
- }
+ return ABS(MIN(A->get_friction(), B->get_friction()));
}
bool BodyPair2DSW::setup(real_t p_step) {
diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp
index ba87969eea..15e80bcd5e 100644
--- a/servers/physics_2d/physics_2d_server_sw.cpp
+++ b/servers/physics_2d/physics_2d_server_sw.cpp
@@ -789,22 +789,6 @@ real_t Physics2DServerSW::body_get_param(RID p_body, BodyParameter p_param) cons
return body->get_param(p_param);
};
-void Physics2DServerSW::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) {
-
- Body2DSW *body = body_owner.get(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_combine_mode(p_param, p_mode);
-}
-
-Physics2DServer::CombineMode Physics2DServerSW::body_get_combine_mode(RID p_body, BodyParameter p_param) const {
-
- Body2DSW *body = body_owner.get(p_body);
- ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT);
-
- return body->get_combine_mode(p_param);
-}
-
void Physics2DServerSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
Body2DSW *body = body_owner.get(p_body);
diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h
index 0b8d3f2a31..d4fc44b1d7 100644
--- a/servers/physics_2d/physics_2d_server_sw.h
+++ b/servers/physics_2d/physics_2d_server_sw.h
@@ -200,10 +200,6 @@ public:
virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value);
virtual real_t body_get_param(RID p_body, BodyParameter p_param) const;
- /// p_param accept only Bounce and Friction
- virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode);
- virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const;
-
virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant);
virtual Variant body_get_state(RID p_body, BodyState p_state) const;
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h
index b9b0f80805..6b34fb9739 100644
--- a/servers/physics_2d/physics_2d_server_wrap_mt.h
+++ b/servers/physics_2d/physics_2d_server_wrap_mt.h
@@ -211,9 +211,6 @@ public:
FUNC3(body_set_param, RID, BodyParameter, real_t);
FUNC2RC(real_t, body_get_param, RID, BodyParameter);
- FUNC3(body_set_combine_mode, RID, BodyParameter, CombineMode);
- FUNC2RC(CombineMode, body_get_combine_mode, RID, BodyParameter);
-
FUNC3(body_set_state, RID, BodyState, const Variant &);
FUNC2RC(Variant, body_get_state, RID, BodyState);
diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h
index 796eec1e8e..f42d9868f0 100644
--- a/servers/physics_2d_server.h
+++ b/servers/physics_2d_server.h
@@ -423,19 +423,6 @@ public:
virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0;
virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0;
- enum CombineMode {
- COMBINE_MODE_MAX,
- COMBINE_MODE_MIN,
- COMBINE_MODE_MULTIPLY,
- COMBINE_MODE_AVERAGE,
-
- COMBINE_MODE_INHERIT /// Inherit from other body or use COMBINE_MODE_MAX (Restitution) COMBINE_MODE_MULTIPLY (Friction)
- };
-
- /// p_param accept only Bounce and Friction
- virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) = 0;
- virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const = 0;
-
//state
enum BodyState {
BODY_STATE_TRANSFORM,
diff --git a/servers/physics_server.h b/servers/physics_server.h
index 294c6b6674..948aec1a2d 100644
--- a/servers/physics_server.h
+++ b/servers/physics_server.h
@@ -401,19 +401,6 @@ public:
virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0;
virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0;
- enum CombineMode {
- COMBINE_MODE_MAX,
- COMBINE_MODE_MIN,
- COMBINE_MODE_MULTIPLY,
- COMBINE_MODE_AVERAGE,
-
- COMBINE_MODE_INHERIT /// Inherit from other body or use COMBINE_MODE_MAX (Restitution) COMBINE_MODE_MULTIPLY (Friction)
- };
-
- /// p_param accept only Bounce and Friction
- virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) = 0;
- virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const = 0;
-
virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) = 0;
virtual real_t body_get_kinematic_safe_margin(RID p_body) const = 0;
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index aa0e5c289b..156e8c8bea 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -73,7 +73,7 @@ static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsag
usage.vram = E->get().bytes;
usage.id = E->get().texture;
usage.type = "Texture";
- usage.format = itos(E->get().size.width) + "x" + itos(E->get().size.height) + " " + Image::get_format_name(E->get().format);
+ usage.format = itos(E->get().width) + "x" + itos(E->get().height) + " " + Image::get_format_name(E->get().format);
r_usage->push_back(usage);
}
}
diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h
index 611e25af2a..843773e5b1 100644
--- a/servers/server_wrap_mt_common.h
+++ b/servers/server_wrap_mt_common.h
@@ -197,9 +197,10 @@
}
#define FUNC5RID(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \
- int m_type##allocn() { \
- for (int i = 0; i < m_type##_pool_max_size; i++) { \
- m_type##_id_pool.push_back(server_name->m_type##_create()); \
+ List<RID> m_type##_id_pool; \
+ int m_type##allocn(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
+ for (int i = 0; i < pool_max_size; i++) { \
+ m_type##_id_pool.push_back(server_name->m_type##_create(p1, p2, p3, p4, p5)); \
} \
return 0; \
} \
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index 5ce4f2b62d..49dff0d557 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -176,17 +176,34 @@ public:
/* TEXTURE API */
virtual RID texture_create() = 0;
- virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) = 0;
- virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) = 0;
- virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) = 0;
- virtual Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const = 0;
+ virtual void texture_allocate(RID p_texture,
+ int p_width,
+ int p_height,
+ int p_depth_3d,
+ Image::Format p_format,
+ VS::TextureType p_type,
+ uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) = 0;
+
+ virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_level = 0) = 0;
+
+ virtual void texture_set_data_partial(RID p_texture,
+ const Ref<Image> &p_image,
+ int src_x, int src_y,
+ int src_w, int src_h,
+ int dst_x, int dst_y,
+ int p_dst_mip,
+ int p_level = 0) = 0;
+
+ virtual Ref<Image> texture_get_data(RID p_texture, int p_level = 0) const = 0;
virtual void texture_set_flags(RID p_texture, uint32_t p_flags) = 0;
virtual uint32_t texture_get_flags(RID p_texture) const = 0;
virtual Image::Format texture_get_format(RID p_texture) const = 0;
+ virtual VS::TextureType texture_get_type(RID p_texture) const = 0;
virtual uint32_t texture_get_texid(RID p_texture) const = 0;
virtual uint32_t texture_get_width(RID p_texture) const = 0;
virtual uint32_t texture_get_height(RID p_texture) const = 0;
- virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0;
+ virtual uint32_t texture_get_depth(RID p_texture) const = 0;
+ virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) = 0;
virtual void texture_set_path(RID p_texture, const String &p_path) = 0;
virtual String texture_get_path(RID p_texture) const = 0;
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index d4fb8d98b0..ca50d0d049 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -123,6 +123,12 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
"TYPE_SAMPLER2D",
"TYPE_ISAMPLER2D",
"TYPE_USAMPLER2D",
+ "TYPE_SAMPLER2DARRAY",
+ "TYPE_ISAMPLER2DARRAY",
+ "TYPE_USAMPLER2DARRAY",
+ "TYPE_SAMPLER3D",
+ "TYPE_ISAMPLER3D",
+ "TYPE_USAMPLER3D",
"TYPE_SAMPLERCUBE",
"INTERPOLATION_FLAT",
"INTERPOLATION_NO_PERSPECTIVE",
@@ -257,6 +263,12 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_TYPE_SAMPLER2D, "sampler2D" },
{ TK_TYPE_ISAMPLER2D, "isampler2D" },
{ TK_TYPE_USAMPLER2D, "usampler2D" },
+ { TK_TYPE_SAMPLER2DARRAY, "sampler2DArray" },
+ { TK_TYPE_ISAMPLER2DARRAY, "isampler2DArray" },
+ { TK_TYPE_USAMPLER2DARRAY, "usampler2DArray" },
+ { TK_TYPE_SAMPLER3D, "sampler3D" },
+ { TK_TYPE_ISAMPLER3D, "isampler3D" },
+ { TK_TYPE_USAMPLER3D, "usampler3D" },
{ TK_TYPE_SAMPLERCUBE, "samplerCube" },
{ TK_INTERPOLATION_FLAT, "flat" },
{ TK_INTERPOLATION_NO_PERSPECTIVE, "noperspective" },
@@ -516,13 +528,14 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
bool hexa_found = false;
bool sign_found = false;
bool minus_exponent_found = false;
+ bool float_suffix_found = false;
String str;
int i = 0;
while (true) {
if (GETCHAR(i) == '.') {
- if (period_found || exponent_found)
+ if (period_found || exponent_found || hexa_found || float_suffix_found)
return _make_token(TK_ERROR, "Invalid numeric constant");
period_found = true;
} else if (GETCHAR(i) == 'x') {
@@ -530,11 +543,16 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
return _make_token(TK_ERROR, "Invalid numeric constant");
hexa_found = true;
} else if (GETCHAR(i) == 'e') {
- if (hexa_found || exponent_found)
+ if (hexa_found || exponent_found || float_suffix_found)
return _make_token(TK_ERROR, "Invalid numeric constant");
exponent_found = true;
+ } else if (GETCHAR(i) == 'f') {
+ if (hexa_found || exponent_found)
+ return _make_token(TK_ERROR, "Invalid numeric constant");
+ float_suffix_found = true;
} else if (_is_number(GETCHAR(i))) {
- //all ok
+ if (float_suffix_found)
+ return _make_token(TK_ERROR, "Invalid numeric constant");
} else if (hexa_found && _is_hex(GETCHAR(i))) {
} else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) {
@@ -550,21 +568,60 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
i++;
}
- if (!_is_number(str[str.length() - 1]))
- return _make_token(TK_ERROR, "Invalid numeric constant");
+ CharType last_char = str[str.length() - 1];
+
+ if (hexa_found) {
+ //hex integers eg."0xFF" or "0x12AB", etc - NOT supported yet
+ return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant - Not supported");
+ } else if (period_found || float_suffix_found) {
+ //floats
+ if (period_found) {
+ if (float_suffix_found) {
+ //checks for eg "1.f" or "1.99f" notations
+ if (last_char != 'f') {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ } else {
+ //checks for eg. "1." or "1.99" notations
+ if (last_char != '.' && !_is_number(last_char)) {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ }
+ } else if (float_suffix_found) {
+ // if no period found the float suffix must be the last character, like in "2f" for "2.0"
+ if (last_char != 'f') {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ }
+
+ if (float_suffix_found) {
+ //strip the suffix
+ str = str.left(str.length() - 1);
+ //compensate reading cursor position
+ char_idx += 1;
+ }
+
+ if (!str.is_valid_float()) {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ } else {
+ //integers
+ if (!_is_number(last_char)) {
+ return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
+ }
+ if (!str.is_valid_integer()) {
+ return _make_token(TK_ERROR, "Invalid numeric constant");
+ }
+ }
char_idx += str.length();
Token tk;
- if (period_found || minus_exponent_found)
+ if (period_found || minus_exponent_found || float_suffix_found)
tk.type = TK_REAL_CONSTANT;
else
tk.type = TK_INT_CONSTANT;
- if (!str.is_valid_float()) {
- return _make_token(TK_ERROR, "Invalid numeric constant");
- }
-
- tk.constant = str.to_double();
+ tk.constant = str.to_double(); //wont work with hex
tk.line = tk_line;
return tk;
@@ -660,6 +717,12 @@ bool ShaderLanguage::is_token_datatype(TokenType p_type) {
p_type == TK_TYPE_SAMPLER2D ||
p_type == TK_TYPE_ISAMPLER2D ||
p_type == TK_TYPE_USAMPLER2D ||
+ p_type == TK_TYPE_SAMPLER2DARRAY ||
+ p_type == TK_TYPE_ISAMPLER2DARRAY ||
+ p_type == TK_TYPE_USAMPLER2DARRAY ||
+ p_type == TK_TYPE_SAMPLER3D ||
+ p_type == TK_TYPE_ISAMPLER3D ||
+ p_type == TK_TYPE_USAMPLER3D ||
p_type == TK_TYPE_SAMPLERCUBE);
}
@@ -731,6 +794,12 @@ String ShaderLanguage::get_datatype_name(DataType p_type) {
case TYPE_SAMPLER2D: return "sampler2D";
case TYPE_ISAMPLER2D: return "isampler2D";
case TYPE_USAMPLER2D: return "usampler2D";
+ case TYPE_SAMPLER2DARRAY: return "sampler2DArray";
+ case TYPE_ISAMPLER2DARRAY: return "isampler2DArray";
+ case TYPE_USAMPLER2DARRAY: return "usampler2DArray";
+ case TYPE_SAMPLER3D: return "sampler3D";
+ case TYPE_ISAMPLER3D: return "isampler3D";
+ case TYPE_USAMPLER3D: return "usampler3D";
case TYPE_SAMPLERCUBE: return "samplerCube";
}
@@ -1802,6 +1871,12 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "textureSize", TYPE_IVEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID } },
{ "textureSize", TYPE_IVEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID } },
{ "textureSize", TYPE_IVEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER2DARRAY, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER2DARRAY, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER2DARRAY, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER3D, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER3D, TYPE_INT, TYPE_VOID } },
+ { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER3D, TYPE_INT, TYPE_VOID } },
{ "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID } },
{ "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID } },
@@ -1813,6 +1888,24 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID } },
{ "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VOID } },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+
{ "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID } },
{ "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
@@ -1831,15 +1924,38 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
{ "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_VOID } },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } },
+
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_VOID } },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } },
+
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VOID } },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } },
+
{ "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
{ "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
{ "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
+ { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
{ "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
{ "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } },
{ "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } },
{ "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } },
+ { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+ { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+ { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+
+ { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+ { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+ { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } },
+
{ "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } },
{ "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } },
@@ -1852,6 +1968,12 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
{ "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
{ "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
+ { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
+ { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } },
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } },
+ { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } },
+ { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } },
{ "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } },
{ "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID } },
@@ -2139,7 +2261,16 @@ bool ShaderLanguage::is_scalar_type(DataType p_type) {
bool ShaderLanguage::is_sampler_type(DataType p_type) {
- return p_type == TYPE_SAMPLER2D || p_type == TYPE_ISAMPLER2D || p_type == TYPE_USAMPLER2D || p_type == TYPE_SAMPLERCUBE;
+ return p_type == TYPE_SAMPLER2D ||
+ p_type == TYPE_ISAMPLER2D ||
+ p_type == TYPE_USAMPLER2D ||
+ p_type == TYPE_SAMPLER2DARRAY ||
+ p_type == TYPE_ISAMPLER2DARRAY ||
+ p_type == TYPE_USAMPLER2DARRAY ||
+ p_type == TYPE_SAMPLER3D ||
+ p_type == TYPE_ISAMPLER3D ||
+ p_type == TYPE_USAMPLER3D ||
+ p_type == TYPE_SAMPLERCUBE;
}
void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h
index b5fd567c07..d68f233b2f 100644
--- a/servers/visual/shader_language.h
+++ b/servers/visual/shader_language.h
@@ -72,6 +72,12 @@ public:
TK_TYPE_SAMPLER2D,
TK_TYPE_ISAMPLER2D,
TK_TYPE_USAMPLER2D,
+ TK_TYPE_SAMPLER2DARRAY,
+ TK_TYPE_ISAMPLER2DARRAY,
+ TK_TYPE_USAMPLER2DARRAY,
+ TK_TYPE_SAMPLER3D,
+ TK_TYPE_ISAMPLER3D,
+ TK_TYPE_USAMPLER3D,
TK_TYPE_SAMPLERCUBE,
TK_INTERPOLATION_FLAT,
TK_INTERPOLATION_NO_PERSPECTIVE,
@@ -186,6 +192,12 @@ public:
TYPE_SAMPLER2D,
TYPE_ISAMPLER2D,
TYPE_USAMPLER2D,
+ TYPE_SAMPLER2DARRAY,
+ TYPE_ISAMPLER2DARRAY,
+ TYPE_USAMPLER2DARRAY,
+ TYPE_SAMPLER3D,
+ TYPE_ISAMPLER3D,
+ TYPE_USAMPLER3D,
TYPE_SAMPLERCUBE,
};
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index d58be21858..a00b364565 100644
--- a/servers/visual/visual_server_raster.h
+++ b/servers/visual/visual_server_raster.h
@@ -148,17 +148,19 @@ public:
/* TEXTURE API */
BIND0R(RID, texture_create)
- BIND5(texture_allocate, RID, int, int, Image::Format, uint32_t)
- BIND3(texture_set_data, RID, const Ref<Image> &, CubeMapSide)
- BIND10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, CubeMapSide)
- BIND2RC(Ref<Image>, texture_get_data, RID, CubeMapSide)
+ BIND7(texture_allocate, RID, int, int, int, Image::Format, TextureType, uint32_t)
+ BIND3(texture_set_data, RID, const Ref<Image> &, int)
+ BIND10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, int)
+ BIND2RC(Ref<Image>, texture_get_data, RID, int)
BIND2(texture_set_flags, RID, uint32_t)
BIND1RC(uint32_t, texture_get_flags, RID)
BIND1RC(Image::Format, texture_get_format, RID)
+ BIND1RC(TextureType, texture_get_type, RID)
BIND1RC(uint32_t, texture_get_texid, RID)
BIND1RC(uint32_t, texture_get_width, RID)
BIND1RC(uint32_t, texture_get_height, RID)
- BIND3(texture_set_size_override, RID, int, int)
+ BIND1RC(uint32_t, texture_get_depth, RID)
+ BIND4(texture_set_size_override, RID, int, int, int)
BIND3(texture_set_detect_3d_callback, RID, TextureDetectCallback, void *)
BIND3(texture_set_detect_srgb_callback, RID, TextureDetectCallback, void *)
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index c6af960d9f..3a4d72c793 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/servers/visual/visual_server_wrap_mt.h
@@ -82,17 +82,19 @@ public:
/* EVENT QUEUING */
FUNCRID(texture)
- FUNC5(texture_allocate, RID, int, int, Image::Format, uint32_t)
- FUNC3(texture_set_data, RID, const Ref<Image> &, CubeMapSide)
- FUNC10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, CubeMapSide)
- FUNC2RC(Ref<Image>, texture_get_data, RID, CubeMapSide)
+ FUNC7(texture_allocate, RID, int, int, int, Image::Format, TextureType, uint32_t)
+ FUNC3(texture_set_data, RID, const Ref<Image> &, int)
+ FUNC10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, int)
+ FUNC2RC(Ref<Image>, texture_get_data, RID, int)
FUNC2(texture_set_flags, RID, uint32_t)
FUNC1RC(uint32_t, texture_get_flags, RID)
FUNC1RC(Image::Format, texture_get_format, RID)
+ FUNC1RC(TextureType, texture_get_type, RID)
FUNC1RC(uint32_t, texture_get_texid, RID)
FUNC1RC(uint32_t, texture_get_width, RID)
FUNC1RC(uint32_t, texture_get_height, RID)
- FUNC3(texture_set_size_override, RID, int, int)
+ FUNC1RC(uint32_t, texture_get_depth, RID)
+ FUNC4(texture_set_size_override, RID, int, int, int)
FUNC3(texture_set_detect_3d_callback, RID, TextureDetectCallback, void *)
FUNC3(texture_set_detect_srgb_callback, RID, TextureDetectCallback, void *)
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index 2e5b27510a..bc9e9042ec 100644
--- a/servers/visual_server.cpp
+++ b/servers/visual_server.cpp
@@ -55,7 +55,7 @@ RID VisualServer::texture_create_from_image(const Ref<Image> &p_image, uint32_t
ERR_FAIL_COND_V(!p_image.is_valid(), RID());
RID texture = texture_create();
- texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), p_flags); //if it has mipmaps, use, else generate
+ texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_flags); //if it has mipmaps, use, else generate
ERR_FAIL_COND_V(!texture.is_valid(), texture);
texture_set_data(texture, p_image);
@@ -72,7 +72,9 @@ Array VisualServer::_texture_debug_usage_bind() {
Dictionary dict;
dict["texture"] = E->get().texture;
- dict["size"] = E->get().size;
+ dict["width"] = E->get().width;
+ dict["height"] = E->get().height;
+ dict["depth"] = E->get().depth;
dict["format"] = E->get().format;
dict["bytes"] = E->get().bytes;
dict["path"] = E->get().path;
@@ -333,7 +335,7 @@ RID VisualServer::get_white_texture() {
}
Ref<Image> white = memnew(Image(4, 4, 0, Image::FORMAT_RGB8, wt));
white_texture = texture_create();
- texture_allocate(white_texture, 4, 4, Image::FORMAT_RGB8);
+ texture_allocate(white_texture, 4, 4, 0, Image::FORMAT_RGB8, TEXTURE_TYPE_2D);
texture_set_data(white_texture, white);
return white_texture;
}
@@ -1658,17 +1660,19 @@ void VisualServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_create"), &VisualServer::texture_create);
ClassDB::bind_method(D_METHOD("texture_create_from_image", "image", "flags"), &VisualServer::texture_create_from_image, DEFVAL(TEXTURE_FLAGS_DEFAULT));
- ClassDB::bind_method(D_METHOD("texture_allocate", "texture", "width", "height", "format", "flags"), &VisualServer::texture_allocate, DEFVAL(TEXTURE_FLAGS_DEFAULT));
- ClassDB::bind_method(D_METHOD("texture_set_data", "texture", "image", "cube_side"), &VisualServer::texture_set_data, DEFVAL(CUBEMAP_LEFT));
- ClassDB::bind_method(D_METHOD("texture_set_data_partial", "texture", "image", "src_x", "src_y", "src_w", "src_h", "dst_x", "dst_y", "dst_mip", "cube_side"), &VisualServer::texture_set_data_partial, DEFVAL(CUBEMAP_LEFT));
+ ClassDB::bind_method(D_METHOD("texture_allocate", "texture", "width", "height", "depth_3d", "format", "type", "flags"), &VisualServer::texture_allocate, DEFVAL(TEXTURE_FLAGS_DEFAULT));
+ ClassDB::bind_method(D_METHOD("texture_set_data", "texture", "image", "layer"), &VisualServer::texture_set_data, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("texture_set_data_partial", "texture", "image", "src_x", "src_y", "src_w", "src_h", "dst_x", "dst_y", "dst_mip", "layer"), &VisualServer::texture_set_data_partial, DEFVAL(0));
ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "cube_side"), &VisualServer::texture_get_data, DEFVAL(CUBEMAP_LEFT));
ClassDB::bind_method(D_METHOD("texture_set_flags", "texture", "flags"), &VisualServer::texture_set_flags);
ClassDB::bind_method(D_METHOD("texture_get_flags", "texture"), &VisualServer::texture_get_flags);
ClassDB::bind_method(D_METHOD("texture_get_format", "texture"), &VisualServer::texture_get_format);
+ ClassDB::bind_method(D_METHOD("texture_get_type", "texture"), &VisualServer::texture_get_type);
ClassDB::bind_method(D_METHOD("texture_get_texid", "texture"), &VisualServer::texture_get_texid);
ClassDB::bind_method(D_METHOD("texture_get_width", "texture"), &VisualServer::texture_get_width);
ClassDB::bind_method(D_METHOD("texture_get_height", "texture"), &VisualServer::texture_get_height);
- ClassDB::bind_method(D_METHOD("texture_set_size_override", "texture", "width", "height"), &VisualServer::texture_set_size_override);
+ ClassDB::bind_method(D_METHOD("texture_get_depth", "texture"), &VisualServer::texture_get_depth);
+ ClassDB::bind_method(D_METHOD("texture_set_size_override", "texture", "width", "height", "depth"), &VisualServer::texture_set_size_override);
ClassDB::bind_method(D_METHOD("texture_set_path", "texture", "path"), &VisualServer::texture_set_path);
ClassDB::bind_method(D_METHOD("texture_get_path", "texture"), &VisualServer::texture_get_path);
ClassDB::bind_method(D_METHOD("texture_set_shrink_all_x2_on_set_data", "shrink"), &VisualServer::texture_set_shrink_all_x2_on_set_data);
@@ -2059,13 +2063,17 @@ void VisualServer::_bind_methods() {
BIND_ENUM_CONSTANT(CUBEMAP_FRONT);
BIND_ENUM_CONSTANT(CUBEMAP_BACK);
+ BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D);
+ BIND_ENUM_CONSTANT(TEXTURE_TYPE_CUBEMAP);
+ BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D_ARRAY);
+ BIND_ENUM_CONSTANT(TEXTURE_TYPE_3D);
+
BIND_ENUM_CONSTANT(TEXTURE_FLAG_MIPMAPS);
BIND_ENUM_CONSTANT(TEXTURE_FLAG_REPEAT);
BIND_ENUM_CONSTANT(TEXTURE_FLAG_FILTER);
BIND_ENUM_CONSTANT(TEXTURE_FLAG_ANISOTROPIC_FILTER);
BIND_ENUM_CONSTANT(TEXTURE_FLAG_CONVERT_TO_LINEAR);
BIND_ENUM_CONSTANT(TEXTURE_FLAG_MIRRORED_REPEAT);
- BIND_ENUM_CONSTANT(TEXTURE_FLAG_CUBEMAP);
BIND_ENUM_CONSTANT(TEXTURE_FLAG_USED_FOR_STREAMING);
BIND_ENUM_CONSTANT(TEXTURE_FLAGS_DEFAULT);
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 6847f6d2ae..0ec902c18c 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -90,11 +90,17 @@ public:
TEXTURE_FLAG_ANISOTROPIC_FILTER = 8,
TEXTURE_FLAG_CONVERT_TO_LINEAR = 16,
TEXTURE_FLAG_MIRRORED_REPEAT = 32, /// Repeat texture, with alternate sections mirrored
- TEXTURE_FLAG_CUBEMAP = 2048,
- TEXTURE_FLAG_USED_FOR_STREAMING = 4096,
+ TEXTURE_FLAG_USED_FOR_STREAMING = 2048,
TEXTURE_FLAGS_DEFAULT = TEXTURE_FLAG_REPEAT | TEXTURE_FLAG_MIPMAPS | TEXTURE_FLAG_FILTER
};
+ enum TextureType {
+ TEXTURE_TYPE_2D,
+ TEXTURE_TYPE_CUBEMAP,
+ TEXTURE_TYPE_2D_ARRAY,
+ TEXTURE_TYPE_3D,
+ };
+
enum CubeMapSide {
CUBEMAP_LEFT,
@@ -107,17 +113,33 @@ public:
virtual RID texture_create() = 0;
RID texture_create_from_image(const Ref<Image> &p_image, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT); // helper
- virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT) = 0;
- virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, CubeMapSide p_cube_side = CUBEMAP_LEFT) = 0;
- virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, CubeMapSide p_cube_side = CUBEMAP_LEFT) = 0;
- virtual Ref<Image> texture_get_data(RID p_texture, CubeMapSide p_cube_side = CUBEMAP_LEFT) const = 0;
+ virtual void texture_allocate(RID p_texture,
+ int p_width,
+ int p_height,
+ int p_depth_3d,
+ Image::Format p_format,
+ TextureType p_type,
+ uint32_t p_flags = TEXTURE_FLAGS_DEFAULT) = 0;
+
+ virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0;
+ virtual void texture_set_data_partial(RID p_texture,
+ const Ref<Image> &p_image,
+ int src_x, int src_y,
+ int src_w, int src_h,
+ int dst_x, int dst_y,
+ int p_dst_mip,
+ int p_layer = 0) = 0;
+
+ virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const = 0;
virtual void texture_set_flags(RID p_texture, uint32_t p_flags) = 0;
virtual uint32_t texture_get_flags(RID p_texture) const = 0;
virtual Image::Format texture_get_format(RID p_texture) const = 0;
+ virtual TextureType texture_get_type(RID p_texture) const = 0;
virtual uint32_t texture_get_texid(RID p_texture) const = 0;
virtual uint32_t texture_get_width(RID p_texture) const = 0;
virtual uint32_t texture_get_height(RID p_texture) const = 0;
- virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0;
+ virtual uint32_t texture_get_depth(RID p_texture) const = 0;
+ virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) = 0;
virtual void texture_set_path(RID p_texture, const String &p_path) = 0;
virtual String texture_get_path(RID p_texture) const = 0;
@@ -132,7 +154,9 @@ public:
struct TextureInfo {
RID texture;
- Size2 size;
+ uint32_t width;
+ uint32_t height;
+ uint32_t depth;
Image::Format format;
int bytes;
String path;
@@ -1054,6 +1078,7 @@ VARIANT_ENUM_CAST(VisualServer::EnvironmentSSAOQuality);
VARIANT_ENUM_CAST(VisualServer::EnvironmentSSAOBlur);
VARIANT_ENUM_CAST(VisualServer::InstanceFlags);
VARIANT_ENUM_CAST(VisualServer::ShadowCastingSetting);
+VARIANT_ENUM_CAST(VisualServer::TextureType);
//typedef VisualServer VS; // makes it easier to use
#define VS VisualServer