summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/color.h10
-rw-r--r--core/os/memory.cpp40
-rw-r--r--core/os/memory.h12
-rw-r--r--doc/base/classes.xml33
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp1
-rw-r--r--editor/editor_node.cpp5
-rw-r--r--editor/editor_themes.cpp11
-rw-r--r--editor/icons/2x/icon_GUI_dropdown.pngbin183 -> 198 bytes
-rw-r--r--editor/icons/icon_GUI_dropdown.pngbin130 -> 136 bytes
-rw-r--r--editor/icons/source/icon_GUI_dropdown.svg22
-rw-r--r--editor/icons/source/icon_connect.svg46
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp1581
-rw-r--r--editor/import/editor_scene_importer_gltf.h258
-rw-r--r--editor/plugins/script_text_editor.cpp12
-rw-r--r--editor/project_settings_editor.cpp18
-rw-r--r--editor/script_create_dialog.cpp31
-rw-r--r--main/main.cpp1
-rw-r--r--main/performance.cpp4
-rw-r--r--methods.py1
-rw-r--r--modules/gdnative/SCsub3
-rw-r--r--modules/gdnative/gdnative.h2
-rw-r--r--modules/gdnative/godot/array.cpp2
-rw-r--r--modules/gdnative/godot/array.h6
-rw-r--r--modules/gdnative/godot/basis.cpp4
-rw-r--r--modules/gdnative/godot/basis.h6
-rw-r--r--modules/gdnative/godot/color.cpp4
-rw-r--r--modules/gdnative/godot/color.h4
-rw-r--r--modules/gdnative/godot/dictionary.cpp4
-rw-r--r--modules/gdnative/godot/dictionary.h6
-rw-r--r--modules/gdnative/godot/gdnative.cpp2
-rw-r--r--modules/gdnative/godot/gdnative.h34
-rw-r--r--modules/gdnative/godot/node_path.cpp4
-rw-r--r--modules/gdnative/godot/node_path.h4
-rw-r--r--modules/gdnative/godot/plane.cpp4
-rw-r--r--modules/gdnative/godot/plane.h4
-rw-r--r--modules/gdnative/godot/pool_arrays.cpp2
-rw-r--r--modules/gdnative/godot/pool_arrays.h10
-rw-r--r--modules/gdnative/godot/quat.cpp4
-rw-r--r--modules/gdnative/godot/quat.h4
-rw-r--r--modules/gdnative/godot/rect2.cpp4
-rw-r--r--modules/gdnative/godot/rect2.h4
-rw-r--r--modules/gdnative/godot/rect3.cpp4
-rw-r--r--modules/gdnative/godot/rect3.h6
-rw-r--r--modules/gdnative/godot/rid.cpp4
-rw-r--r--modules/gdnative/godot/rid.h2
-rw-r--r--modules/gdnative/godot/string.cpp2
-rw-r--r--modules/gdnative/godot/string.h2
-rw-r--r--modules/gdnative/godot/transform.cpp4
-rw-r--r--modules/gdnative/godot/transform.h8
-rw-r--r--modules/gdnative/godot/transform2d.cpp4
-rw-r--r--modules/gdnative/godot/transform2d.h6
-rw-r--r--modules/gdnative/godot/variant.cpp3
-rw-r--r--modules/gdnative/godot/variant.h38
-rw-r--r--modules/gdnative/godot/vector2.cpp4
-rw-r--r--modules/gdnative/godot/vector2.h2
-rw-r--r--modules/gdnative/godot/vector3.cpp4
-rw-r--r--modules/gdnative/godot/vector3.h4
-rw-r--r--modules/gdnative/register_types.cpp22
-rw-r--r--modules/nativescript/nativescript.cpp5
-rw-r--r--platform/android/SCsub2
-rw-r--r--platform/android/detect.py28
-rw-r--r--platform/android/export/export.cpp15
-rw-r--r--platform/android/java_class_wrapper.cpp12
-rw-r--r--scene/2d/tile_map.cpp15
-rw-r--r--scene/2d/tile_map.h1
-rw-r--r--scene/3d/arvr_nodes.cpp113
-rw-r--r--scene/3d/arvr_nodes.h37
-rw-r--r--scene/gui/item_list.cpp8
-rw-r--r--scene/gui/menu_button.cpp2
-rw-r--r--scene/gui/text_edit.cpp121
-rw-r--r--scene/gui/tree.cpp1
-rw-r--r--scene/register_scene_types.cpp1
-rw-r--r--scene/resources/material.cpp109
-rw-r--r--scene/resources/material.h31
-rw-r--r--scene/resources/surface_tool.cpp75
-rw-r--r--scene/resources/surface_tool.h3
-rw-r--r--servers/arvr/arvr_positional_tracker.cpp33
-rw-r--r--servers/arvr/arvr_positional_tracker.h8
-rw-r--r--servers/audio_server.cpp3
-rw-r--r--servers/physics/area_sw.h1
-rw-r--r--servers/physics/body_sw.cpp3
-rw-r--r--servers/physics/body_sw.h1
-rw-r--r--servers/physics/physics_server_sw.cpp30
-rw-r--r--servers/physics/space_sw.cpp6
-rw-r--r--servers/physics_2d/area_2d_sw.h1
-rw-r--r--servers/physics_2d/body_2d_sw.h1
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.cpp6
-rw-r--r--servers/physics_2d/physics_2d_server_sw.cpp31
-rw-r--r--thirdparty/misc/base64.h5
89 files changed, 2685 insertions, 349 deletions
diff --git a/core/color.h b/core/color.h
index c83dcda4b4..9074a0e6d6 100644
--- a/core/color.h
+++ b/core/color.h
@@ -140,8 +140,16 @@ struct Color {
b < 0.04045 ? b * (1.0 / 12.92) : Math::pow((b + 0.055) * (1.0 / (1 + 0.055)), 2.4),
a);
}
+ _FORCE_INLINE_ Color to_srgb() const {
- static Color hex(uint32_t p_hex);
+ return Color(
+ r < 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math::pow(r, 1.0f / 2.4f) - 0.055,
+ g < 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math::pow(g, 1.0f / 2.4f) - 0.055,
+ b < 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math::pow(b, 1.0f / 2.4f) - 0.055, a);
+ }
+
+ static Color
+ hex(uint32_t p_hex);
static Color html(const String &p_color);
static bool html_is_valid(const String &p_color);
static Color named(const String &p_name);
diff --git a/core/os/memory.cpp b/core/os/memory.cpp
index 069ee48fae..acc960acd9 100644
--- a/core/os/memory.cpp
+++ b/core/os/memory.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "memory.h"
#include "copymem.h"
+#include "core/safe_refcount.h"
#include "error_macros.h"
#include <stdio.h>
#include <stdlib.h>
@@ -43,14 +44,12 @@ void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)) {
return p_allocfunc(p_size);
}
-#include <stdio.h>
-
#ifdef DEBUG_ENABLED
-size_t Memory::mem_usage = 0;
-size_t Memory::max_usage = 0;
+uint64_t Memory::mem_usage = 0;
+uint64_t Memory::max_usage = 0;
#endif
-size_t Memory::alloc_count = 0;
+uint64_t Memory::alloc_count = 0;
void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
@@ -62,10 +61,10 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
void *mem = malloc(p_bytes + (prepad ? PAD_ALIGN : 0));
- alloc_count++;
-
ERR_FAIL_COND_V(!mem, NULL);
+ atomic_increment(&alloc_count);
+
if (prepad) {
uint64_t *s = (uint64_t *)mem;
*s = p_bytes;
@@ -73,10 +72,8 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
uint8_t *s8 = (uint8_t *)mem;
#ifdef DEBUG_ENABLED
- mem_usage += p_bytes;
- if (mem_usage > max_usage) {
- max_usage = mem_usage;
- }
+ atomic_add(&mem_usage, p_bytes);
+ atomic_exchange_if_greater(&max_usage, mem_usage);
#endif
return s8 + PAD_ALIGN;
} else {
@@ -103,8 +100,12 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
uint64_t *s = (uint64_t *)mem;
#ifdef DEBUG_ENABLED
- mem_usage -= *s;
- mem_usage += p_bytes;
+ if (p_bytes > *s) {
+ atomic_add(&mem_usage, p_bytes - *s);
+ atomic_exchange_if_greater(&max_usage, mem_usage);
+ } else {
+ atomic_sub(&mem_usage, *s - p_bytes);
+ }
#endif
if (p_bytes == 0) {
@@ -144,14 +145,14 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) {
bool prepad = p_pad_align;
#endif
- alloc_count--;
+ atomic_decrement(&alloc_count);
if (prepad) {
mem -= PAD_ALIGN;
uint64_t *s = (uint64_t *)mem;
#ifdef DEBUG_ENABLED
- mem_usage -= *s;
+ atomic_sub(&mem_usage, *s);
#endif
free(mem);
@@ -161,19 +162,20 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) {
}
}
-size_t Memory::get_mem_available() {
+uint64_t Memory::get_mem_available() {
- return 0xFFFFFFFFFFFFF;
+ return -1; // 0xFFFF...
}
-size_t Memory::get_mem_usage() {
+uint64_t Memory::get_mem_usage() {
#ifdef DEBUG_ENABLED
return mem_usage;
#else
return 0;
#endif
}
-size_t Memory::get_mem_max_usage() {
+
+uint64_t Memory::get_mem_max_usage() {
#ifdef DEBUG_ENABLED
return max_usage;
#else
diff --git a/core/os/memory.h b/core/os/memory.h
index b3eb599955..e1d7138ad5 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -45,20 +45,20 @@ class Memory {
Memory();
#ifdef DEBUG_ENABLED
- static size_t mem_usage;
- static size_t max_usage;
+ static uint64_t mem_usage;
+ static uint64_t max_usage;
#endif
- static size_t alloc_count;
+ static uint64_t alloc_count;
public:
static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false);
static void free_static(void *p_ptr, bool p_pad_align = false);
- static size_t get_mem_available();
- static size_t get_mem_usage();
- static size_t get_mem_max_usage();
+ static uint64_t get_mem_available();
+ static uint64_t get_mem_usage();
+ static uint64_t get_mem_max_usage();
};
class DefaultAllocator {
diff --git a/doc/base/classes.xml b/doc/base/classes.xml
index 70a7dcb651..268bfeca1a 100644
--- a/doc/base/classes.xml
+++ b/doc/base/classes.xml
@@ -746,13 +746,16 @@
[AudioServer] singleton
</member>
<member name="ClassDB" type="ClassDB" setter="" getter="" brief="">
+ [ClassDB] singleton
</member>
<member name="Engine" type="Engine" setter="" getter="" brief="">
+ [Engine] singleton
</member>
<member name="Geometry" type="Geometry" setter="" getter="" brief="">
[Geometry] singleton
</member>
<member name="ProjectSettings" type="ProjectSettings" setter="" getter="" brief="">
+ [ProjectSettings] singleton
</member>
<member name="IP" type="IP" setter="" getter="" brief="">
[IP] singleton
@@ -4632,7 +4635,7 @@
<argument index="0" name="from" type="PoolColorArray">
</argument>
<description>
- Construct an array from a [PoolByteArray].
+ Construct an array from a [PoolColorArray].
</description>
</method>
<method name="Array">
@@ -4641,7 +4644,7 @@
<argument index="0" name="from" type="PoolVector3Array">
</argument>
<description>
- Construct an array from a [PoolByteArray].
+ Construct an array from a [PoolVector3Array].
</description>
</method>
<method name="Array">
@@ -4650,7 +4653,7 @@
<argument index="0" name="from" type="PoolVector2Array">
</argument>
<description>
- Construct an array from a [PoolByteArray].
+ Construct an array from a [PoolVector2Array].
</description>
</method>
<method name="Array">
@@ -4677,7 +4680,7 @@
<argument index="0" name="from" type="PoolIntArray">
</argument>
<description>
- Construct an array from a [PoolByteArray].
+ Construct an array from a [PoolIntArray].
</description>
</method>
<method name="Array">
@@ -11516,7 +11519,7 @@
<return type="Rect2">
</return>
<description>
- Return position and size of the Control, relative to the top-left corner of the [i]window[/i] Control. This is a helper (see [method get_global_pos], [method get_size]).
+ Return position and size of the Control, relative to the top-left corner of the [i]window[/i] Control. This is a helper (see [method get_global_position], [method get_size]).
</description>
</method>
<method name="get_h_grow_direction" qualifiers="const">
@@ -11594,7 +11597,7 @@
<return type="Rect2">
</return>
<description>
- Return position and size of the Control, relative to the top-left corner of the parent Control. This is a helper (see [method get_pos], [method get_size]).
+ Return position and size of the Control, relative to the top-left corner of the parent Control. This is a helper (see [method get_position], [method get_size]).
</description>
</method>
<method name="get_rotation" qualifiers="const">
@@ -17915,7 +17918,7 @@
Contains global variables accessible from everywhere.
</brief_description>
<description>
- Contains global variables accessible from everywhere. Use the normal [Object] API, such as "Globals.get(variable)", "Globals.set(variable,value)" or "Globals.has(variable)" to access them. Variables stored in project.godot are also loaded into globals, making this object very useful for reading custom game configuration options.
+ Contains global variables accessible from everywhere. Use the normal [Object] API, such as "ProjectSettings.get(variable)", "ProjectSettings.set(variable,value)" or "ProjectSettings.has(variable)" to access them. Variables stored in project.godot are also loaded into ProjectSettings, making this object very useful for reading custom game configuration options.
</description>
<methods>
<method name="add_property_info">
@@ -17925,7 +17928,7 @@
Add a custom property info to a property. The dictionary must contain: name:[String](the name of the property) and type:[int](see TYPE_* in [@Global Scope]), and optionally hint:[int](see PROPERTY_HINT_* in [@Global Scope]), hint_string:[String].
Example:
[codeblock]
- Globals.set("category/property_name", 0)
+ ProjectSettings.set("category/property_name", 0)
var property_info = {
"name": "category/property_name",
@@ -17934,7 +17937,7 @@
"hint_string": "one,two,three"
}
- Globals.add_property_info(property_info)
+ ProjectSettings.add_property_info(property_info)
[/codeblock]
</description>
</method>
@@ -21642,7 +21645,7 @@
</method>
<method name="load_from_globals">
<description>
- Clear the [InputMap] and load it anew from [Globals].
+ Clear the [InputMap] and load it anew from [ProjectSettings].
</description>
</method>
</methods>
@@ -25089,7 +25092,7 @@
MultiMesh provides low level mesh instancing. If the amount of [Mesh] instances needed goes from hundreds to thousands (and most need to be visible at close proximity) creating such a large amount of [MeshInstance] nodes may affect performance by using too much CPU or video memory.
For this case a MultiMesh becomes very useful, as it can draw thousands of instances with little API overhead.
As a drawback, if the instances are too far away of each other, performance may be reduced as every single instance will always rendered (they are spatially indexed as one, for the whole object).
- Since instances may have any behavior, the Rect3 used for visibility must be provided by the user, or generated with [method generate_aabb].
+ Since instances may have any behavior, the Rect3 used for visibility must be provided by the user.
</description>
<methods>
<method name="get_aabb" qualifiers="const">
@@ -28019,7 +28022,7 @@
<return type="Array">
</return>
<description>
- Return the property list, array of dictionaries, dictionaries must contain: name:String, type:int (see TYPE_* enum in globals) and optionally: hint:int (see PROPERTY_HINT_* in globals), hint_string:String, usage:int (see PROPERTY_USAGE_* in globals).
+ Return the property list, array of dictionaries, dictionaries must contain: name:String, type:int (see TYPE_* enum in [@Global Scope]) and optionally: hint:int (see PROPERTY_HINT_* in [@Global Scope]), hint_string:String, usage:int (see PROPERTY_USAGE_* in [@Global Scope]).
</description>
</method>
<method name="_init" qualifiers="virtual">
@@ -28180,7 +28183,7 @@
<return type="Array">
</return>
<description>
- Return the list of properties as an array of dictionaries, dictionaries contain: name:String, type:int (see TYPE_* enum in globals) and optionally: hint:int (see PROPERTY_HINT_* in globals), hint_string:String, usage:int (see PROPERTY_USAGE_* in globals).
+ Return the list of properties as an array of dictionaries, dictionaries contain: name:String, type:int (see TYPE_* enum in [@Global Scope]) and optionally: hint:int (see PROPERTY_HINT_* in [@Global Scope]), hint_string:String, usage:int (see PROPERTY_USAGE_* in [@Global Scope]).
</description>
</method>
<method name="get_script" qualifiers="const">
@@ -34623,7 +34626,7 @@
<argument index="1" name="to" type="int">
</argument>
<description>
- Returns the slice of the [PoolByteArray] between indices (inclusive) as a new [RawArray]. Any negative index is considered to be from the end of the array.
+ Returns the slice of the [PoolByteArray] between indices (inclusive) as a new [PoolByteArray]. Any negative index is considered to be from the end of the array.
</description>
</method>
</methods>
@@ -37280,7 +37283,7 @@
<argument index="0" name="with" type="Rect3">
</argument>
<description>
- Return the intersection between two [Rect3]. An empty AABB (size 0,0,0) is returned on failure.
+ Return the intersection between two [Rect3]. An empty Rect3 (size 0,0,0) is returned on failure.
</description>
</method>
<method name="intersects">
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index bb7b85e653..3fc5bed80b 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -83,7 +83,6 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL
if (type == _EXT_DEBUG_TYPE_OTHER_ARB)
return;
- print_line("mesege");
char debSource[256], debType[256], debSev[256];
if (source == _EXT_DEBUG_SOURCE_API_ARB)
strcpy(debSource, "OpenGL");
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 0cdb981306..4d5dd14172 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -110,6 +110,7 @@
// end
#include "editor_settings.h"
#include "import/editor_import_collada.h"
+#include "import/editor_scene_importer_gltf.h"
#include "io_plugins/editor_bitmask_import_plugin.h"
#include "io_plugins/editor_export_scene.h"
#include "io_plugins/editor_font_import_plugin.h"
@@ -5151,6 +5152,10 @@ EditorNode::EditorNode() {
Ref<EditorOBJImporter> import_obj;
import_obj.instance();
import_scene->add_importer(import_obj);
+
+ Ref<EditorSceneImporterGLTF> import_gltf;
+ import_gltf.instance();
+ import_scene->add_importer(import_gltf);
}
}
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 6b985c7b4b..df16de947e 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -163,6 +163,13 @@ Ref<Theme> create_editor_theme() {
theme->set_color("light_color_1", "Editor", light_color_1);
theme->set_color("light_color_2", "Editor", light_color_2);
+ Color success_color = highlight_color.linear_interpolate(Color(0, 1, .8), 0.8);
+ Color warning_color = highlight_color.linear_interpolate(Color(1, 1, .2), 0.8);
+ Color error_color = highlight_color.linear_interpolate(Color(1, .2, .2), 0.8);
+ theme->set_color("success_color", "Editor", success_color);
+ theme->set_color("warning_color", "Editor", warning_color);
+ theme->set_color("error_color", "Editor", error_color);
+
// Checkbox icon
theme->set_icon("checked", "CheckBox", theme->get_icon("GuiChecked", "EditorIcons"));
theme->set_icon("unchecked", "CheckBox", theme->get_icon("GuiUnchecked", "EditorIcons"));
@@ -307,8 +314,8 @@ Ref<Theme> create_editor_theme() {
theme->set_icon("arrow_collapsed", "Tree", theme->get_icon("GuiTreeArrowRight", "EditorIcons"));
theme->set_icon("select_arrow", "Tree", theme->get_icon("GuiDropdown", "EditorIcons"));
theme->set_stylebox("bg_focus", "Tree", focus_sbt);
- theme->set_stylebox("custom_button", "Tree", style_button_type);
- theme->set_stylebox("custom_button_pressed", "Tree", style_button_type);
+ theme->set_stylebox("custom_button", "Tree", make_empty_stylebox());
+ theme->set_stylebox("custom_button_pressed", "Tree", make_empty_stylebox());
theme->set_stylebox("custom_button_hover", "Tree", style_button_type);
theme->set_color("custom_button_font_highlight", "Tree", HIGHLIGHT_COLOR_LIGHT);
diff --git a/editor/icons/2x/icon_GUI_dropdown.png b/editor/icons/2x/icon_GUI_dropdown.png
index c959378430..78d3352e4e 100644
--- a/editor/icons/2x/icon_GUI_dropdown.png
+++ b/editor/icons/2x/icon_GUI_dropdown.png
Binary files differ
diff --git a/editor/icons/icon_GUI_dropdown.png b/editor/icons/icon_GUI_dropdown.png
index 4bd6544830..d21cdb634e 100644
--- a/editor/icons/icon_GUI_dropdown.png
+++ b/editor/icons/icon_GUI_dropdown.png
Binary files differ
diff --git a/editor/icons/source/icon_GUI_dropdown.svg b/editor/icons/source/icon_GUI_dropdown.svg
index f313b09983..897f63c268 100644
--- a/editor/icons/source/icon_GUI_dropdown.svg
+++ b/editor/icons/source/icon_GUI_dropdown.svg
@@ -9,9 +9,9 @@
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="8"
+ width="14"
height="14"
- viewBox="0 0 8 14"
+ viewBox="0 0 14 14"
id="svg2"
version="1.1"
inkscape:version="0.92+devel unknown"
@@ -28,9 +28,9 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="45.254834"
- inkscape:cx="1.2944669"
- inkscape:cy="5.9830116"
+ inkscape:zoom="32"
+ inkscape:cx="6.5843041"
+ inkscape:cy="6.8000184"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
@@ -72,21 +72,21 @@
id="layer1"
transform="translate(0,-1038.3622)">
<circle
- style="fill:#ffffff;fill-opacity:0.58823532;stroke-width:2;stroke-linejoin:round;stroke-opacity:0.39215686"
+ style="fill:#ffffff;fill-opacity:0.58823529;stroke-width:2;stroke-linejoin:round;stroke-opacity:0.39215686"
id="path4268"
- cx="4.5"
+ cx="7.5"
cy="1040.8622"
r="1.5" />
<circle
r="1.5"
cy="1045.8622"
- cx="4.5"
+ cx="7.5"
id="circle4271"
- style="fill:#ffffff;fill-opacity:0.58823532;stroke-width:2;stroke-linejoin:round;stroke-opacity:0.39215686" />
+ style="fill:#ffffff;fill-opacity:0.58823529;stroke-width:2;stroke-linejoin:round;stroke-opacity:0.39215686" />
<circle
- style="fill:#ffffff;fill-opacity:0.58823532;stroke-width:2;stroke-linejoin:round;stroke-opacity:0.39215686"
+ style="fill:#ffffff;fill-opacity:0.58823529;stroke-width:2;stroke-linejoin:round;stroke-opacity:0.39215686"
id="circle4273"
- cx="4.5"
+ cx="7.5"
cy="1050.8622"
r="1.5" />
</g>
diff --git a/editor/icons/source/icon_connect.svg b/editor/icons/source/icon_connect.svg
index 745d3cc436..15c8b481a1 100644
--- a/editor/icons/source/icon_connect.svg
+++ b/editor/icons/source/icon_connect.svg
@@ -14,7 +14,7 @@
viewBox="0 0 16 16"
id="svg2"
version="1.1"
- inkscape:version="0.91 r13725"
+ inkscape:version="0.92+devel unknown"
inkscape:export-filename="/home/djrm/Projects/godot/tools/editor/icons/icon_add_track.png"
inkscape:export-xdpi="45"
inkscape:export-ydpi="45"
@@ -28,9 +28,9 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="22.627418"
- inkscape:cx="0.78663326"
- inkscape:cy="12.940707"
+ inkscape:zoom="32.000001"
+ inkscape:cx="13.864856"
+ inkscape:cy="7.2235346"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
@@ -46,7 +46,8 @@
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
- inkscape:window-maximized="1">
+ inkscape:window-maximized="1"
+ inkscape:document-rotation="0">
<inkscape:grid
type="xygrid"
id="grid3336" />
@@ -68,10 +69,37 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
+ <circle
+ style="fill:#e0e0e0;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round"
+ id="path4266"
+ cx="4"
+ cy="1048.3622"
+ r="2" />
<path
- style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="M 7 2 A 2 2 0 0 0 5 4 L 5 7 L 1 7 L 1 9 L 5 9 L 5 12 A 2 2 0 0 0 7 14 L 11 14 L 11 12 L 14 12 L 14 10 L 11 10 L 11 6 L 14 6 L 14 4 L 11 4 L 11 2 L 7 2 z "
- transform="translate(0,1036.3622)"
- id="rect4155" />
+ id="circle4268"
+ style="fill:none;stroke:#e0e0e0;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc"
+ sodipodi:cx="4"
+ sodipodi:cy="1048.3622"
+ sodipodi:rx="5"
+ sodipodi:ry="5"
+ sodipodi:start="4.712389"
+ sodipodi:end="0"
+ sodipodi:arc-type="arc"
+ d="M 4.0000001,1043.3622 A 5,5 0 0 1 9,1048.3622"
+ sodipodi:open="true" />
+ <path
+ id="circle4270"
+ style="fill:none;stroke:#e0e0e0;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:type="arc"
+ sodipodi:cx="4"
+ sodipodi:cy="1048.3622"
+ sodipodi:rx="9"
+ sodipodi:ry="9"
+ sodipodi:start="4.712389"
+ sodipodi:end="0"
+ sodipodi:open="true"
+ sodipodi:arc-type="arc"
+ d="m 4.0000002,1039.3622 a 9,9 0 0 1 8.9999998,9" />
</g>
</svg>
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
new file mode 100644
index 0000000000..35b31b56b4
--- /dev/null
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -0,0 +1,1581 @@
+#include "editor_scene_importer_gltf.h"
+#include "io/json.h"
+#include "os/file_access.h"
+#include "os/os.h"
+#include "scene/3d/camera.h"
+#include "scene/3d/mesh_instance.h"
+#include "scene/resources/surface_tool.h"
+#include "thirdparty/misc/base64.h"
+
+uint32_t EditorSceneImporterGLTF::get_import_flags() const {
+
+ return IMPORT_SCENE | IMPORT_ANIMATION;
+}
+void EditorSceneImporterGLTF::get_extensions(List<String> *r_extensions) const {
+
+ r_extensions->push_back("gltf");
+ r_extensions->push_back("gfb");
+}
+
+Error EditorSceneImporterGLTF::_parse_json(const String &p_path, GLTFState &state) {
+
+ Error err;
+ FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (!f) {
+ return err;
+ }
+
+ Vector<uint8_t> array;
+ array.resize(f->get_len());
+ f->get_buffer(array.ptr(), array.size());
+ String text;
+ text.parse_utf8((const char *)array.ptr(), array.size());
+
+ String err_txt;
+ int err_line;
+ Variant v;
+ err = JSON::parse(text, v, err_txt, err_line);
+ if (err != OK) {
+ _err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT);
+ return err;
+ }
+ state.json = v;
+
+ return OK;
+}
+
+static Vector3 _arr_to_vec3(const Array &p_array) {
+ ERR_FAIL_COND_V(p_array.size() != 3, Vector3());
+ return Vector3(p_array[0], p_array[1], p_array[2]);
+}
+
+static Quat _arr_to_quat(const Array &p_array) {
+ ERR_FAIL_COND_V(p_array.size() != 4, Quat());
+ return Quat(p_array[0], p_array[1], p_array[2], p_array[3]);
+}
+
+static Transform _arr_to_xform(const Array &p_array) {
+ ERR_FAIL_COND_V(p_array.size() != 16, Transform());
+
+ Transform xform;
+ xform.basis.set_axis(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2]));
+ xform.basis.set_axis(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6]));
+ xform.basis.set_axis(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10]));
+ xform.set_origin(Vector3(p_array[12], p_array[13], p_array[14]));
+
+ return xform;
+}
+
+String EditorSceneImporterGLTF::_gen_unique_name(GLTFState &state, const String &p_name) {
+
+ int index = 1;
+
+ String name;
+ while (true) {
+
+ name = p_name;
+ if (index > 1) {
+ name += " " + itos(index);
+ }
+ if (!state.unique_names.has(name)) {
+ break;
+ }
+ index++;
+ }
+
+ state.unique_names.insert(name);
+
+ return name;
+}
+
+Error EditorSceneImporterGLTF::_parse_scenes(GLTFState &state) {
+
+ ERR_FAIL_COND_V(!state.json.has("scenes"), ERR_FILE_CORRUPT);
+ Array scenes = state.json["scenes"];
+ for (int i = 0; i < 1; i++) { //only first scene is imported
+ Dictionary s = scenes[i];
+ ERR_FAIL_COND_V(!s.has("nodes"), ERR_UNAVAILABLE);
+ Array nodes = s["nodes"];
+ for (int j = 0; j < nodes.size(); j++) {
+ state.root_nodes.push_back(nodes[j]);
+ }
+
+ if (s.has("name")) {
+ state.scene_name = s["name"];
+ }
+ }
+
+ return OK;
+}
+
+Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) {
+
+ ERR_FAIL_COND_V(!state.json.has("nodes"), ERR_FILE_CORRUPT);
+ Array nodes = state.json["nodes"];
+ for (int i = 0; i < nodes.size(); i++) {
+
+ GLTFNode *node = memnew(GLTFNode);
+ Dictionary n = nodes[i];
+
+ print_line("node " + itos(i) + ": " + String(Variant(n)));
+ if (n.has("name")) {
+ node->name = n["name"];
+ }
+ if (n.has("camera")) {
+ node->camera = n["camera"];
+ }
+ if (n.has("mesh")) {
+ node->mesh = n["mesh"];
+ }
+ if (n.has("skin")) {
+ node->skin = n["skin"];
+ if (!state.skin_users.has(node->skin)) {
+ state.skin_users[node->skin] = Vector<int>();
+ }
+
+ state.skin_users[node->skin].push_back(i);
+ }
+ if (n.has("matrix")) {
+ node->xform = _arr_to_xform(n["matrix"]);
+
+ } else {
+
+ if (n.has("translation")) {
+ node->translation = _arr_to_vec3(n["translation"]);
+ }
+ if (n.has("rotation")) {
+ node->rotation = _arr_to_quat(n["rotation"]);
+ }
+ if (n.has("scale")) {
+ node->scale = _arr_to_vec3(n["scale"]);
+ }
+
+ node->xform.basis = Basis(node->rotation);
+ node->xform.basis.scale(node->scale);
+ node->xform.origin = node->translation;
+ }
+
+ if (n.has("children")) {
+ Array children = n["children"];
+ for (int i = 0; i < children.size(); i++) {
+ node->children.push_back(children[i]);
+ }
+ }
+
+ state.nodes.push_back(node);
+ }
+
+ //build the hierarchy
+
+ for (int i = 0; i < state.nodes.size(); i++) {
+
+ for (int j = 0; j < state.nodes[i]->children.size(); j++) {
+ int child = state.nodes[i]->children[j];
+ ERR_FAIL_INDEX_V(child, state.nodes.size(), ERR_FILE_CORRUPT);
+ ERR_CONTINUE(state.nodes[child]->parent != -1); //node already has a parent, wtf.
+
+ state.nodes[child]->parent = i;
+ }
+ }
+
+ return OK;
+}
+
+static Vector<uint8_t> _parse_base64_uri(const String &uri) {
+
+ int start = uri.find(",");
+ ERR_FAIL_COND_V(start == -1, Vector<uint8_t>());
+
+ CharString substr = uri.right(start + 1).ascii();
+
+ int strlen = substr.length();
+
+ Vector<uint8_t> buf;
+ buf.resize(strlen / 4 * 3 + 1 + 1);
+
+ int len = base64_decode((char *)buf.ptr(), (char *)substr.get_data(), strlen);
+
+ buf.resize(len);
+
+ return buf;
+}
+
+Error EditorSceneImporterGLTF::_parse_buffers(GLTFState &state, const String &p_base_path) {
+
+ if (!state.json.has("buffers"))
+ return OK;
+
+ Array buffers = state.json["buffers"];
+ for (int i = 0; i < buffers.size(); i++) {
+
+ if (i == 0 && state.gfb_data.size()) {
+ state.buffers.push_back(state.gfb_data);
+
+ } else {
+ Dictionary buffer = buffers[i];
+ if (buffer.has("uri")) {
+
+ Vector<uint8_t> buffer_data;
+ String uri = buffer["uri"];
+
+ if (uri.findn("data:application/octet-stream;base64") == 0) {
+ //embedded data
+ buffer_data = _parse_base64_uri(uri);
+ } else {
+
+ uri = p_base_path.plus_file(uri).replace("\\", "/"); //fix for windows
+ buffer_data = FileAccess::get_file_as_array(uri);
+ ERR_FAIL_COND_V(buffer.size() == 0, ERR_PARSE_ERROR);
+ }
+
+ ERR_FAIL_COND_V(!buffer.has("byteLength"), ERR_PARSE_ERROR);
+ int byteLength = buffer["byteLength"];
+ ERR_FAIL_COND_V(byteLength < buffer_data.size(), ERR_PARSE_ERROR);
+ state.buffers.push_back(buffer_data);
+ }
+ }
+ }
+
+ print_line("total buffers: " + itos(state.buffers.size()));
+
+ return OK;
+}
+
+Error EditorSceneImporterGLTF::_parse_buffer_views(GLTFState &state) {
+
+ ERR_FAIL_COND_V(!state.json.has("bufferViews"), ERR_FILE_CORRUPT);
+ Array buffers = state.json["bufferViews"];
+ for (int i = 0; i < buffers.size(); i++) {
+
+ Dictionary d = buffers[i];
+
+ GLTFBufferView buffer_view;
+
+ ERR_FAIL_COND_V(!d.has("buffer"), ERR_PARSE_ERROR);
+ buffer_view.buffer = d["buffer"];
+ ERR_FAIL_COND_V(!d.has("byteLength"), ERR_PARSE_ERROR);
+ buffer_view.byte_length = d["byteLength"];
+
+ if (d.has("byteOffset")) {
+ buffer_view.byte_offset = d["byteOffset"];
+ }
+
+ if (d.has("byteStride")) {
+ buffer_view.byte_stride = d["byteStride"];
+ }
+
+ if (d.has("target")) {
+ int target = d["target"];
+ buffer_view.indices = target == ELEMENT_ARRAY_BUFFER;
+ }
+
+ state.buffer_views.push_back(buffer_view);
+ }
+
+ print_line("total buffer views: " + itos(state.buffer_views.size()));
+
+ return OK;
+}
+
+EditorSceneImporterGLTF::GLTFType EditorSceneImporterGLTF::_get_type_from_str(const String &p_string) {
+
+ if (p_string == "SCALAR")
+ return TYPE_SCALAR;
+
+ if (p_string == "VEC2")
+ return TYPE_VEC2;
+ if (p_string == "VEC3")
+ return TYPE_VEC3;
+ if (p_string == "VEC4")
+ return TYPE_VEC4;
+
+ if (p_string == "MAT2")
+ return TYPE_MAT2;
+ if (p_string == "MAT3")
+ return TYPE_MAT3;
+ if (p_string == "MAT4")
+ return TYPE_MAT4;
+
+ ERR_FAIL_V(TYPE_SCALAR);
+}
+
+Error EditorSceneImporterGLTF::_parse_accessors(GLTFState &state) {
+
+ ERR_FAIL_COND_V(!state.json.has("accessors"), ERR_FILE_CORRUPT);
+ Array accessors = state.json["accessors"];
+ for (int i = 0; i < accessors.size(); i++) {
+
+ Dictionary d = accessors[i];
+
+ GLTFAccessor accessor;
+
+ ERR_FAIL_COND_V(!d.has("componentType"), ERR_PARSE_ERROR);
+ accessor.component_type = d["componentType"];
+ ERR_FAIL_COND_V(!d.has("count"), ERR_PARSE_ERROR);
+ accessor.count = d["count"];
+ ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR);
+ accessor.type = _get_type_from_str(d["type"]);
+
+ if (d.has("bufferView")) {
+ accessor.buffer_view = d["bufferView"]; //optional because it may be sparse...
+ }
+
+ if (d.has("byteOffset")) {
+ accessor.byte_offset = d["byteOffset"];
+ }
+
+ if (d.has("max")) {
+ accessor.max = d["max"];
+ }
+
+ if (d.has("min")) {
+ accessor.min = d["min"];
+ }
+
+ if (d.has("sparse")) {
+ //eeh..
+
+ Dictionary s = d["sparse"];
+
+ ERR_FAIL_COND_V(!d.has("count"), ERR_PARSE_ERROR);
+ accessor.sparse_count = d["count"];
+ ERR_FAIL_COND_V(!d.has("indices"), ERR_PARSE_ERROR);
+ Dictionary si = d["indices"];
+
+ ERR_FAIL_COND_V(!si.has("bufferView"), ERR_PARSE_ERROR);
+ accessor.sparse_indices_buffer_view = si["bufferView"];
+ ERR_FAIL_COND_V(!si.has("componentType"), ERR_PARSE_ERROR);
+ accessor.sparse_indices_component_type = si["componentType"];
+
+ if (si.has("byteOffset")) {
+ accessor.sparse_indices_byte_offset = si["byteOffset"];
+ }
+
+ ERR_FAIL_COND_V(!d.has("values"), ERR_PARSE_ERROR);
+ Dictionary sv = d["values"];
+
+ ERR_FAIL_COND_V(!sv.has("bufferView"), ERR_PARSE_ERROR);
+ accessor.sparse_values_buffer_view = sv["bufferView"];
+ if (sv.has("byteOffset")) {
+ accessor.sparse_values_byte_offset = sv["byteOffset"];
+ }
+ }
+
+ state.accessors.push_back(accessor);
+ }
+
+ print_line("total accessors: " + itos(state.accessors.size()));
+
+ return OK;
+}
+
+String EditorSceneImporterGLTF::_get_component_type_name(uint32_t p_component) {
+
+ switch (p_component) {
+ case COMPONENT_TYPE_BYTE: return "Byte";
+ case COMPONENT_TYPE_UNSIGNED_BYTE: return "UByte";
+ case COMPONENT_TYPE_SHORT: return "Short";
+ case COMPONENT_TYPE_UNSIGNED_SHORT: return "UShort";
+ case COMPONENT_TYPE_INT: return "Int";
+ case COMPONENT_TYPE_FLOAT: return "Float";
+ }
+
+ return "<Error>";
+}
+
+String EditorSceneImporterGLTF::_get_type_name(GLTFType p_component) {
+
+ static const char *names[] = {
+ "float",
+ "vec2",
+ "vec3",
+ "vec4",
+ "mat2",
+ "mat3",
+ "mat4"
+ };
+
+ return names[p_component];
+}
+
+Error EditorSceneImporterGLTF::_decode_buffer_view(GLTFState &state, int p_buffer_view, double *dst, int skip_every, int skip_bytes, int element_size, int count, GLTFType type, int component_count, int component_type, int component_size, bool normalized, int byte_offset, bool for_vertex) {
+
+ const GLTFBufferView &bv = state.buffer_views[p_buffer_view];
+
+ int stride = bv.byte_stride ? bv.byte_stride : element_size;
+ if (for_vertex && stride % 4) {
+ stride += 4 - (stride % 4); //according to spec must be multiple of 4
+ }
+
+ ERR_FAIL_INDEX_V(bv.buffer, state.buffers.size(), ERR_PARSE_ERROR);
+
+ uint32_t offset = bv.byte_offset + byte_offset;
+ Vector<uint8_t> buffer = state.buffers[bv.buffer]; //copy on write, so no performance hit
+
+ //use to debug
+ print_line("type " + _get_type_name(type) + " component type: " + _get_component_type_name(component_type) + " stride: " + itos(stride) + " amount " + itos(count));
+ print_line("accessor offset" + itos(byte_offset) + " view offset: " + itos(bv.byte_offset) + " total buffer len: " + itos(buffer.size()) + " view len " + itos(bv.byte_length));
+
+ int buffer_end = (stride * (count - 1)) + element_size;
+ ERR_FAIL_COND_V(buffer_end > bv.byte_length, ERR_PARSE_ERROR);
+
+ ERR_FAIL_COND_V((offset + buffer_end) > buffer.size(), ERR_PARSE_ERROR);
+
+ //fill everything as doubles
+
+ for (int i = 0; i < count; i++) {
+
+ const uint8_t *src = &buffer[offset + i * stride];
+
+ for (int j = 0; j < component_count; j++) {
+
+ if (skip_every && j > 0 && (j % skip_every) == 0) {
+ src += skip_bytes;
+ }
+
+ double d = 0;
+
+ switch (component_type) {
+ case COMPONENT_TYPE_BYTE: {
+ int8_t b = int8_t(*src);
+ if (normalized) {
+ d = (double(b) / 128.0);
+ } else {
+ d = double(b);
+ }
+ } break;
+ case COMPONENT_TYPE_UNSIGNED_BYTE: {
+ uint8_t b = *src;
+ if (normalized) {
+ d = (double(b) / 255.0);
+ } else {
+ d = double(b);
+ }
+ } break;
+ case COMPONENT_TYPE_SHORT: {
+ int16_t s = *(int16_t *)src;
+ if (normalized) {
+ d = (double(s) / 32768.0);
+ } else {
+ d = double(s);
+ }
+ } break;
+ case COMPONENT_TYPE_UNSIGNED_SHORT: {
+ uint16_t s = *(uint16_t *)src;
+ if (normalized) {
+ d = (double(s) / 65535.0);
+ } else {
+ d = double(s);
+ }
+
+ } break;
+ case COMPONENT_TYPE_INT: {
+ d = *(int *)src;
+ } break;
+ case COMPONENT_TYPE_FLOAT: {
+ d = *(float *)src;
+ } break;
+ }
+
+ *dst++ = d;
+ src += component_size;
+ }
+ }
+
+ return OK;
+}
+
+int EditorSceneImporterGLTF::_get_component_type_size(int component_type) {
+
+ switch (component_type) {
+ case COMPONENT_TYPE_BYTE: return 1; break;
+ case COMPONENT_TYPE_UNSIGNED_BYTE: return 1; break;
+ case COMPONENT_TYPE_SHORT: return 2; break;
+ case COMPONENT_TYPE_UNSIGNED_SHORT: return 2; break;
+ case COMPONENT_TYPE_INT: return 4; break;
+ case COMPONENT_TYPE_FLOAT: return 4; break;
+ default: { ERR_FAIL_V(0); }
+ }
+ return 0;
+}
+
+Vector<double> EditorSceneImporterGLTF::_decode_accessor(GLTFState &state, int p_accessor, bool p_for_vertex) {
+
+ //spec, for reference:
+ //https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
+
+ ERR_FAIL_INDEX_V(p_accessor, state.accessors.size(), Vector<double>());
+
+ const GLTFAccessor &a = state.accessors[p_accessor];
+
+ int component_count_for_type[7] = {
+ 1, 2, 3, 4, 4, 9, 16
+ };
+
+ int component_count = component_count_for_type[a.type];
+ int component_size = _get_component_type_size(a.component_type);
+ ERR_FAIL_COND_V(component_size == 0, Vector<double>());
+ int element_size = component_count * component_size;
+
+ int skip_every = 0;
+ int skip_bytes = 0;
+ //special case of alignments, as described in spec
+ switch (a.component_type) {
+ case COMPONENT_TYPE_BYTE:
+ case COMPONENT_TYPE_UNSIGNED_BYTE: {
+
+ if (a.type == TYPE_MAT2) {
+ skip_every = 2;
+ skip_bytes = 2;
+ element_size = 8; //override for this case
+ }
+ if (a.type == TYPE_MAT3) {
+ skip_every = 3;
+ skip_bytes = 1;
+ element_size = 12; //override for this case
+ }
+
+ } break;
+ case COMPONENT_TYPE_SHORT:
+ case COMPONENT_TYPE_UNSIGNED_SHORT: {
+ if (a.type == TYPE_MAT3) {
+ skip_every = 6;
+ skip_bytes = 4;
+ element_size = 16; //override for this case
+ }
+ } break;
+ default: {}
+ }
+
+ Vector<double> dst_buffer;
+ dst_buffer.resize(component_count * a.count);
+ double *dst = dst_buffer.ptr();
+
+ if (a.buffer_view >= 0) {
+
+ ERR_FAIL_INDEX_V(a.buffer_view, state.buffer_views.size(), Vector<double>());
+
+ Error err = _decode_buffer_view(state, a.buffer_view, dst, skip_every, skip_bytes, element_size, a.count, a.type, component_count, a.component_type, component_size, a.normalized, a.byte_offset, p_for_vertex);
+ if (err != OK)
+ return Vector<double>();
+
+ } else {
+ //fill with zeros, as bufferview is not defined.
+ for (int i = 0; i < (a.count * component_count); i++) {
+ dst_buffer[i] = 0;
+ }
+ }
+
+ if (a.sparse_count > 0) {
+ // I could not find any file using this, so this code is so far untested
+ Vector<double> indices;
+ indices.resize(a.sparse_count);
+ int indices_component_size = _get_component_type_size(a.sparse_indices_component_type);
+
+ Error err = _decode_buffer_view(state, a.sparse_indices_buffer_view, indices.ptr(), 0, 0, indices_component_size, a.sparse_count, TYPE_SCALAR, 1, a.sparse_indices_component_type, indices_component_size, false, a.sparse_indices_byte_offset, false);
+ if (err != OK)
+ return Vector<double>();
+
+ Vector<double> data;
+ data.resize(component_count * a.sparse_count);
+ err = _decode_buffer_view(state, a.sparse_values_buffer_view, data.ptr(), skip_every, skip_bytes, element_size, a.sparse_count, a.type, component_count, a.component_type, component_size, a.normalized, a.sparse_values_byte_offset, p_for_vertex);
+ if (err != OK)
+ return Vector<double>();
+
+ for (int i = 0; i < indices.size(); i++) {
+ int write_offset = int(indices[i]) * component_count;
+
+ for (int j = 0; j < component_count; j++) {
+ dst[write_offset + j] = data[i * component_count + j];
+ }
+ }
+ }
+
+ return dst_buffer;
+}
+
+PoolVector<int> EditorSceneImporterGLTF::_decode_accessor_as_ints(GLTFState &state, int p_accessor, bool p_for_vertex) {
+
+ Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ PoolVector<int> ret;
+ if (attribs.size() == 0)
+ return ret;
+ const double *attribs_ptr = attribs.ptr();
+ int ret_size = attribs.size();
+ ret.resize(ret_size);
+ {
+ PoolVector<int>::Write w = ret.write();
+ for (int i = 0; i < ret_size; i++) {
+ w[i] = int(attribs_ptr[i]);
+ }
+ }
+ return ret;
+}
+
+PoolVector<float> EditorSceneImporterGLTF::_decode_accessor_as_floats(GLTFState &state, int p_accessor, bool p_for_vertex) {
+
+ Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ PoolVector<float> ret;
+ if (attribs.size() == 0)
+ return ret;
+ const double *attribs_ptr = attribs.ptr();
+ int ret_size = attribs.size();
+ ret.resize(ret_size);
+ {
+ PoolVector<float>::Write w = ret.write();
+ for (int i = 0; i < ret_size; i++) {
+ w[i] = float(attribs_ptr[i]);
+ }
+ }
+ return ret;
+}
+
+PoolVector<Vector2> EditorSceneImporterGLTF::_decode_accessor_as_vec2(GLTFState &state, int p_accessor, bool p_for_vertex) {
+
+ Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ PoolVector<Vector2> ret;
+ if (attribs.size() == 0)
+ return ret;
+ ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret);
+ const double *attribs_ptr = attribs.ptr();
+ int ret_size = attribs.size() / 2;
+ ret.resize(ret_size);
+ {
+ PoolVector<Vector2>::Write w = ret.write();
+ for (int i = 0; i < ret_size; i++) {
+ w[i] = Vector2(attribs_ptr[i * 2 + 0], attribs_ptr[i * 2 + 1]);
+ }
+ }
+ return ret;
+}
+
+PoolVector<Vector3> EditorSceneImporterGLTF::_decode_accessor_as_vec3(GLTFState &state, int p_accessor, bool p_for_vertex) {
+
+ Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ PoolVector<Vector3> ret;
+ if (attribs.size() == 0)
+ return ret;
+ ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret);
+ const double *attribs_ptr = attribs.ptr();
+ int ret_size = attribs.size() / 3;
+ ret.resize(ret_size);
+ {
+ PoolVector<Vector3>::Write w = ret.write();
+ for (int i = 0; i < ret_size; i++) {
+ w[i] = Vector3(attribs_ptr[i * 3 + 0], attribs_ptr[i * 3 + 1], attribs_ptr[i * 3 + 2]);
+ }
+ }
+ return ret;
+}
+PoolVector<Color> EditorSceneImporterGLTF::_decode_accessor_as_color(GLTFState &state, int p_accessor, bool p_for_vertex) {
+
+ Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ PoolVector<Color> ret;
+ if (attribs.size() == 0)
+ return ret;
+ ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
+ const double *attribs_ptr = attribs.ptr();
+ int ret_size = attribs.size() / 4;
+ ret.resize(ret_size);
+ {
+ PoolVector<Color>::Write w = ret.write();
+ for (int i = 0; i < ret_size; i++) {
+ w[i] = Color(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]);
+ }
+ }
+ return ret;
+}
+Vector<Transform2D> EditorSceneImporterGLTF::_decode_accessor_as_xform2d(GLTFState &state, int p_accessor, bool p_for_vertex) {
+
+ Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<Transform2D> ret;
+ if (attribs.size() == 0)
+ return ret;
+ ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
+ ret.resize(attribs.size() / 4);
+ for (int i = 0; i < ret.size(); i++) {
+ ret[i][0] = Vector2(attribs[i * 4 + 0], attribs[i * 4 + 1]);
+ ret[i][1] = Vector2(attribs[i * 4 + 2], attribs[i * 4 + 3]);
+ }
+ return ret;
+}
+
+Vector<Basis> EditorSceneImporterGLTF::_decode_accessor_as_basis(GLTFState &state, int p_accessor, bool p_for_vertex) {
+
+ Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<Basis> ret;
+ if (attribs.size() == 0)
+ return ret;
+ ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret);
+ ret.resize(attribs.size() / 9);
+ for (int i = 0; i < ret.size(); i++) {
+ ret[i].set_axis(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2]));
+ ret[i].set_axis(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5]));
+ ret[i].set_axis(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8]));
+ }
+ return ret;
+}
+Vector<Transform> EditorSceneImporterGLTF::_decode_accessor_as_xform(GLTFState &state, int p_accessor, bool p_for_vertex) {
+
+ Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
+ Vector<Transform> ret;
+ if (attribs.size() == 0)
+ return ret;
+ ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret);
+ ret.resize(attribs.size() / 16);
+ for (int i = 0; i < ret.size(); i++) {
+ ret[i].basis.set_axis(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2]));
+ ret[i].basis.set_axis(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6]));
+ ret[i].basis.set_axis(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10]));
+ ret[i].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14]));
+ }
+ return ret;
+}
+
+Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) {
+
+ if (!state.json.has("meshes"))
+ return OK;
+
+ Array meshes = state.json["meshes"];
+ for (int i = 0; i < meshes.size(); i++) {
+
+ Dictionary d = meshes[i];
+
+ GLTFMesh mesh;
+ mesh.mesh.instance();
+
+ ERR_FAIL_COND_V(!d.has("primitives"), ERR_PARSE_ERROR);
+
+ Array primitives = d["primitives"];
+
+ for (int j = 0; j < primitives.size(); j++) {
+
+ Dictionary p = primitives[j];
+
+ Array array;
+ array.resize(Mesh::ARRAY_MAX);
+
+ ERR_FAIL_COND_V(!p.has("attributes"), ERR_PARSE_ERROR);
+
+ Dictionary a = p["attributes"];
+
+ Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_TRIANGLES;
+ if (p.has("mode")) {
+ int mode = p["mode"];
+ ERR_FAIL_INDEX_V(mode, 7, ERR_FILE_CORRUPT);
+ static const Mesh::PrimitiveType primitives[7] = {
+ Mesh::PRIMITIVE_POINTS,
+ Mesh::PRIMITIVE_LINES,
+ Mesh::PRIMITIVE_LINE_LOOP,
+ Mesh::PRIMITIVE_LINE_STRIP,
+ Mesh::PRIMITIVE_TRIANGLES,
+ Mesh::PRIMITIVE_TRIANGLE_STRIP,
+ Mesh::PRIMITIVE_TRIANGLE_FAN,
+ };
+
+ primitive = primitives[mode];
+ }
+
+ if (a.has("POSITION")) {
+ array[Mesh::ARRAY_VERTEX] = _decode_accessor_as_vec3(state, a["POSITION"], true);
+ }
+ if (a.has("NORMAL")) {
+ array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(state, a["NORMAL"], true);
+ }
+ if (a.has("TANGENT")) {
+ array[Mesh::ARRAY_TANGENT] = _decode_accessor_as_floats(state, a["TANGENT"], true);
+ }
+ if (a.has("TEXCOORD_0")) {
+ array[Mesh::ARRAY_TEX_UV] = _decode_accessor_as_vec2(state, a["TEXCOORD_0"], true);
+ }
+ if (a.has("TEXCOORD_1")) {
+ array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(state, a["TEXCOORD_1"], true);
+ }
+ if (a.has("COLOR_0")) {
+ array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(state, a["COLOR_0"], true);
+ }
+ if (a.has("JOINTS_0")) {
+ array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(state, a["JOINTS_0"], true);
+ }
+ if (a.has("WEIGHTS_0")) {
+ PoolVector<float> weights = _decode_accessor_as_floats(state, a["WEIGHTS_0"], true);
+ { //gltf does not seem to normalize the weights for some reason..
+ int wc = weights.size();
+ PoolVector<float>::Write w = weights.write();
+ for (int i = 0; i < wc; i += 4) {
+ float total = 0.0;
+ total += w[i + 0];
+ total += w[i + 1];
+ total += w[i + 2];
+ total += w[i + 3];
+ if (total > 0.0) {
+ w[i + 0] /= total;
+ w[i + 1] /= total;
+ w[i + 2] /= total;
+ w[i + 3] /= total;
+ }
+ }
+ }
+ array[Mesh::ARRAY_WEIGHTS] = weights;
+ }
+
+ if (p.has("indices")) {
+
+ PoolVector<int> indices = _decode_accessor_as_ints(state, p["indices"], false);
+
+ if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
+ //swap around indices, convert ccw to cw for front face
+
+ int is = indices.size();
+ PoolVector<int>::Write w = indices.write();
+ for (int i = 0; i < is; i += 3) {
+ SWAP(w[i + 1], w[i + 2]);
+ }
+ }
+ array[Mesh::ARRAY_INDEX] = indices;
+ } else if (primitive == Mesh::PRIMITIVE_TRIANGLES) {
+ //generate indices because they need to be swapped for CW/CCW
+ PoolVector<Vector3> vertices = array[Mesh::ARRAY_VERTEX];
+ ERR_FAIL_COND_V(vertices.size() == 0, ERR_PARSE_ERROR);
+ PoolVector<int> indices;
+ int vs = vertices.size();
+ indices.resize(vs);
+ {
+ PoolVector<int>::Write w = indices.write();
+ for (int i = 0; i < vs; i += 3) {
+ w[i] = i;
+ w[i + 1] = i + 2;
+ w[i + 2] = i + 1;
+ }
+ }
+ array[Mesh::ARRAY_INDEX] = indices;
+ }
+
+ bool generated_tangents = false;
+ Variant erased_indices;
+
+ if (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL")) {
+ //must generate mikktspace tangents.. ergh..
+ Ref<SurfaceTool> st;
+ st.instance();
+ st->create_from_triangle_arrays(array);
+ if (p.has("targets")) {
+ //morph targets should not be reindexed, as array size might differ
+ //removing indices is the best bet here
+ st->deindex();
+ erased_indices = a[Mesh::ARRAY_INDEX];
+ a[Mesh::ARRAY_INDEX] = Variant();
+ }
+ st->generate_tangents();
+ array = st->commit_to_arrays();
+ generated_tangents = true;
+ }
+
+ Array morphs;
+ //blend shapes
+ if (p.has("targets")) {
+ print_line("has targets!");
+ Array targets = p["targets"];
+
+ if (j == 0) {
+ for (int k = 0; k < targets.size(); k++) {
+ mesh.mesh->add_blend_shape(String("morph_") + itos(k));
+ }
+ }
+
+ for (int k = 0; k < targets.size(); k++) {
+
+ Dictionary t = targets[k];
+
+ Array array_copy;
+ array_copy.resize(Mesh::ARRAY_MAX);
+
+ for (int l = 0; l < Mesh::ARRAY_MAX; l++) {
+ array_copy[l] = array[l];
+ }
+
+ array_copy[Mesh::ARRAY_INDEX] = Variant();
+
+ if (t.has("POSITION")) {
+ array_copy[Mesh::ARRAY_VERTEX] = _decode_accessor_as_vec3(state, t["POSITION"], true);
+ }
+ if (t.has("NORMAL")) {
+ array_copy[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(state, t["NORMAL"], true);
+ }
+ if (t.has("TANGENT")) {
+ PoolVector<Vector3> tangents_v3 = _decode_accessor_as_vec3(state, t["TANGENT"], true);
+ PoolVector<float> tangents_v4;
+ PoolVector<float> src_tangents = array[Mesh::ARRAY_TANGENT];
+ ERR_FAIL_COND_V(src_tangents.size() == 0, ERR_PARSE_ERROR);
+
+ {
+
+ int size4 = src_tangents.size();
+ tangents_v4.resize(size4);
+ PoolVector<float>::Write w4 = tangents_v4.write();
+
+ PoolVector<Vector3>::Read r3 = tangents_v3.read();
+ PoolVector<float>::Read r4 = src_tangents.read();
+
+ for (int l = 0; l < size4 / 4; l++) {
+
+ w4[l * 4 + 0] = r3[l].x;
+ w4[l * 4 + 1] = r3[l].y;
+ w4[l * 4 + 2] = r3[l].z;
+ w4[l * 4 + 3] = r4[l * 4 + 3]; //copy flip value
+ }
+ }
+
+ array_copy[Mesh::ARRAY_TANGENT] = tangents_v4;
+ }
+
+ if (generated_tangents) {
+ Ref<SurfaceTool> st;
+ st.instance();
+ array_copy[Mesh::ARRAY_INDEX] = erased_indices; //needed for tangent generation, erased by deindex
+ st->create_from_triangle_arrays(array_copy);
+ st->deindex();
+ st->generate_tangents();
+ array_copy = st->commit_to_arrays();
+ }
+
+ morphs.push_back(array_copy);
+ }
+ }
+
+ //just add it
+ mesh.mesh->add_surface_from_arrays(primitive, array, morphs);
+
+ if (p.has("material")) {
+ int material = p["material"];
+ ERR_FAIL_INDEX_V(material, state.materials.size(), ERR_FILE_CORRUPT);
+ Ref<Material> mat = state.materials[material];
+
+ mesh.mesh->surface_set_material(mesh.mesh->get_surface_count() - 1, mat);
+ }
+ }
+
+ if (d.has("weights")) {
+ Array weights = d["weights"];
+ ERR_FAIL_COND_V(mesh.mesh->get_blend_shape_count() != weights.size(), ERR_PARSE_ERROR);
+ mesh.blend_weights.resize(weights.size());
+ for (int j = 0; j < weights.size(); j++) {
+ mesh.blend_weights[j] = weights[j];
+ }
+ }
+
+ state.meshes.push_back(mesh);
+ }
+
+ print_line("total meshes: " + itos(state.meshes.size()));
+
+ return OK;
+}
+
+Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_base_path) {
+
+ if (!state.json.has("images"))
+ return OK;
+
+ Array images = state.json["images"];
+ for (int i = 0; i < images.size(); i++) {
+
+ Dictionary d = images[i];
+
+ String mimetype;
+ if (d.has("mimeType")) {
+ mimetype = d["mimeType"];
+ }
+
+ Vector<uint8_t> data;
+ const uint8_t *data_ptr = NULL;
+ int data_size = 0;
+
+ if (d.has("uri")) {
+ String uri = d["uri"];
+
+ if (uri.findn("data:application/octet-stream;base64") == 0) {
+ //embedded data
+ data = _parse_base64_uri(uri);
+ data_ptr = data.ptr();
+ data_size = data.size();
+ } else {
+
+ uri = p_base_path.plus_file(uri).replace("\\", "/"); //fix for windows
+ Ref<Texture> texture = ResourceLoader::load(uri);
+ state.images.push_back(texture);
+ continue;
+ }
+ }
+
+ if (d.has("bufferView")) {
+ int bvi = d["bufferView"];
+
+ ERR_FAIL_INDEX_V(bvi, state.buffer_views.size(), ERR_PARAMETER_RANGE_ERROR);
+
+ GLTFBufferView &bv = state.buffer_views[bvi];
+
+ int bi = bv.buffer;
+ ERR_FAIL_INDEX_V(bi, state.buffers.size(), ERR_PARAMETER_RANGE_ERROR);
+
+ ERR_FAIL_COND_V(bv.byte_offset + bv.byte_length > state.buffers[bi].size(), ERR_FILE_CORRUPT);
+
+ data_ptr = &state.buffers[bi][bv.byte_offset];
+ data_size = bv.byte_length;
+ }
+
+ ERR_FAIL_COND_V(mimetype == "", ERR_FILE_CORRUPT);
+
+ if (mimetype.findn("png") != -1) {
+ //is a png
+ Ref<Image> img = Image::_png_mem_loader_func(data_ptr, data_size);
+
+ ERR_FAIL_COND_V(img.is_null(), ERR_FILE_CORRUPT);
+
+ Ref<ImageTexture> t;
+ t.instance();
+ t->create_from_image(img);
+
+ state.images.push_back(t);
+ continue;
+ }
+
+ if (mimetype.findn("jpg") != -1) {
+ //is a jpg
+ Ref<Image> img = Image::_jpg_mem_loader_func(data_ptr, data_size);
+
+ ERR_FAIL_COND_V(img.is_null(), ERR_FILE_CORRUPT);
+
+ Ref<ImageTexture> t;
+ t.instance();
+ t->create_from_image(img);
+
+ state.images.push_back(t);
+
+ continue;
+ }
+
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ print_line("total images: " + itos(state.images.size()));
+
+ return OK;
+}
+
+Error EditorSceneImporterGLTF::_parse_textures(GLTFState &state) {
+
+ if (!state.json.has("textures"))
+ return OK;
+
+ Array textures = state.json["textures"];
+ for (int i = 0; i < textures.size(); i++) {
+
+ Dictionary d = textures[i];
+
+ ERR_FAIL_COND_V(!d.has("source"), ERR_PARSE_ERROR);
+
+ GLTFTexture t;
+ t.src_image = d["source"];
+ state.textures.push_back(t);
+ }
+
+ return OK;
+}
+
+Ref<Texture> EditorSceneImporterGLTF::_get_texture(GLTFState &state, int p_texture) {
+ ERR_FAIL_INDEX_V(p_texture, state.textures.size(), Ref<Texture>());
+ int image = state.textures[p_texture].src_image;
+
+ ERR_FAIL_INDEX_V(image, state.images.size(), Ref<Texture>());
+
+ return state.images[image];
+}
+
+Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) {
+
+ if (!state.json.has("materials"))
+ return OK;
+
+ Array materials = state.json["materials"];
+ for (int i = 0; i < materials.size(); i++) {
+
+ Dictionary d = materials[i];
+
+ Ref<SpatialMaterial> material;
+ material.instance();
+ if (d.has("name")) {
+ material->set_name(d["name"]);
+ }
+
+ if (d.has("pbrMetallicRoughness")) {
+
+ Dictionary mr = d["pbrMetallicRoughness"];
+ if (mr.has("baseColorFactor")) {
+ Array arr = mr["baseColorFactor"];
+ ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR);
+ Color c = Color(arr[0], arr[1], arr[2], arr[3]).to_srgb();
+
+ material->set_albedo(c);
+ }
+
+ if (mr.has("baseColorTexture")) {
+ Dictionary bct = mr["baseColorTexture"];
+ if (bct.has("index")) {
+ material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, _get_texture(state, bct["index"]));
+ }
+ if (!mr.has("baseColorFactor")) {
+ material->set_albedo(Color(1, 1, 1));
+ }
+ }
+
+ if (mr.has("metallicFactor")) {
+
+ material->set_metallic(mr["metallicFactor"]);
+ }
+ if (mr.has("roughnessFactor")) {
+
+ material->set_roughness(mr["roughnessFactor"]);
+ }
+
+ if (mr.has("metallicRoughnessTexture")) {
+ Dictionary bct = mr["metallicRoughnessTexture"];
+ if (bct.has("index")) {
+ Ref<Texture> t = _get_texture(state, bct["index"]);
+ material->set_texture(SpatialMaterial::TEXTURE_METALLIC, t);
+ material->set_metallic_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_RED);
+ material->set_texture(SpatialMaterial::TEXTURE_ROUGHNESS, t);
+ material->set_roughness_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_GREEN);
+ if (!mr.has("metallicFactor")) {
+ material->set_metallic(1);
+ }
+ if (!mr.has("roughnessFactor")) {
+ material->set_roughness(1);
+ }
+ }
+ }
+ }
+
+ if (d.has("normalTexture")) {
+ Dictionary bct = d["normalTexture"];
+ if (bct.has("index")) {
+ material->set_texture(SpatialMaterial::TEXTURE_NORMAL, _get_texture(state, bct["index"]));
+ material->set_feature(SpatialMaterial::FEATURE_NORMAL_MAPPING, true);
+ }
+ if (bct.has("scale")) {
+ material->set_normal_scale(bct["scale"]);
+ }
+ }
+ if (d.has("occlusionTexture")) {
+ Dictionary bct = d["occlusionTexture"];
+ if (bct.has("index")) {
+ material->set_texture(SpatialMaterial::TEXTURE_AMBIENT_OCCLUSION, _get_texture(state, bct["index"]));
+ material->set_feature(SpatialMaterial::FEATURE_AMBIENT_OCCLUSION, true);
+ }
+ }
+
+ if (d.has("emissiveFactor")) {
+ Array arr = d["emissiveFactor"];
+ ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR);
+ Color c = Color(arr[0], arr[1], arr[2]).to_srgb();
+ material->set_feature(SpatialMaterial::FEATURE_EMISSION, true);
+
+ material->set_emission(c);
+ }
+
+ if (d.has("emissiveTexture")) {
+ Dictionary bct = d["emissiveTexture"];
+ if (bct.has("index")) {
+ material->set_texture(SpatialMaterial::TEXTURE_EMISSION, _get_texture(state, bct["index"]));
+ material->set_feature(SpatialMaterial::FEATURE_EMISSION, true);
+ material->set_emission(Color(0, 0, 0));
+ }
+ }
+
+ if (d.has("doubleSided")) {
+ bool ds = d["doubleSided"];
+ if (ds) {
+ material->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+ }
+ }
+
+ if (d.has("alphaMode")) {
+ String am = d["alphaMode"];
+ if (am != "OPAQUE") {
+ material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ }
+ }
+
+ state.materials.push_back(material);
+ }
+
+ print_line("total materials: " + itos(state.materials.size()));
+
+ return OK;
+}
+
+Error EditorSceneImporterGLTF::_parse_skins(GLTFState &state) {
+
+ if (!state.json.has("skins"))
+ return OK;
+
+ Array skins = state.json["skins"];
+ for (int i = 0; i < skins.size(); i++) {
+
+ Dictionary d = skins[i];
+
+ GLTFSkin skin;
+
+ ERR_FAIL_COND_V(!d.has("joints"), ERR_PARSE_ERROR);
+
+ Array joints = d["joints"];
+ Vector<Transform> bind_matrices;
+
+ if (d.has("inverseBindMatrices")) {
+ bind_matrices = _decode_accessor_as_xform(state, d["inverseBindMatrices"], false);
+ ERR_FAIL_COND_V(bind_matrices.size() != joints.size(), ERR_PARSE_ERROR);
+ }
+
+ for (int j = 0; j < joints.size(); j++) {
+ int index = joints[j];
+ ERR_FAIL_INDEX_V(index, state.nodes.size(), ERR_PARSE_ERROR);
+ state.nodes[index]->joint_skin = state.skins.size();
+ state.nodes[index]->joint_bone = j;
+ GLTFSkin::Bone bone;
+ bone.node = index;
+ if (bind_matrices.size()) {
+ bone.inverse_bind = bind_matrices[j];
+ }
+
+ skin.bones.push_back(bone);
+ }
+
+ print_line("skin has skeleton? " + itos(d.has("skeleton")));
+ if (d.has("skeleton")) {
+ int skeleton = d["skeleton"];
+ ERR_FAIL_INDEX_V(skeleton, state.nodes.size(), ERR_PARSE_ERROR);
+ state.nodes[skeleton]->skeleton_skin = state.skins.size();
+ print_line("setting skeleton skin to" + itos(skeleton));
+ skin.skeleton = skeleton;
+ }
+
+ if (d.has("name")) {
+ skin.name = d["name"];
+ }
+
+ //locate the right place to put a Skeleton node
+
+ if (state.skin_users.has(i)) {
+ Vector<int> users = state.skin_users[i];
+ int skin_node = -1;
+ for (int j = 0; j < users.size(); j++) {
+ int user = state.nodes[users[j]]->parent; //always go from parent
+ if (j == 0) {
+ skin_node = user;
+ } else if (skin_node != -1) {
+ bool found = false;
+ while (skin_node >= 0) {
+
+ int cuser = user;
+ while (cuser != -1) {
+ if (cuser == skin_node) {
+ found = true;
+ break;
+ }
+ cuser = state.nodes[skin_node]->parent;
+ }
+ if (found)
+ break;
+ skin_node = state.nodes[skin_node]->parent;
+ }
+
+ if (!found) {
+ skin_node = -1; //just leave where it is
+ }
+
+ //find a common parent
+ }
+ }
+
+ if (skin_node != -1) {
+ for (int j = 0; j < users.size(); j++) {
+ state.nodes[users[j]]->child_of_skeleton = i;
+ }
+
+ state.nodes[skin_node]->skeleton_children.push_back(i);
+ }
+ state.skins.push_back(skin);
+ }
+ }
+ print_line("total skins: " + itos(state.skins.size()));
+
+ //now
+
+ return OK;
+}
+
+Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) {
+
+ if (!state.json.has("cameras"))
+ return OK;
+
+ Array cameras = state.json["cameras"];
+
+ for (int i = 0; i < cameras.size(); i++) {
+
+ Dictionary d = cameras[i];
+
+ GLTFCamera camera;
+ ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR);
+ String type = d["type"];
+ if (type == "orthographic") {
+
+ camera.perspective = false;
+ if (d.has("orthographic")) {
+ Dictionary og = d["orthographic"];
+ camera.fov_size = og["ymag"];
+ camera.zfar = og["zfar"];
+ camera.znear = og["znear"];
+ } else {
+ camera.fov_size = 10;
+ }
+
+ } else if (type == "perspective") {
+
+ camera.perspective = true;
+ if (d.has("perspective")) {
+ Dictionary ppt = d["perspective"];
+ camera.fov_size = ppt["yfov"];
+ camera.zfar = ppt["zfar"];
+ camera.znear = ppt["znear"];
+ } else {
+ camera.fov_size = 10;
+ }
+ } else {
+ ERR_EXPLAIN("Camera should be in 'orthographic' or 'perspective'");
+ ERR_FAIL_V(ERR_PARSE_ERROR);
+ }
+
+ state.cameras.push_back(camera);
+ }
+}
+
+void EditorSceneImporterGLTF::_assign_scene_names(GLTFState &state) {
+
+ for (int i = 0; i < state.nodes.size(); i++) {
+ GLTFNode *n = state.nodes[i];
+ if (n->name == "") {
+ if (n->mesh >= 0) {
+ n->name = "Mesh";
+ } else if (n->joint_skin >= 0) {
+ n->name = "Bone";
+ } else {
+ n->name = "Node";
+ }
+ }
+
+ n->name = _gen_unique_name(state, n->name);
+ }
+}
+
+void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node *p_parent, Node *p_owner, Vector<Skeleton *> &skeletons) {
+ ERR_FAIL_INDEX(p_node, state.nodes.size());
+
+ GLTFNode *n = state.nodes[p_node];
+ Spatial *node;
+
+ if (n->mesh >= 0) {
+ ERR_FAIL_INDEX(n->mesh, state.meshes.size());
+ MeshInstance *mi = memnew(MeshInstance);
+ const GLTFMesh &mesh = state.meshes[n->mesh];
+ mi->set_mesh(mesh.mesh);
+ for (int i = 0; i < mesh.blend_weights.size(); i++) {
+ mi->set("blend_shapes/" + mesh.mesh->get_blend_shape_name(i), mesh.blend_weights[i]);
+ }
+
+ node = mi;
+ } else if (n->camera >= 0) {
+ ERR_FAIL_INDEX(n->camera, state.cameras.size());
+ Camera *camera = memnew(Camera);
+
+ const GLTFCamera &c = state.cameras[n->camera];
+ if (c.perspective) {
+ camera->set_perspective(c.fov_size, c.znear, c.znear);
+ } else {
+ camera->set_orthogonal(c.fov_size, c.znear, c.znear);
+ }
+
+ node = camera;
+ } else {
+ node = memnew(Spatial);
+ }
+
+ node->set_name(n->name);
+
+ if (n->child_of_skeleton >= 0) {
+ //move skeleton around and place it on node, as the node _is_ a skeleton.
+ Skeleton *s = skeletons[n->child_of_skeleton];
+ p_parent = s;
+ }
+
+ p_parent->add_child(node);
+ node->set_owner(p_owner);
+ node->set_transform(n->xform);
+
+ for (int i = 0; i < n->skeleton_children.size(); i++) {
+
+ Skeleton *s = skeletons[n->skeleton_children[i]];
+ s->get_parent()->remove_child(s);
+ node->add_child(s);
+ s->set_owner(p_owner);
+ }
+
+ for (int i = 0; i < n->children.size(); i++) {
+ if (state.nodes[n->children[i]]->joint_skin >= 0) {
+ _generate_bone(state, n->children[i], skeletons, -1);
+ } else {
+ _generate_node(state, n->children[i], node, p_owner, skeletons);
+ }
+ }
+}
+
+void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, int p_parent_bone) {
+ ERR_FAIL_INDEX(p_node, state.nodes.size());
+
+ GLTFNode *n = state.nodes[p_node];
+
+ ERR_FAIL_COND(n->joint_skin < 0);
+
+ int bone_index = skeletons[n->joint_skin]->get_bone_count();
+ skeletons[n->joint_skin]->add_bone(n->name);
+ if (p_parent_bone >= 0) {
+ skeletons[n->joint_skin]->set_bone_parent(bone_index, p_parent_bone);
+ }
+ skeletons[n->joint_skin]->set_bone_rest(bone_index, state.skins[n->joint_skin].bones[n->joint_bone].inverse_bind.affine_inverse());
+
+ for (int i = 0; i < n->children.size(); i++) {
+ ERR_CONTINUE(state.nodes[n->children[i]]->joint_skin < 0);
+ _generate_bone(state, n->children[i], skeletons, bone_index);
+ }
+}
+
+Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state) {
+
+ Spatial *root = memnew(Spatial);
+ root->set_name(state.scene_name);
+ //generate skeletons
+ Vector<Skeleton *> skeletons;
+ for (int i = 0; i < state.skins.size(); i++) {
+ Skeleton *s = memnew(Skeleton);
+ String name = state.skins[i].name;
+ if (name == "") {
+ name = _gen_unique_name(state, "Skeleton");
+ }
+ s->set_name(name);
+ root->add_child(s);
+ s->set_owner(root);
+ skeletons.push_back(s);
+ }
+ for (int i = 0; i < state.root_nodes.size(); i++) {
+ if (state.nodes[state.root_nodes[i]]->joint_skin >= 0) {
+ _generate_bone(state, state.root_nodes[i], skeletons, -1);
+ } else {
+ _generate_node(state, state.root_nodes[i], root, root, skeletons);
+ }
+ }
+
+ for (int i = 0; i < skeletons.size(); i++) {
+ skeletons[i]->localize_rests();
+ }
+
+ return root;
+}
+
+Node *EditorSceneImporterGLTF::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
+
+ GLTFState state;
+ Error err = _parse_json(p_path, state);
+ if (err)
+ return NULL;
+
+ ERR_FAIL_COND_V(!state.json.has("asset"), NULL);
+
+ Dictionary asset = state.json["asset"];
+
+ ERR_FAIL_COND_V(!asset.has("version"), NULL);
+
+ String version = asset["version"];
+
+ state.major_version = version.get_slice(".", 0).to_int();
+ state.minor_version = version.get_slice(".", 1).to_int();
+
+ /* STEP 0 PARSE SCENE */
+ err = _parse_scenes(state);
+ if (err != OK)
+ return NULL;
+
+ /* STEP 1 PARSE NODES */
+ err = _parse_nodes(state);
+ if (err != OK)
+ return NULL;
+
+ /* STEP 2 PARSE BUFFERS */
+ err = _parse_buffers(state, p_path.get_base_dir());
+ if (err != OK)
+ return NULL;
+
+ /* STEP 3 PARSE BUFFER VIEWS */
+ err = _parse_buffer_views(state);
+ if (err != OK)
+ return NULL;
+
+ /* STEP 4 PARSE ACCESSORS */
+ err = _parse_accessors(state);
+ if (err != OK)
+ return NULL;
+
+ /* STEP 5 PARSE IMAGES */
+ err = _parse_images(state, p_path.get_base_dir());
+ if (err != OK)
+ return NULL;
+
+ /* STEP 6 PARSE TEXTURES */
+ err = _parse_textures(state);
+ if (err != OK)
+ return NULL;
+
+ /* STEP 7 PARSE TEXTURES */
+ err = _parse_materials(state);
+ if (err != OK)
+ return NULL;
+
+ /* STEP 8 PARSE MESHES (we have enough info now) */
+ err = _parse_meshes(state);
+ if (err != OK)
+ return NULL;
+
+ /* STEP 9 PARSE SKINS */
+ err = _parse_skins(state);
+ if (err != OK)
+ return NULL;
+
+ /* STEP 10 PARSE CAMERAS */
+ err = _parse_cameras(state);
+ if (err != OK)
+ return NULL;
+
+ _assign_scene_names(state);
+
+ Spatial *scene = _generate_scene(state);
+
+ return scene;
+}
+
+Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path, uint32_t p_flags) {
+
+ return Ref<Animation>();
+}
+
+EditorSceneImporterGLTF::EditorSceneImporterGLTF() {
+}
diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h
new file mode 100644
index 0000000000..ab6dc6939a
--- /dev/null
+++ b/editor/import/editor_scene_importer_gltf.h
@@ -0,0 +1,258 @@
+#ifndef EDITOR_SCENE_IMPORTER_GLTF_H
+#define EDITOR_SCENE_IMPORTER_GLTF_H
+
+#include "editor/import/resource_importer_scene.h"
+#include "scene/3d/skeleton.h"
+#include "scene/3d/spatial.h"
+
+class EditorSceneImporterGLTF : public EditorSceneImporter {
+
+ GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter);
+
+ enum {
+ ARRAY_BUFFER = 34962,
+ ELEMENT_ARRAY_BUFFER = 34963,
+
+ TYPE_BYTE = 5120,
+ TYPE_UNSIGNED_BYTE = 5121,
+ TYPE_SHORT = 5122,
+ TYPE_UNSIGNED_SHORT = 5123,
+ TYPE_UNSIGNED_INT = 5125,
+ TYPE_FLOAT = 5126,
+
+ COMPONENT_TYPE_BYTE = 5120,
+ COMPONENT_TYPE_UNSIGNED_BYTE = 5121,
+ COMPONENT_TYPE_SHORT = 5122,
+ COMPONENT_TYPE_UNSIGNED_SHORT = 5123,
+ COMPONENT_TYPE_INT = 5125,
+ COMPONENT_TYPE_FLOAT = 5126,
+
+ };
+
+ String _get_component_type_name(uint32_t p_component);
+ int _get_component_type_size(int component_type);
+
+ enum GLTFType {
+ TYPE_SCALAR,
+ TYPE_VEC2,
+ TYPE_VEC3,
+ TYPE_VEC4,
+ TYPE_MAT2,
+ TYPE_MAT3,
+ TYPE_MAT4,
+ };
+
+ String _get_type_name(GLTFType p_component);
+
+ struct GLTFNode {
+ //matrices need to be transformed to this
+ int parent;
+
+ Transform xform;
+ String name;
+
+ int mesh;
+ int camera;
+ int skin;
+ int skeleton_skin;
+ int child_of_skeleton; // put as children of skeleton
+ Vector<int> skeleton_children; //skeleton put as children of this
+
+ int joint_skin;
+ int joint_bone;
+
+ //keep them for animation
+ Vector3 translation;
+ Quat rotation;
+ Vector3 scale;
+
+ Vector<int> children;
+
+ GLTFNode() {
+ joint_skin = -1;
+ joint_bone = -1;
+ child_of_skeleton = -1;
+ skeleton_skin = -1;
+ mesh = -1;
+ camera = -1;
+ parent = -1;
+ scale = Vector3(1, 1, 1);
+ }
+ };
+
+ struct GLTFBufferView {
+
+ int buffer;
+ int byte_offset;
+ int byte_length;
+ int byte_stride;
+ bool indices;
+ //matrices need to be transformed to this
+
+ GLTFBufferView() {
+ buffer = 0;
+ byte_offset = 0;
+ byte_length = 0;
+ byte_stride = 0;
+ indices = false;
+ }
+ };
+
+ struct GLTFAccessor {
+
+ int buffer_view;
+ int byte_offset;
+ int component_type;
+ bool normalized;
+ int count;
+ GLTFType type;
+ float min;
+ float max;
+ int sparse_count;
+ int sparse_indices_buffer_view;
+ int sparse_indices_byte_offset;
+ int sparse_indices_component_type;
+ int sparse_values_buffer_view;
+ int sparse_values_byte_offset;
+
+ //matrices need to be transformed to this
+
+ GLTFAccessor() {
+ buffer_view = 0;
+ byte_offset = 0;
+ component_type = 0;
+ normalized = false;
+ count = 0;
+ min = 0;
+ max = 0;
+ sparse_count = 0;
+ sparse_indices_byte_offset = 0;
+ sparse_values_byte_offset = 0;
+ }
+ };
+ struct GLTFTexture {
+ int src_image;
+ };
+
+ struct GLTFSkin {
+
+ String name;
+ struct Bone {
+ Transform inverse_bind;
+ int node;
+ };
+
+ int skeleton;
+ Vector<Bone> bones;
+
+ //matrices need to be transformed to this
+
+ GLTFSkin() {
+ skeleton = -1;
+ }
+ };
+
+ struct GLTFMesh {
+ Ref<ArrayMesh> mesh;
+ Vector<float> blend_weights;
+ };
+
+ struct GLTFCamera {
+
+ bool perspective;
+ float fov_size;
+ float zfar;
+ float znear;
+
+ GLTFCamera() {
+ perspective = true;
+ fov_size = 65;
+ zfar = 500;
+ znear = 0.1;
+ }
+ };
+
+ struct GLTFState {
+
+ Dictionary json;
+ int major_version;
+ int minor_version;
+ Vector<uint8_t> gfb_data;
+
+ Vector<GLTFNode *> nodes;
+ Vector<Vector<uint8_t> > buffers;
+ Vector<GLTFBufferView> buffer_views;
+ Vector<GLTFAccessor> accessors;
+
+ Vector<GLTFMesh> meshes; //meshes are loaded directly, no reason not to.
+ Vector<Ref<Material> > materials;
+
+ String scene_name;
+ Vector<int> root_nodes;
+
+ Vector<GLTFTexture> textures;
+ Vector<Ref<Texture> > images;
+
+ Vector<GLTFSkin> skins;
+ Vector<GLTFCamera> cameras;
+
+ Set<String> unique_names;
+
+ Map<int, Vector<int> > skin_users; //cache skin users
+
+ ~GLTFState() {
+ for (int i = 0; i < nodes.size(); i++) {
+ memdelete(nodes[i]);
+ }
+ }
+ };
+
+ String _gen_unique_name(GLTFState &state, const String &p_name);
+
+ Ref<Texture> _get_texture(GLTFState &state, int p_texture);
+
+ Error _parse_json(const String &p_path, GLTFState &state);
+
+ Error _parse_scenes(GLTFState &state);
+ Error _parse_nodes(GLTFState &state);
+ Error _parse_buffers(GLTFState &state, const String &p_base_path);
+ Error _parse_buffer_views(GLTFState &state);
+ GLTFType _get_type_from_str(const String &p_string);
+ Error _parse_accessors(GLTFState &state);
+ Error _decode_buffer_view(GLTFState &state, int p_buffer_view, double *dst, int skip_every, int skip_bytes, int element_size, int count, GLTFType type, int component_count, int component_type, int component_size, bool normalized, int byte_offset, bool for_vertex);
+ Vector<double> _decode_accessor(GLTFState &state, int p_accessor, bool p_for_vertex);
+ PoolVector<float> _decode_accessor_as_floats(GLTFState &state, int p_accessor, bool p_for_vertex);
+ PoolVector<int> _decode_accessor_as_ints(GLTFState &state, int p_accessor, bool p_for_vertex);
+ PoolVector<Vector2> _decode_accessor_as_vec2(GLTFState &state, int p_accessor, bool p_for_vertex);
+ PoolVector<Vector3> _decode_accessor_as_vec3(GLTFState &state, int p_accessor, bool p_for_vertex);
+ PoolVector<Color> _decode_accessor_as_color(GLTFState &state, int p_accessor, bool p_for_vertex);
+ Vector<Transform2D> _decode_accessor_as_xform2d(GLTFState &state, int p_accessor, bool p_for_vertex);
+ Vector<Basis> _decode_accessor_as_basis(GLTFState &state, int p_accessor, bool p_for_vertex);
+ Vector<Transform> _decode_accessor_as_xform(GLTFState &state, int p_accessor, bool p_for_vertex);
+
+ void _generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, int p_parent_bone);
+ void _generate_node(GLTFState &state, int p_node, Node *p_parent, Node *p_owner, Vector<Skeleton *> &skeletons);
+ Spatial *_generate_scene(GLTFState &state);
+
+ Error _parse_meshes(GLTFState &state);
+ Error _parse_images(GLTFState &state, const String &p_base_path);
+ Error _parse_textures(GLTFState &state);
+
+ Error _parse_materials(GLTFState &state);
+
+ Error _parse_skins(GLTFState &state);
+
+ Error _parse_cameras(GLTFState &state);
+
+ void _assign_scene_names(GLTFState &state);
+
+public:
+ virtual uint32_t get_import_flags() const;
+ virtual void get_extensions(List<String> *r_extensions) const;
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = NULL, Error *r_err = NULL);
+ virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags);
+
+ EditorSceneImporterGLTF();
+};
+
+#endif // EDITOR_SCENE_IMPORTER_GLTF_H
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index e260b1ea22..e3184a028e 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -634,7 +634,17 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
}
ScriptLanguage::LookupResult result;
- if (script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), p_symbol, script->get_path().get_base_dir(), base, result) == OK) {
+ if (p_symbol.is_resource_file()) {
+ List<String> scene_extensions;
+ ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
+
+ if (scene_extensions.find(p_symbol.get_extension())) {
+ EditorNode::get_singleton()->load_scene(p_symbol);
+ } else {
+ EditorNode::get_singleton()->load_resource(p_symbol);
+ }
+
+ } else if (script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), p_symbol, script->get_path().get_base_dir(), base, result) == OK) {
_goto_line(p_row);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 6d23e874df..6238cad14d 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -140,7 +140,7 @@ void ProjectSettingsEditor::_action_edited() {
add_at = "input/" + old_name;
message->set_text(TTR("Invalid action (anything goes but '/' or ':')."));
- message->popup_centered(Size2(300, 100));
+ message->popup_centered(Size2(300, 100) * EDSCALE);
return;
}
@@ -152,7 +152,7 @@ void ProjectSettingsEditor::_action_edited() {
add_at = "input/" + old_name;
message->set_text(vformat(TTR("Action '%s' already exists!"), new_name));
- message->popup_centered(Size2(300, 100));
+ message->popup_centered(Size2(300, 100) * EDSCALE);
return;
}
@@ -399,7 +399,7 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
device_index->add_item(TTR("Button 7"));
device_index->add_item(TTR("Button 8"));
device_index->add_item(TTR("Button 9"));
- device_input->popup_centered_minsize(Size2(350, 95));
+ device_input->popup_centered_minsize(Size2(350, 95) * EDSCALE);
Ref<InputEventMouseButton> mb = p_exiting_event;
if (mb.is_valid()) {
@@ -420,7 +420,7 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
String desc = _axis_names[i];
device_index->add_item(TTR("Axis") + " " + itos(i / 2) + " " + (i & 1 ? "+" : "-") + desc);
}
- device_input->popup_centered_minsize(Size2(350, 95));
+ device_input->popup_centered_minsize(Size2(350, 95) * EDSCALE);
Ref<InputEventJoypadMotion> jm = p_exiting_event;
if (jm.is_valid()) {
@@ -441,7 +441,7 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
device_index->add_item(itos(i) + ": " + String(_button_names[i]));
}
- device_input->popup_centered_minsize(Size2(350, 95));
+ device_input->popup_centered_minsize(Size2(350, 95) * EDSCALE);
Ref<InputEventJoypadButton> jb = p_exiting_event;
if (jb.is_valid()) {
@@ -835,13 +835,13 @@ void ProjectSettingsEditor::_action_add() {
String action = action_name->get_text();
if (action.find("/") != -1 || action.find(":") != -1 || action == "") {
message->set_text(TTR("Invalid action (anything goes but '/' or ':')."));
- message->popup_centered(Size2(300, 100));
+ message->popup_centered(Size2(300, 100) * EDSCALE);
return;
}
if (ProjectSettings::get_singleton()->has("input/" + action)) {
message->set_text(vformat(TTR("Action '%s' already exists!"), action));
- message->popup_centered(Size2(300, 100));
+ message->popup_centered(Size2(300, 100) * EDSCALE);
return;
}
@@ -879,7 +879,7 @@ void ProjectSettingsEditor::_save() {
Error err = ProjectSettings::get_singleton()->save();
message->set_text(err != OK ? TTR("Error saving settings.") : TTR("Settings saved OK."));
- message->popup_centered(Size2(300, 100));
+ message->popup_centered(Size2(300, 100) * EDSCALE);
}
void ProjectSettingsEditor::_settings_prop_edited(const String &p_name) {
@@ -1554,7 +1554,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
add = memnew(Button);
hbc->add_child(add);
- add->set_custom_minimum_size(Size2(150, 0));
+ add->set_custom_minimum_size(Size2(150, 0) * EDSCALE);
add->set_text(TTR("Add"));
add->connect("pressed", this, "_action_add");
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index d81161ae94..0748c43b5f 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "script_create_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor_file_system.h"
#include "io/resource_saver.h"
@@ -229,7 +230,7 @@ void ScriptCreateDialog::_lang_changed(int l) {
List<String> extensions;
// get all possible extensions for script
for (int l = 0; l < language_menu->get_item_count(); l++) {
- language->get_recognized_extensions(&extensions);
+ ScriptServer::get_language(l)->get_recognized_extensions(&extensions);
}
for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
@@ -240,8 +241,11 @@ void ScriptCreateDialog::_lang_changed(int l) {
}
}
}
- file_path->set_text(path);
+ } else {
+ path = "class" + selected_ext;
+ _path_changed(path);
}
+ file_path->set_text(path);
bool use_templates = language->is_using_templates();
template_menu->set_disabled(!use_templates);
@@ -403,9 +407,9 @@ void ScriptCreateDialog::_msg_script_valid(bool valid, const String &p_msg) {
error_label->set_text(TTR(p_msg));
if (valid) {
- error_label->add_color_override("font_color", Color(0, 1.0, 0.8, 0.8));
+ error_label->add_color_override("font_color", get_color("success_color", "Editor"));
} else {
- error_label->add_color_override("font_color", Color(1, 0.2, 0.2, 0.8));
+ error_label->add_color_override("font_color", get_color("error_color", "Editor"));
}
}
@@ -413,9 +417,9 @@ void ScriptCreateDialog::_msg_path_valid(bool valid, const String &p_msg) {
path_error_label->set_text(TTR(p_msg));
if (valid) {
- path_error_label->add_color_override("font_color", Color(0, 1.0, 0.8, 0.8));
+ path_error_label->add_color_override("font_color", get_color("success_color", "Editor"));
} else {
- path_error_label->add_color_override("font_color", Color(1, 0.4, 0.0, 0.8));
+ path_error_label->add_color_override("font_color", get_color("error_color", "Editor"));
}
}
@@ -543,19 +547,6 @@ ScriptCreateDialog::ScriptCreateDialog() {
gc = memnew(GridContainer);
gc->set_columns(2);
- /* Error Stylebox Background */
-
- StyleBoxFlat *sb = memnew(StyleBoxFlat);
- sb->set_bg_color(Color(0, 0, 0, 0.05));
- sb->set_light_color(Color(1, 1, 1, 0.05));
- sb->set_dark_color(Color(1, 1, 1, 0.05));
- sb->set_border_blend(false);
- sb->set_border_size(1);
- sb->set_default_margin(MARGIN_TOP, 10.0 * EDSCALE);
- sb->set_default_margin(MARGIN_BOTTOM, 10.0 * EDSCALE);
- sb->set_default_margin(MARGIN_LEFT, 10.0 * EDSCALE);
- sb->set_default_margin(MARGIN_RIGHT, 10.0 * EDSCALE);
-
/* Error Messages Field */
vb = memnew(VBoxContainer);
@@ -582,7 +573,7 @@ ScriptCreateDialog::ScriptCreateDialog() {
pc = memnew(PanelContainer);
pc->set_h_size_flags(Control::SIZE_FILL);
- pc->add_style_override("panel", sb);
+ pc->add_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_stylebox("bg", "Tree"));
pc->add_child(vb);
/* Margins */
diff --git a/main/main.cpp b/main/main.cpp
index 8960d85c45..ed6ed019f4 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1704,6 +1704,7 @@ void Main::cleanup() {
#endif
if (audio_server) {
+ audio_server->finish();
memdelete(audio_server);
}
diff --git a/main/performance.cpp b/main/performance.cpp
index c819e15f71..3d8e21bf33 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -117,8 +117,8 @@ float Performance::get_monitor(Monitor p_monitor) const {
case TIME_FIXED_PROCESS: return _fixed_process_time;
case MEMORY_STATIC: return Memory::get_mem_usage();
case MEMORY_DYNAMIC: return MemoryPool::total_memory;
- case MEMORY_STATIC_MAX: return MemoryPool::max_memory;
- case MEMORY_DYNAMIC_MAX: return 0;
+ case MEMORY_STATIC_MAX: return Memory::get_mem_max_usage();
+ case MEMORY_DYNAMIC_MAX: return MemoryPool::max_memory;
case MEMORY_MESSAGE_BUFFER_MAX: return MessageQueue::get_singleton()->get_max_buffer_usage();
case OBJECT_COUNT: return ObjectDB::get_object_count();
case OBJECT_RESOURCE_COUNT: return ResourceCache::get_cached_resource_count();
diff --git a/methods.py b/methods.py
index abd87c07d7..30a1f3caed 100644
--- a/methods.py
+++ b/methods.py
@@ -244,6 +244,7 @@ def build_glsl_header(filename):
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Color& p_color) { _FU GLfloat col[4]={p_color.r,p_color.g,p_color.b,p_color.a}; glUniform4fv(get_uniform(p_uniform),1,col); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector2& p_vec2) { _FU GLfloat vec2[2]={p_vec2.x,p_vec2.y}; glUniform2fv(get_uniform(p_uniform),1,vec2); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector3& p_vec3) { _FU GLfloat vec3[3]={p_vec3.x,p_vec3.y,p_vec3.z}; glUniform3fv(get_uniform(p_uniform),1,vec3); }\n\n")
+ fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Plane& p_plane) { _FU GLfloat plane[4]={p_plane.normal.x,p_plane.normal.y,p_plane.normal.z,p_plane.d}; glUniform4fv(get_uniform(p_uniform),1,plane); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b) { _FU glUniform2f(get_uniform(p_uniform),p_a,p_b); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c) { _FU glUniform3f(get_uniform(p_uniform),p_a,p_b,p_c); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c, float p_d) { _FU glUniform4f(get_uniform(p_uniform),p_a,p_b,p_c,p_d); }\n\n")
diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub
index ac13319a1d..65970d48c1 100644
--- a/modules/gdnative/SCsub
+++ b/modules/gdnative/SCsub
@@ -6,9 +6,8 @@ env.add_source_files(env.modules_sources, "*.cpp")
env.add_source_files(env.modules_sources, "godot/*.cpp")
env.Append(CPPFLAGS=['-DGDAPI_BUILT_IN'])
+env.Append(CPPPATH=['#modules/gdnative/'])
if "platform" in env and env["platform"] == "x11": # there has to be a better solution?
env.Append(LINKFLAGS=["-rdynamic"])
env.use_ptrcall = True
-
-Export('env')
diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h
index dd845cab7a..f02741f4e3 100644
--- a/modules/gdnative/gdnative.h
+++ b/modules/gdnative/gdnative.h
@@ -35,7 +35,7 @@
#include "os/thread_safe.h"
#include "resource.h"
-#include "godot/gdnative.h"
+#include <godot/gdnative.h>
class GDNativeLibrary : public Resource {
GDCLASS(GDNativeLibrary, Resource)
diff --git a/modules/gdnative/godot/array.cpp b/modules/gdnative/godot/array.cpp
index c068eecf8f..97c73dc253 100644
--- a/modules/gdnative/godot/array.cpp
+++ b/modules/gdnative/godot/array.cpp
@@ -27,7 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "array.h"
+#include <godot/array.h>
#include "core/array.h"
#include "core/os/memory.h"
diff --git a/modules/gdnative/godot/array.h b/modules/gdnative/godot/array.h
index cbdbfbdde3..158170ba0e 100644
--- a/modules/gdnative/godot/array.h
+++ b/modules/gdnative/godot/array.h
@@ -46,10 +46,10 @@ typedef struct {
} godot_array;
#endif
-#include "pool_arrays.h"
-#include "variant.h"
+#include <godot/pool_arrays.h>
+#include <godot/variant.h>
-#include "gdnative.h"
+#include <godot/gdnative.h>
void GDAPI godot_array_new(godot_array *r_dest);
void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src);
diff --git a/modules/gdnative/godot/basis.cpp b/modules/gdnative/godot/basis.cpp
index 7188215d04..5cf379b7d5 100644
--- a/modules/gdnative/godot/basis.cpp
+++ b/modules/gdnative/godot/basis.cpp
@@ -27,10 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "basis.h"
-#include "core/variant.h"
+#include <godot/basis.h>
#include "core/math/matrix3.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/basis.h b/modules/gdnative/godot/basis.h
index 79b2b45fdd..e96b8b730d 100644
--- a/modules/gdnative/godot/basis.h
+++ b/modules/gdnative/godot/basis.h
@@ -45,9 +45,9 @@ typedef struct {
} godot_basis;
#endif
-#include "gdnative.h"
-#include "quat.h"
-#include "vector3.h"
+#include <godot/gdnative.h>
+#include <godot/quat.h>
+#include <godot/vector3.h>
void GDAPI godot_basis_new_with_rows(godot_basis *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis);
void GDAPI godot_basis_new_with_axis_and_angle(godot_basis *r_dest, const godot_vector3 *p_axis, const godot_real p_phi);
diff --git a/modules/gdnative/godot/color.cpp b/modules/gdnative/godot/color.cpp
index eac966ca1f..a5ffee1e0b 100644
--- a/modules/gdnative/godot/color.cpp
+++ b/modules/gdnative/godot/color.cpp
@@ -27,10 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "color.h"
-#include "core/variant.h"
+#include <godot/color.h>
#include "core/color.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/color.h b/modules/gdnative/godot/color.h
index 77e709fbe3..2cd6b48b48 100644
--- a/modules/gdnative/godot/color.h
+++ b/modules/gdnative/godot/color.h
@@ -45,8 +45,8 @@ typedef struct {
} godot_color;
#endif
-#include "gdnative.h"
-#include "string.h"
+#include <godot/gdnative.h>
+#include <godot/string.h>
void GDAPI godot_color_new_rgba(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b, const godot_real p_a);
void GDAPI godot_color_new_rgb(godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b);
diff --git a/modules/gdnative/godot/dictionary.cpp b/modules/gdnative/godot/dictionary.cpp
index 1c0761edfd..ce402fa008 100644
--- a/modules/gdnative/godot/dictionary.cpp
+++ b/modules/gdnative/godot/dictionary.cpp
@@ -27,11 +27,11 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "dictionary.h"
-#include "core/variant.h"
+#include <godot/dictionary.h>
#include "core/dictionary.h"
#include "core/io/json.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/dictionary.h b/modules/gdnative/godot/dictionary.h
index a08deb27df..594b02b4dd 100644
--- a/modules/gdnative/godot/dictionary.h
+++ b/modules/gdnative/godot/dictionary.h
@@ -45,9 +45,9 @@ typedef struct {
} godot_dictionary;
#endif
-#include "array.h"
-#include "gdnative.h"
-#include "variant.h"
+#include <godot/array.h>
+#include <godot/gdnative.h>
+#include <godot/variant.h>
void GDAPI godot_dictionary_new(godot_dictionary *r_dest);
void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src);
diff --git a/modules/gdnative/godot/gdnative.cpp b/modules/gdnative/godot/gdnative.cpp
index 29b499ebab..4cda1f4560 100644
--- a/modules/gdnative/godot/gdnative.cpp
+++ b/modules/gdnative/godot/gdnative.cpp
@@ -27,7 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "gdnative.h"
+#include <godot/gdnative.h>
#include "class_db.h"
#include "error_macros.h"
diff --git a/modules/gdnative/godot/gdnative.h b/modules/gdnative/godot/gdnative.h
index b0343272ef..d849999079 100644
--- a/modules/gdnative/godot/gdnative.h
+++ b/modules/gdnative/godot/gdnative.h
@@ -174,72 +174,72 @@ typedef struct godot_pool_color_array godot_pool_color_array;
*/
/////// String
-#include "string.h"
+#include <godot/string.h>
////// Vector2
-#include "vector2.h"
+#include <godot/vector2.h>
////// Rect2
-#include "rect2.h"
+#include <godot/rect2.h>
////// Vector3
-#include "vector3.h"
+#include <godot/vector3.h>
////// Transform2D
-#include "transform2d.h"
+#include <godot/transform2d.h>
/////// Plane
-#include "plane.h"
+#include <godot/plane.h>
/////// Quat
-#include "quat.h"
+#include <godot/quat.h>
/////// Rect3
-#include "rect3.h"
+#include <godot/rect3.h>
/////// Basis
-#include "basis.h"
+#include <godot/basis.h>
/////// Transform
-#include "transform.h"
+#include <godot/transform.h>
/////// Color
-#include "color.h"
+#include <godot/color.h>
/////// NodePath
-#include "node_path.h"
+#include <godot/node_path.h>
/////// RID
-#include "rid.h"
+#include <godot/rid.h>
/////// Dictionary
-#include "dictionary.h"
+#include <godot/dictionary.h>
/////// Array
-#include "array.h"
+#include <godot/array.h>
// single API file for Pool*Array
-#include "pool_arrays.h"
+#include <godot/pool_arrays.h>
void GDAPI godot_object_destroy(godot_object *p_o);
////// Variant
-#include "variant.h"
+#include <godot/variant.h>
////// Singleton API
diff --git a/modules/gdnative/godot/node_path.cpp b/modules/gdnative/godot/node_path.cpp
index a9edbc8352..e718a9e55f 100644
--- a/modules/gdnative/godot/node_path.cpp
+++ b/modules/gdnative/godot/node_path.cpp
@@ -27,10 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "node_path.h"
-#include "core/variant.h"
+#include <godot/node_path.h>
#include "core/path_db.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/node_path.h b/modules/gdnative/godot/node_path.h
index 06955a052e..4d3dc4e0ee 100644
--- a/modules/gdnative/godot/node_path.h
+++ b/modules/gdnative/godot/node_path.h
@@ -45,8 +45,8 @@ typedef struct {
} godot_node_path;
#endif
-#include "gdnative.h"
-#include "string.h"
+#include <godot/gdnative.h>
+#include <godot/string.h>
void GDAPI godot_node_path_new(godot_node_path *r_dest, const godot_string *p_from);
void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src);
diff --git a/modules/gdnative/godot/plane.cpp b/modules/gdnative/godot/plane.cpp
index e9e659e5da..5c5b302345 100644
--- a/modules/gdnative/godot/plane.cpp
+++ b/modules/gdnative/godot/plane.cpp
@@ -27,10 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "plane.h"
-#include "core/variant.h"
+#include <godot/plane.h>
#include "core/math/plane.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/plane.h b/modules/gdnative/godot/plane.h
index e9e3b71e03..8519ac60c4 100644
--- a/modules/gdnative/godot/plane.h
+++ b/modules/gdnative/godot/plane.h
@@ -45,8 +45,8 @@ typedef struct {
} godot_plane;
#endif
-#include "gdnative.h"
-#include "vector3.h"
+#include <godot/gdnative.h>
+#include <godot/vector3.h>
void GDAPI godot_plane_new_with_reals(godot_plane *r_dest, const godot_real p_a, const godot_real p_b, const godot_real p_c, const godot_real p_d);
void GDAPI godot_plane_new_with_vectors(godot_plane *r_dest, const godot_vector3 *p_v1, const godot_vector3 *p_v2, const godot_vector3 *p_v3);
diff --git a/modules/gdnative/godot/pool_arrays.cpp b/modules/gdnative/godot/pool_arrays.cpp
index 6a6ee0f126..fa460be8bc 100644
--- a/modules/gdnative/godot/pool_arrays.cpp
+++ b/modules/gdnative/godot/pool_arrays.cpp
@@ -27,7 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "pool_arrays.h"
+#include <godot/pool_arrays.h>
#include "array.h"
#include "core/variant.h"
diff --git a/modules/gdnative/godot/pool_arrays.h b/modules/gdnative/godot/pool_arrays.h
index 1e2916cea9..29517d21ac 100644
--- a/modules/gdnative/godot/pool_arrays.h
+++ b/modules/gdnative/godot/pool_arrays.h
@@ -113,12 +113,12 @@ typedef struct {
} godot_pool_color_array;
#endif
-#include "array.h"
-#include "color.h"
-#include "vector2.h"
-#include "vector3.h"
+#include <godot/array.h>
+#include <godot/color.h>
+#include <godot/vector2.h>
+#include <godot/vector3.h>
-#include "gdnative.h"
+#include <godot/gdnative.h>
// byte
diff --git a/modules/gdnative/godot/quat.cpp b/modules/gdnative/godot/quat.cpp
index 6800f7fc7e..37ee4d6b15 100644
--- a/modules/gdnative/godot/quat.cpp
+++ b/modules/gdnative/godot/quat.cpp
@@ -27,10 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "quat.h"
-#include "core/variant.h"
+#include <godot/quat.h>
#include "core/math/quat.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/quat.h b/modules/gdnative/godot/quat.h
index b86cbacc62..0979653d93 100644
--- a/modules/gdnative/godot/quat.h
+++ b/modules/gdnative/godot/quat.h
@@ -45,8 +45,8 @@ typedef struct {
} godot_quat;
#endif
-#include "gdnative.h"
-#include "vector3.h"
+#include <godot/gdnative.h>
+#include <godot/vector3.h>
void GDAPI godot_quat_new(godot_quat *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z, const godot_real p_w);
void GDAPI godot_quat_new_with_axis_angle(godot_quat *r_dest, const godot_vector3 *p_axis, const godot_real p_angle);
diff --git a/modules/gdnative/godot/rect2.cpp b/modules/gdnative/godot/rect2.cpp
index 830d7bb496..023584c4f6 100644
--- a/modules/gdnative/godot/rect2.cpp
+++ b/modules/gdnative/godot/rect2.cpp
@@ -27,10 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "rect2.h"
-#include "core/variant.h"
+#include <godot/rect2.h>
#include "core/math/math_2d.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/rect2.h b/modules/gdnative/godot/rect2.h
index 7b6613d9dd..cb1ddb58cf 100644
--- a/modules/gdnative/godot/rect2.h
+++ b/modules/gdnative/godot/rect2.h
@@ -43,8 +43,8 @@ typedef struct godot_rect2 {
} godot_rect2;
#endif
-#include "gdnative.h"
-#include "vector2.h"
+#include <godot/gdnative.h>
+#include <godot/vector2.h>
void GDAPI godot_rect2_new_with_position_and_size(godot_rect2 *r_dest, const godot_vector2 *p_pos, const godot_vector2 *p_size);
void GDAPI godot_rect2_new(godot_rect2 *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_width, const godot_real p_height);
diff --git a/modules/gdnative/godot/rect3.cpp b/modules/gdnative/godot/rect3.cpp
index 0fabba5b7b..708d2987f2 100644
--- a/modules/gdnative/godot/rect3.cpp
+++ b/modules/gdnative/godot/rect3.cpp
@@ -27,10 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "rect3.h"
-#include "core/variant.h"
+#include <godot/rect3.h>
#include "core/math/rect3.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/rect3.h b/modules/gdnative/godot/rect3.h
index 638d89f76f..69279351c4 100644
--- a/modules/gdnative/godot/rect3.h
+++ b/modules/gdnative/godot/rect3.h
@@ -45,9 +45,9 @@ typedef struct {
} godot_rect3;
#endif
-#include "gdnative.h"
-#include "plane.h"
-#include "vector3.h"
+#include <godot/gdnative.h>
+#include <godot/plane.h>
+#include <godot/vector3.h>
void GDAPI godot_rect3_new(godot_rect3 *r_dest, const godot_vector3 *p_pos, const godot_vector3 *p_size);
diff --git a/modules/gdnative/godot/rid.cpp b/modules/gdnative/godot/rid.cpp
index 2b724e554d..eb9538e692 100644
--- a/modules/gdnative/godot/rid.cpp
+++ b/modules/gdnative/godot/rid.cpp
@@ -27,11 +27,11 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "rid.h"
-#include "core/variant.h"
+#include <godot/rid.h>
#include "core/resource.h"
#include "core/rid.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/rid.h b/modules/gdnative/godot/rid.h
index 92e101fd2e..ac5b5383d9 100644
--- a/modules/gdnative/godot/rid.h
+++ b/modules/gdnative/godot/rid.h
@@ -45,7 +45,7 @@ typedef struct {
} godot_rid;
#endif
-#include "gdnative.h"
+#include <godot/gdnative.h>
void GDAPI godot_rid_new(godot_rid *r_dest);
diff --git a/modules/gdnative/godot/string.cpp b/modules/gdnative/godot/string.cpp
index e54ef3655f..3573f266ac 100644
--- a/modules/gdnative/godot/string.cpp
+++ b/modules/gdnative/godot/string.cpp
@@ -27,7 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "string.h"
+#include <godot/string.h>
#include "string_db.h"
#include "ustring.h"
diff --git a/modules/gdnative/godot/string.h b/modules/gdnative/godot/string.h
index d4d6d6c1d0..9013326454 100644
--- a/modules/gdnative/godot/string.h
+++ b/modules/gdnative/godot/string.h
@@ -46,7 +46,7 @@ typedef struct {
} godot_string;
#endif
-#include "gdnative.h"
+#include <godot/gdnative.h>
void GDAPI godot_string_new(godot_string *r_dest);
void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src);
diff --git a/modules/gdnative/godot/transform.cpp b/modules/gdnative/godot/transform.cpp
index e566ed0b6e..87fee918bd 100644
--- a/modules/gdnative/godot/transform.cpp
+++ b/modules/gdnative/godot/transform.cpp
@@ -27,10 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "transform.h"
-#include "core/variant.h"
+#include <godot/transform.h>
#include "core/math/transform.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/transform.h b/modules/gdnative/godot/transform.h
index d14190ec49..30b9970f67 100644
--- a/modules/gdnative/godot/transform.h
+++ b/modules/gdnative/godot/transform.h
@@ -45,10 +45,10 @@ typedef struct {
} godot_transform;
#endif
-#include "basis.h"
-#include "gdnative.h"
-#include "variant.h"
-#include "vector3.h"
+#include <godot/basis.h>
+#include <godot/gdnative.h>
+#include <godot/variant.h>
+#include <godot/vector3.h>
void GDAPI godot_transform_new_with_axis_origin(godot_transform *r_dest, const godot_vector3 *p_x_axis, const godot_vector3 *p_y_axis, const godot_vector3 *p_z_axis, const godot_vector3 *p_origin);
void GDAPI godot_transform_new(godot_transform *r_dest, const godot_basis *p_basis, const godot_vector3 *p_origin);
diff --git a/modules/gdnative/godot/transform2d.cpp b/modules/gdnative/godot/transform2d.cpp
index 01db3f7ae0..65f9f8ee32 100644
--- a/modules/gdnative/godot/transform2d.cpp
+++ b/modules/gdnative/godot/transform2d.cpp
@@ -27,10 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "transform2d.h"
-#include "core/variant.h"
+#include <godot/transform2d.h>
#include "core/math/math_2d.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/transform2d.h b/modules/gdnative/godot/transform2d.h
index 7171e528f2..41c8ba982c 100644
--- a/modules/gdnative/godot/transform2d.h
+++ b/modules/gdnative/godot/transform2d.h
@@ -45,9 +45,9 @@ typedef struct {
} godot_transform2d;
#endif
-#include "gdnative.h"
-#include "variant.h"
-#include "vector2.h"
+#include <godot/gdnative.h>
+#include <godot/variant.h>
+#include <godot/vector2.h>
void GDAPI godot_transform2d_new(godot_transform2d *r_dest, const godot_real p_rot, const godot_vector2 *p_pos);
void GDAPI godot_transform2d_new_axis_origin(godot_transform2d *r_dest, const godot_vector2 *p_x_axis, const godot_vector2 *p_y_axis, const godot_vector2 *p_origin);
diff --git a/modules/gdnative/godot/variant.cpp b/modules/gdnative/godot/variant.cpp
index 3469058cfd..506614583c 100644
--- a/modules/gdnative/godot/variant.cpp
+++ b/modules/gdnative/godot/variant.cpp
@@ -27,7 +27,8 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "variant.h"
+#include <godot/variant.h>
+
#include "core/variant.h"
#ifdef __cplusplus
diff --git a/modules/gdnative/godot/variant.h b/modules/gdnative/godot/variant.h
index b56d5824fa..1c19d2a25b 100644
--- a/modules/gdnative/godot/variant.h
+++ b/modules/gdnative/godot/variant.h
@@ -99,25 +99,25 @@ typedef struct godot_variant_call_error {
godot_variant_type expected;
} godot_variant_call_error;
-#include "array.h"
-#include "basis.h"
-#include "color.h"
-#include "dictionary.h"
-#include "node_path.h"
-#include "plane.h"
-#include "pool_arrays.h"
-#include "quat.h"
-#include "rect2.h"
-#include "rect3.h"
-#include "rid.h"
-#include "string.h"
-#include "transform.h"
-#include "transform2d.h"
-#include "variant.h"
-#include "vector2.h"
-#include "vector3.h"
-
-#include "gdnative.h"
+#include <godot/array.h>
+#include <godot/basis.h>
+#include <godot/color.h>
+#include <godot/dictionary.h>
+#include <godot/node_path.h>
+#include <godot/plane.h>
+#include <godot/pool_arrays.h>
+#include <godot/quat.h>
+#include <godot/rect2.h>
+#include <godot/rect3.h>
+#include <godot/rid.h>
+#include <godot/string.h>
+#include <godot/transform.h>
+#include <godot/transform2d.h>
+#include <godot/variant.h>
+#include <godot/vector2.h>
+#include <godot/vector3.h>
+
+#include <godot/gdnative.h>
godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_v);
diff --git a/modules/gdnative/godot/vector2.cpp b/modules/gdnative/godot/vector2.cpp
index 6b40e31a89..05d4b1acc8 100644
--- a/modules/gdnative/godot/vector2.cpp
+++ b/modules/gdnative/godot/vector2.cpp
@@ -27,10 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "vector2.h"
-#include "core/variant.h"
+#include <godot/vector2.h>
#include "core/math/math_2d.h"
+#include "core/variant.h"
#ifdef __cplusplus
extern "C" {
diff --git a/modules/gdnative/godot/vector2.h b/modules/gdnative/godot/vector2.h
index 9934ddadbb..9db238b4fd 100644
--- a/modules/gdnative/godot/vector2.h
+++ b/modules/gdnative/godot/vector2.h
@@ -45,7 +45,7 @@ typedef struct {
} godot_vector2;
#endif
-#include "gdnative.h"
+#include <godot/gdnative.h>
void GDAPI godot_vector2_new(godot_vector2 *r_dest, const godot_real p_x, const godot_real p_y);
diff --git a/modules/gdnative/godot/vector3.cpp b/modules/gdnative/godot/vector3.cpp
index 904cdad9d0..fe27e740e2 100644
--- a/modules/gdnative/godot/vector3.cpp
+++ b/modules/gdnative/godot/vector3.cpp
@@ -27,9 +27,9 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "vector3.h"
-#include "core/variant.h"
+#include <godot/vector3.h>
+#include "core/variant.h"
#include "core/vector.h"
#ifdef __cplusplus
diff --git a/modules/gdnative/godot/vector3.h b/modules/gdnative/godot/vector3.h
index b5f8d0f49a..8aba1d9a85 100644
--- a/modules/gdnative/godot/vector3.h
+++ b/modules/gdnative/godot/vector3.h
@@ -45,8 +45,8 @@ typedef struct {
} godot_vector3;
#endif
-#include "basis.h"
-#include "gdnative.h"
+#include <godot/basis.h>
+#include <godot/gdnative.h>
typedef enum {
GODOT_VECTOR3_AXIS_X,
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index d180d5aada..da50104e26 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -76,4 +76,26 @@ void register_gdnative_types() {
void unregister_gdnative_types() {
memdelete(GDNativeCallRegistry::singleton);
+
+ // This is for printing out the sizes of the core types
+
+ /*
+ print_line(String("array:\t") + itos(sizeof(Array)));
+ print_line(String("basis:\t") + itos(sizeof(Basis)));
+ print_line(String("color:\t") + itos(sizeof(Color)));
+ print_line(String("dict:\t" ) + itos(sizeof(Dictionary)));
+ print_line(String("node_path:\t") + itos(sizeof(NodePath)));
+ print_line(String("plane:\t") + itos(sizeof(Plane)));
+ print_line(String("poolarray:\t") + itos(sizeof(PoolByteArray)));
+ print_line(String("quat:\t") + itos(sizeof(Quat)));
+ print_line(String("rect2:\t") + itos(sizeof(Rect2)));
+ print_line(String("rect3:\t") + itos(sizeof(Rect3)));
+ print_line(String("rid:\t") + itos(sizeof(RID)));
+ print_line(String("string:\t") + itos(sizeof(String)));
+ print_line(String("transform:\t") + itos(sizeof(Transform)));
+ print_line(String("transfo2D:\t") + itos(sizeof(Transform2D)));
+ print_line(String("variant:\t") + itos(sizeof(Variant)));
+ print_line(String("vector2:\t") + itos(sizeof(Vector2)));
+ print_line(String("vector3:\t") + itos(sizeof(Vector3)));
+ */
}
diff --git a/modules/nativescript/nativescript.cpp b/modules/nativescript/nativescript.cpp
index 49806a8e8c..226b5effa9 100644
--- a/modules/nativescript/nativescript.cpp
+++ b/modules/nativescript/nativescript.cpp
@@ -213,11 +213,6 @@ ScriptInstance *NativeScript::instance_create(Object *p_this) {
owners_lock->unlock();
#endif
- // try to call _init
- // we don't care if it doesn't exist, so we ignore errors.
- Variant::CallError err;
- call("_init", NULL, 0, err);
-
return nsi;
}
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 7fb3c876be..b124a1a5a8 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -141,6 +141,8 @@ if env['android_arch'] == 'armv6':
lib_arch_dir = 'armeabi'
elif env['android_arch'] == 'armv7':
lib_arch_dir = 'armeabi-v7a'
+elif env['android_arch'] == 'arm64v8':
+ lib_arch_dir = 'arm64-v8a'
elif env['android_arch'] == 'x86':
lib_arch_dir = 'x86'
else:
diff --git a/platform/android/detect.py b/platform/android/detect.py
index fae1df3f27..ad5bfb4949 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -22,7 +22,7 @@ def get_opts():
return [
('ANDROID_NDK_ROOT', 'Path to the Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),
('ndk_platform', 'Target platform (android-<api>, e.g. "android-18")', "android-18"),
- ('android_arch', 'Target architecture (armv7/armv6/x86)', "armv7"),
+ ('android_arch', 'Target architecture (armv7/armv6/arm64v8/x86)', "armv7"),
('android_neon', 'Enable NEON support (armv7 only)', "yes"),
('android_stl', 'Enable Android STL support (for modules)', "no")
]
@@ -89,7 +89,7 @@ def configure(env):
## Architecture
- if env['android_arch'] not in ['armv7', 'armv6', 'x86']:
+ if env['android_arch'] not in ['armv7', 'armv6', 'arm64v8', 'x86']:
env['android_arch'] = 'armv7'
neon_text = ""
@@ -99,18 +99,21 @@ def configure(env):
can_vectorize = True
if env['android_arch'] == 'x86':
+ env['ARCH'] = 'arch-x86'
env.extra_suffix = ".x86" + env.extra_suffix
target_subpath = "x86-4.9"
abi_subpath = "i686-linux-android"
arch_subpath = "x86"
env["x86_libtheora_opt_gcc"] = True
elif env['android_arch'] == 'armv6':
+ env['ARCH'] = 'arch-arm'
env.extra_suffix = ".armv6" + env.extra_suffix
target_subpath = "arm-linux-androideabi-4.9"
abi_subpath = "arm-linux-androideabi"
arch_subpath = "armeabi"
can_vectorize = False
elif env["android_arch"] == "armv7":
+ env['ARCH'] = 'arch-arm'
target_subpath = "arm-linux-androideabi-4.9"
abi_subpath = "arm-linux-androideabi"
arch_subpath = "armeabi-v7a"
@@ -118,6 +121,12 @@ def configure(env):
env.extra_suffix = ".armv7.neon" + env.extra_suffix
else:
env.extra_suffix = ".armv7" + env.extra_suffix
+ elif env["android_arch"] == "arm64v8":
+ env['ARCH'] = 'arch-arm64'
+ target_subpath = "aarch64-linux-android-4.9"
+ abi_subpath = "aarch64-linux-android"
+ arch_subpath = "arm64-v8a"
+ env.extra_suffix = ".armv8" + env.extra_suffix
## Build type
@@ -149,6 +158,8 @@ def configure(env):
elif (sys.platform.startswith('win')):
if (platform.machine().endswith('64')):
host_subpath = "windows-x86_64"
+ if env["android_arch"] == "arm64v8":
+ mt_link = False
else:
mt_link = False
host_subpath = "windows"
@@ -166,11 +177,6 @@ def configure(env):
env['RANLIB'] = tools_path + "/ranlib"
env['AS'] = tools_path + "/as"
- if env['android_arch'] == 'x86':
- env['ARCH'] = 'arch-x86'
- else:
- env['ARCH'] = 'arch-arm'
-
sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH']
common_opts = ['-fno-integrated-as', '-gcc-toolchain', gcc_toolchain_path]
@@ -199,6 +205,11 @@ def configure(env):
else:
env.Append(CPPFLAGS=['-mfpu=vfpv3-d16'])
+ elif env["android_arch"] == "arm64v8":
+ target_opts = ['-target', 'aarch64-none-linux-android']
+ env.Append(CPPFLAGS=['-D__ARM_ARCH_8A__'])
+ env.Append(CPPFLAGS=['-mfix-cortex-a53-835769'])
+
env.Append(CPPFLAGS=target_opts)
env.Append(CPPFLAGS=common_opts)
@@ -213,7 +224,8 @@ def configure(env):
## Link flags
env['LINKFLAGS'] = ['-shared', '--sysroot=' + sysroot, '-Wl,--warn-shared-textrel']
- env.Append(LINKFLAGS=string.split('-Wl,--fix-cortex-a8'))
+ if env["android_arch"] == "armv7":
+ env.Append(LINKFLAGS=string.split('-Wl,--fix-cortex-a8'))
env.Append(LINKFLAGS=string.split('-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now'))
env.Append(LINKFLAGS=string.split('-Wl,-soname,libgodot_android.so -Wl,--gc-sections'))
if mt_link:
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index a722cd1b8c..3c52834d92 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -219,6 +219,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
bool use_32_fb;
bool immersive;
bool export_arm;
+ bool export_arm64;
bool export_x86;
String apk_expansion_salt;
String apk_expansion_pkey;
@@ -319,6 +320,8 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant&
_signed=p_value;
else if (n=="architecture/arm")
export_arm=p_value;
+ else if (n=="architecture/arm64")
+ export_arm64=p_value;
else if (n=="architecture/x86")
export_x86=p_value;
else if (n=="screen/use_32_bits_view")
@@ -392,6 +395,8 @@ bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret)
r_ret=_signed;
else if (n=="architecture/arm")
r_ret=export_arm;
+ else if (n=="architecture/arm64")
+ r_ret=export_arm64;
else if (n=="architecture/x86")
r_ret=export_x86;
else if (n=="screen/use_32_bits_view")
@@ -1164,6 +1169,10 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
skip=true;
}
+ if (file.match("lib/arm64*/libgodot_android.so") && !export_arm64) {
+ skip = true;
+ }
+
if (file.begins_with("META-INF") && _signed) {
skip=true;
}
@@ -1801,6 +1810,7 @@ EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
immersive=true;
export_arm=true;
+ export_arm64=false;
export_x86=false;
@@ -3176,6 +3186,7 @@ public:
bool export_x86 = p_preset->get("architecture/x86");
bool export_arm = p_preset->get("architecture/arm");
+ bool export_arm64 = p_preset->get("architecture/arm64");
bool use_32_fb = p_preset->get("screen/use_32_bits_view");
bool immersive = p_preset->get("screen/immersive_mode");
@@ -3267,6 +3278,10 @@ public:
skip = true;
}
+ if (file.match("lib/arm64*/libgodot_android.so") && !export_arm64) {
+ skip = true;
+ }
+
if (file.begins_with("META-INF") && _signed) {
skip = true;
}
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index 56a27fa0e0..52ff9cd562 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -190,7 +190,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
argv[i].i = *p_args[i];
} break;
case ARG_TYPE_LONG: {
- argv[i].j = *p_args[i];
+ argv[i].j = (int64_t)*p_args[i];
} break;
case ARG_TYPE_FLOAT: {
argv[i].f = *p_args[i];
@@ -350,7 +350,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
Array arr = *p_args[i];
jlongArray a = env->NewLongArray(arr.size());
for (int j = 0; j < arr.size(); j++) {
- jlong val = arr[j];
+ jlong val = (int64_t)arr[j];
env->SetLongArrayRegion(a, j, 1, &val);
}
argv[i].l = a;
@@ -460,9 +460,9 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
case ARG_TYPE_LONG: {
if (method->_static) {
- ret = env->CallStaticLongMethodA(_class, method->method, argv);
+ ret = (int64_t)env->CallStaticLongMethodA(_class, method->method, argv);
} else {
- ret = env->CallLongMethodA(p_instance->instance, method->method, argv);
+ ret = (int64_t)env->CallLongMethodA(p_instance->instance, method->method, argv);
}
} break;
@@ -680,7 +680,7 @@ bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &va
} break;
case ARG_TYPE_LONG | ARG_NUMBER_CLASS_BIT: {
- var = env->CallLongMethod(obj, JavaClassWrapper::singleton->Long_longValue);
+ var = (int64_t)env->CallLongMethod(obj, JavaClassWrapper::singleton->Long_longValue);
return true;
} break;
@@ -802,7 +802,7 @@ bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &va
jlong val;
env->GetLongArrayRegion((jlongArray)arr, 0, 1, &val);
- ret.push_back(val);
+ ret.push_back((int64_t)val);
}
var = ret;
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 9d70b75027..02dcc7d059 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1144,6 +1144,20 @@ Array TileMap::get_used_cells() const {
return a;
}
+Array TileMap::get_used_cells_by_id(int p_id) const {
+
+ Array a;
+ for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
+
+ if (E->value().id == p_id) {
+ Vector2 p(E->key().x, E->key().y);
+ a.push_back(p);
+ }
+ }
+
+ return a;
+}
+
Rect2 TileMap::get_used_rect() { // Not const because of cache
if (used_size_cache_dirty) {
@@ -1262,6 +1276,7 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear"), &TileMap::clear);
ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMap::get_used_cells);
+ ClassDB::bind_method(D_METHOD("get_used_cells_by_id", "id"), &TileMap::get_used_cells_by_id);
ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMap::get_used_rect);
ClassDB::bind_method(D_METHOD("map_to_world", "mappos", "ignore_half_ofs"), &TileMap::map_to_world, DEFVAL(false));
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 3468854a61..082e9d1018 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -270,6 +270,7 @@ public:
bool is_y_sort_mode_enabled() const;
Array get_used_cells() const;
+ Array get_used_cells_by_id(int p_id) const;
Rect2 get_used_rect(); // Not const because of cache
void set_occluder_light_mask(int p_mask);
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
index 5f2a720748..3c99f7fb3a 100644
--- a/scene/3d/arvr_nodes.cpp
+++ b/scene/3d/arvr_nodes.cpp
@@ -98,6 +98,7 @@ void ARVRController::_notification(int p_what) {
is_active = false;
button_states = 0;
} else {
+ is_active = true;
set_transform(tracker->get_transform(true));
int joy_id = tracker->get_joy_id();
@@ -231,6 +232,118 @@ ARVRController::~ARVRController(){
////////////////////////////////////////////////////////////////////////////////////////////////////
+void ARVRAnchor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ set_process_internal(true);
+ }; break;
+ case NOTIFICATION_EXIT_TREE: {
+ set_process_internal(false);
+ }; break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ // get our ARVRServer
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL(arvr_server);
+
+ // find the tracker for our anchor
+ ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_ANCHOR, anchor_id);
+ if (tracker == NULL) {
+ // this anchor is currently not available
+ is_active = false;
+ } else {
+ is_active = true;
+ Transform transform;
+
+ // we'll need our world_scale
+ real_t world_scale = arvr_server->get_world_scale();
+
+ // get our info from our tracker
+ transform.basis = tracker->get_orientation();
+ transform.origin = tracker->get_position(); // <-- already adjusted to world scale
+
+ // our basis is scaled to the size of the plane the anchor is tracking
+ // extract the size from our basis and reset the scale
+ size = transform.basis.get_scale() * world_scale;
+ transform.basis.set_scale(Vector3(1.0, 1.0, 1.0));
+
+ // apply our reference frame and set our transform
+ set_transform(arvr_server->get_reference_frame() * transform);
+ };
+ }; break;
+ default:
+ break;
+ };
+};
+
+void ARVRAnchor::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_anchor_id", "anchor_id"), &ARVRAnchor::set_anchor_id);
+ ClassDB::bind_method(D_METHOD("get_anchor_id"), &ARVRAnchor::get_anchor_id);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id"), "set_anchor_id", "get_anchor_id");
+ ClassDB::bind_method(D_METHOD("get_anchor_name"), &ARVRAnchor::get_anchor_name);
+
+ ClassDB::bind_method(D_METHOD("get_is_active"), &ARVRAnchor::get_is_active);
+ ClassDB::bind_method(D_METHOD("get_size"), &ARVRAnchor::get_size);
+};
+
+void ARVRAnchor::set_anchor_id(int p_anchor_id) {
+ // we don't check any bounds here, this anchor may not yet be active and just be a place holder until it is.
+ anchor_id = p_anchor_id;
+};
+
+int ARVRAnchor::get_anchor_id(void) const {
+ return anchor_id;
+};
+
+Vector3 ARVRAnchor::get_size() const {
+ return size;
+};
+
+String ARVRAnchor::get_anchor_name(void) const {
+ // get our ARVRServer
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL_V(arvr_server, String());
+
+ ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_ANCHOR, anchor_id);
+ if (tracker == NULL) {
+ return String("Not connected");
+ };
+
+ return tracker->get_name();
+};
+
+bool ARVRAnchor::get_is_active() const {
+ return is_active;
+};
+
+String ARVRAnchor::get_configuration_warning() const {
+ if (!is_visible() || !is_inside_tree())
+ return String();
+
+ // must be child node of ARVROrigin!
+ ARVROrigin *origin = get_parent()->cast_to<ARVROrigin>();
+ if (origin == NULL) {
+ return TTR("ARVRAnchor must have an ARVROrigin node as its parent");
+ };
+
+ if (anchor_id == 0) {
+ return TTR("The anchor id must not be 0 or this anchor will not be bound to an actual anchor");
+ };
+
+ return String();
+};
+
+ARVRAnchor::ARVRAnchor() {
+ anchor_id = 0;
+ is_active = true;
+};
+
+ARVRAnchor::~ARVRAnchor(){
+ // nothing to do here yet for now..
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
String ARVROrigin::get_configuration_warning() const {
if (!is_visible() || !is_inside_tree())
return String();
diff --git a/scene/3d/arvr_nodes.h b/scene/3d/arvr_nodes.h
index 3dab263317..936519126b 100644
--- a/scene/3d/arvr_nodes.h
+++ b/scene/3d/arvr_nodes.h
@@ -39,7 +39,7 @@
**/
/*
- ARVRCamera is a subclass of camera which will register itself with its parent ARVROrigin and as a result is automatically positioned
+ ARVRCamera is a subclass of camera which will register itself with its parent ARVROrigin and as a result is automatically positioned
*/
class ARVRCamera : public Camera {
@@ -56,9 +56,9 @@ public:
};
/*
- ARVRController is a helper node that automatically updates it's position based on tracker data.
+ ARVRController is a helper node that automatically updates it's position based on tracker data.
- It must be a child node of our ARVROrigin node
+ It must be a child node of our ARVROrigin node
*/
class ARVRController : public Spatial {
@@ -92,6 +92,37 @@ public:
};
/*
+ ARVRAnchor is a helper node that automatically updates it's position based on anchor data, it represents a real world location.
+ It must be a child node of our ARVROrigin node
+*/
+
+class ARVRAnchor : public Spatial {
+ GDCLASS(ARVRAnchor, Spatial);
+
+private:
+ int anchor_id;
+ bool is_active;
+ Vector3 size;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_anchor_id(int p_anchor_id);
+ int get_anchor_id(void) const;
+ String get_anchor_name(void) const;
+
+ bool get_is_active() const;
+ Vector3 get_size() const;
+
+ String get_configuration_warning() const;
+
+ ARVRAnchor();
+ ~ARVRAnchor();
+};
+
+/*
ARVROrigin is special spatial node that acts as our origin point mapping our real world center of our tracking volume into our virtual world.
It is this point that you will move around the world as the player 'moves while standing still', i.e. the player moves through teleporting or controller inputs as opposed to physically moving.
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 97f49da2be..34533375b2 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -431,7 +431,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && (mb->get_button_index() == BUTTON_LEFT || (allow_rmb_select && mb->get_button_index() == BUTTON_RIGHT)) && mb->is_pressed()) {
search_string = ""; //any mousepress cancels
- Vector2 pos(mb->get_position().x, mb->get_position().y);
+ Vector2 pos = mb->get_position();
Ref<StyleBox> bg = get_stylebox("bg");
pos -= bg->get_offset();
pos.y += scroll_bar->get_value();
@@ -475,7 +475,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
if (mb->get_button_index() == BUTTON_RIGHT) {
- emit_signal("item_rmb_selected", i, Vector2(mb->get_position().x, mb->get_position().y));
+ emit_signal("item_rmb_selected", i, pos);
}
} else {
@@ -486,7 +486,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
if (items[i].selected && mb->get_button_index() == BUTTON_RIGHT) {
- emit_signal("item_rmb_selected", i, Vector2(mb->get_position().x, mb->get_position().y));
+ emit_signal("item_rmb_selected", i, pos);
} else {
bool selected = !items[i].selected;
@@ -501,7 +501,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
if (mb->get_button_index() == BUTTON_RIGHT) {
- emit_signal("item_rmb_selected", i, Vector2(mb->get_position().x, mb->get_position().y));
+ emit_signal("item_rmb_selected", i, pos);
} else if (/*select_mode==SELECT_SINGLE &&*/ mb->is_doubleclick()) {
emit_signal("item_activated", i);
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index fe76b16460..57aa72b7d0 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -55,7 +55,6 @@ void MenuButton::pressed() {
popup->set_size(Size2(size.width, 0));
popup->set_parent_rect(Rect2(Point2(gp - popup->get_global_position()), get_size()));
popup->popup();
- popup->call_deferred("grab_click_focus");
popup->set_invalidate_click_until_motion();
}
@@ -112,6 +111,7 @@ MenuButton::MenuButton() {
popup->hide();
add_child(popup);
popup->set_as_toplevel(true);
+ connect("button_up", popup, "call_deferred", make_binds("grab_click_focus"));
set_process_unhandled_key_input(true);
set_action_mode(ACTION_MODE_BUTTON_PRESS);
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 8baca50d32..2fc3204f3a 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -49,6 +49,10 @@ static bool _is_symbol(CharType c) {
return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
}
+static bool _is_whitespace(CharType c) {
+ return c == '\t' || c == ' ';
+}
+
static bool _is_char(CharType c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
@@ -2096,45 +2100,43 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
#ifdef APPLE_STYLE_KEYS
- if (k->get_alt()) {
+ if (k->get_alt() && cursor.column > 1) {
#else
if (k->get_alt()) {
scancode_handled = false;
break;
- } else if (k->get_command()) {
+ } else if (k->get_command() && cursor.column > 1) {
#endif
int line = cursor.line;
int column = cursor.column;
- bool prev_char = false;
- bool only_whitespace = true;
-
- while (only_whitespace && line > 0) {
-
- while (column > 0) {
- CharType c = text[line][column - 1];
-
- if (c != '\t' && c != ' ') {
- only_whitespace = false;
- break;
- }
+ // check if we are removing a single whitespace, if so remove it and the next char type
+ // else we just remove the whitespace
+ bool only_whitespace = false;
+ if (_is_whitespace(text[line][column - 1]) && _is_whitespace(text[line][column - 2])) {
+ only_whitespace = true;
+ } else if (_is_whitespace(text[line][column - 1])) {
+ // remove the single whitespace
+ column--;
+ }
- column--;
- }
+ // check if its a text char
+ bool only_char = (_is_text_char(text[line][column - 1]) && !only_whitespace);
- if (only_whitespace) {
- line--;
- column = text[line].length();
- }
- }
+ // if its not whitespace or char then symbol.
+ bool only_symbols = !(only_whitespace || only_char);
while (column > 0) {
- bool ischar = _is_text_char(text[line][column - 1]);
+ bool is_whitespace = _is_whitespace(text[line][column - 1]);
+ bool is_text_char = _is_text_char(text[line][column - 1]);
- if (prev_char && !ischar)
+ if (only_whitespace && !is_whitespace) {
break;
-
- prev_char = ischar;
+ } else if (only_char && !is_text_char) {
+ break;
+ } else if (only_symbols && (is_whitespace || is_text_char)) {
+ break;
+ }
column--;
}
@@ -2356,52 +2358,50 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
int next_column;
#ifdef APPLE_STYLE_KEYS
- if (k->get_alt()) {
+ if (k->get_alt() && cursor.column < curline_len - 1) {
#else
if (k->get_alt()) {
scancode_handled = false;
break;
- } else if (k->get_command()) {
+ } else if (k->get_command() && cursor.column < curline_len - 1) {
#endif
- int last_line = text.size() - 1;
int line = cursor.line;
int column = cursor.column;
- bool prev_char = false;
- bool only_whitespace = true;
-
- while (only_whitespace && line < last_line) {
-
- while (column < text[line].length()) {
- CharType c = text[line][column];
-
- if (c != '\t' && c != ' ') {
- only_whitespace = false;
- break;
- }
-
- column++;
- }
-
- if (only_whitespace) {
- line++;
- column = 0;
- }
+ // check if we are removing a single whitespace, if so remove it and the next char type
+ // else we just remove the whitespace
+ bool only_whitespace = false;
+ if (_is_whitespace(text[line][column]) && _is_whitespace(text[line][column + 1])) {
+ only_whitespace = true;
+ } else if (_is_whitespace(text[line][column])) {
+ // remove the single whitespace
+ column++;
}
- while (column < text[line].length()) {
+ // check if its a text char
+ bool only_char = (_is_text_char(text[line][column]) && !only_whitespace);
- bool ischar = _is_text_char(text[line][column]);
+ // if its not whitespace or char then symbol.
+ bool only_symbols = !(only_whitespace || only_char);
- if (prev_char && !ischar)
+ while (column < curline_len) {
+ bool is_whitespace = _is_whitespace(text[line][column]);
+ bool is_text_char = _is_text_char(text[line][column]);
+
+ if (only_whitespace && !is_whitespace) {
break;
- prev_char = ischar;
+ } else if (only_char && !is_text_char) {
+ break;
+ } else if (only_symbols && (is_whitespace || is_text_char)) {
+ break;
+ }
column++;
}
next_line = line;
next_column = column;
+
} else {
next_column = cursor.column < curline_len ? (cursor.column + 1) : 0;
}
@@ -4353,6 +4353,23 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this
+ bool inside_quotes = false;
+ int qbegin, qend;
+ for (int i = 0; i < s.length(); i++) {
+ if (s[i] == '"') {
+ if (inside_quotes) {
+ qend = i;
+ inside_quotes = false;
+ if (col >= qbegin && col <= qend) {
+ return s.substr(qbegin, qend - qbegin);
+ }
+ } else {
+ qbegin = i + 1;
+ inside_quotes = true;
+ }
+ }
+ }
+
while (beg > 0 && s[beg - 1] > 32 && (symbol == _is_symbol(s[beg - 1]))) {
beg--;
}
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 1456ab51c0..0b57841be7 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1605,7 +1605,6 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
int plus = 1;
while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text == "" && p_item->cells[i + plus].icon.is_null()) {
- plus++;
col_width += cache.hseparation;
col_width += get_column_width(i + plus);
plus++;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index f286bfb81a..3e6d80d314 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -409,6 +409,7 @@ void register_scene_types() {
ClassDB::register_class<Listener>();
ClassDB::register_class<ARVRCamera>();
ClassDB::register_class<ARVRController>();
+ ClassDB::register_class<ARVRAnchor>();
ClassDB::register_class<ARVROrigin>();
ClassDB::register_class<InterpolatedCamera>();
ClassDB::register_class<MeshInstance>();
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 24ec39afe3..5a79e49240 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -234,6 +234,14 @@ void SpatialMaterial::init_shaders() {
shader_names->grow = "grow";
+ shader_names->metallic_texture_channel = "metallic_texture_channel";
+ shader_names->roughness_texture_channel = "roughness_texture_channel";
+ shader_names->ao_texture_channel = "ao_texture_channel";
+ shader_names->clearcoat_texture_channel = "clearcoat_texture_channel";
+ shader_names->rim_texture_channel = "rim_texture_channel";
+ shader_names->depth_texture_channel = "depth_texture_channel";
+ shader_names->refraction_texture_channel = "refraction_texture_channel";
+
shader_names->texture_names[TEXTURE_ALBEDO] = "texture_albedo";
shader_names->texture_names[TEXTURE_METALLIC] = "texture_metallic";
shader_names->texture_names[TEXTURE_ROUGHNESS] = "texture_roughness";
@@ -354,7 +362,9 @@ void SpatialMaterial::_update_shader() {
code += "uniform float roughness : hint_range(0,1);\n";
code += "uniform float point_size : hint_range(0,128);\n";
code += "uniform sampler2D texture_metallic : hint_white;\n";
+ code += "uniform vec4 metallic_texture_channel;\n";
code += "uniform sampler2D texture_roughness : hint_white;\n";
+ code += "uniform vec4 roughness_texture_channel;\n";
if (billboard_mode == BILLBOARD_PARTICLES) {
code += "uniform int particles_anim_h_frames;\n";
code += "uniform int particles_anim_v_frames;\n";
@@ -371,6 +381,7 @@ void SpatialMaterial::_update_shader() {
if (features[FEATURE_REFRACTION]) {
code += "uniform sampler2D texture_refraction;\n";
code += "uniform float refraction : hint_range(-16,16);\n";
+ code += "uniform vec4 refraction_texture_channel;\n";
}
if (features[FEATURE_NORMAL_MAPPING]) {
@@ -393,6 +404,7 @@ void SpatialMaterial::_update_shader() {
}
if (features[FEATURE_AMBIENT_OCCLUSION]) {
code += "uniform sampler2D texture_ambient_occlusion : hint_white;\n";
+ code += "uniform vec4 ao_texture_channel;\n";
}
if (features[FEATURE_DETAIL]) {
@@ -617,15 +629,15 @@ void SpatialMaterial::_update_shader() {
code += "\tALBEDO = albedo.rgb * albedo_tex.rgb;\n";
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tfloat metallic_tex = triplanar_texture(texture_metallic,uv1_power_normal,uv1_world_pos).r;\n";
+ code += "\tfloat metallic_tex = dot(triplanar_texture(texture_metallic,uv1_power_normal,uv1_world_pos),metallic_texture_channel);\n";
} else {
- code += "\tfloat metallic_tex = texture(texture_metallic,base_uv).r;\n";
+ code += "\tfloat metallic_tex = dot(texture(texture_metallic,base_uv),metallic_texture_channel);\n";
}
code += "\tMETALLIC = metallic_tex * metallic;\n";
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tfloat roughness_tex = triplanar_texture(texture_roughness,uv1_power_normal,uv1_world_pos).r;\n";
+ code += "\tfloat roughness_tex = dot(triplanar_texture(texture_roughness,uv1_power_normal,uv1_world_pos),roughness_texture_channel);\n";
} else {
- code += "\tfloat roughness_tex = texture(texture_roughness,base_uv).r;\n";
+ code += "\tfloat roughness_tex = dot(texture(texture_roughness,base_uv),roughness_texture_channel);\n";
}
code += "\tROUGHNESS = roughness_tex * roughness;\n";
code += "\tSPECULAR = specular;\n";
@@ -656,7 +668,7 @@ void SpatialMaterial::_update_shader() {
code += "\tvec3 ref_normal = NORMAL;\n";
}
- code += "\tvec2 ref_ofs = SCREEN_UV - ref_normal.xy * texture(texture_refraction,base_uv).r * refraction;\n";
+ code += "\tvec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction,base_uv),refraction_texture_channel) * refraction;\n";
code += "\tfloat ref_amount = 1.0 - albedo.a * albedo_tex.a;\n";
code += "\tEMISSION += textureLod(SCREEN_TEXTURE,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount;\n";
code += "\tALBEDO *= 1.0 - ref_amount;\n";
@@ -699,15 +711,15 @@ void SpatialMaterial::_update_shader() {
if (features[FEATURE_AMBIENT_OCCLUSION]) {
if (flags[FLAG_AO_ON_UV2]) {
if (flags[FLAG_UV2_USE_TRIPLANAR]) {
- code += "\tAO = triplanar_texture(texture_ambient_occlusion,uv2_power_normal,uv2_world_pos).r;\n";
+ code += "\tAO = dot(triplanar_texture(texture_ambient_occlusion,uv2_power_normal,uv2_world_pos),ao_texture_channel);\n";
} else {
- code += "\tAO = texture(texture_ambient_occlusion,base_uv2).r;\n";
+ code += "\tAO = dot(texture(texture_ambient_occlusion,base_uv2),ao_texture_channel);\n";
}
} else {
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tAO = triplanar_texture(texture_ambient_occlusion,uv1_power_normal,uv1_world_pos).r;\n";
+ code += "\tAO = dot(triplanar_texture(texture_ambient_occlusion,uv1_power_normal,uv1_world_pos),ao_texture_channel);\n";
} else {
- code += "\tAO = texture(texture_ambient_occlusion,base_uv).r;\n";
+ code += "\tAO = dot(texture(texture_ambient_occlusion,base_uv),ao_texture_channel);\n";
}
}
}
@@ -1327,6 +1339,58 @@ float SpatialMaterial::get_grow() const {
return grow;
}
+static Plane _get_texture_mask(SpatialMaterial::TextureChannel p_channel) {
+ static const Plane masks[5] = {
+ Plane(1, 0, 0, 0),
+ Plane(0, 1, 0, 0),
+ Plane(0, 0, 1, 0),
+ Plane(0, 0, 0, 1),
+ Plane(0.3333333, 0.3333333, 0.3333333, 0),
+ };
+
+ return masks[p_channel];
+}
+
+void SpatialMaterial::set_metallic_texture_channel(TextureChannel p_channel) {
+
+ metallic_texture_channel = p_channel;
+ VS::get_singleton()->material_set_param(_get_material(), shader_names->metallic_texture_channel, _get_texture_mask(p_channel));
+}
+
+SpatialMaterial::TextureChannel SpatialMaterial::get_metallic_texture_channel() const {
+ return metallic_texture_channel;
+}
+
+void SpatialMaterial::set_roughness_texture_channel(TextureChannel p_channel) {
+
+ roughness_texture_channel = p_channel;
+ VS::get_singleton()->material_set_param(_get_material(), shader_names->roughness_texture_channel, _get_texture_mask(p_channel));
+}
+
+SpatialMaterial::TextureChannel SpatialMaterial::get_roughness_texture_channel() const {
+ return roughness_texture_channel;
+}
+
+void SpatialMaterial::set_ao_texture_channel(TextureChannel p_channel) {
+
+ ao_texture_channel = p_channel;
+ VS::get_singleton()->material_set_param(_get_material(), shader_names->ao_texture_channel, _get_texture_mask(p_channel));
+}
+
+SpatialMaterial::TextureChannel SpatialMaterial::get_ao_texture_channel() const {
+ return ao_texture_channel;
+}
+
+void SpatialMaterial::set_refraction_texture_channel(TextureChannel p_channel) {
+
+ refraction_texture_channel = p_channel;
+ VS::get_singleton()->material_set_param(_get_material(), shader_names->refraction_texture_channel, _get_texture_mask(p_channel));
+}
+
+SpatialMaterial::TextureChannel SpatialMaterial::get_refraction_texture_channel() const {
+ return refraction_texture_channel;
+}
+
void SpatialMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_albedo", "albedo"), &SpatialMaterial::set_albedo);
@@ -1455,6 +1519,18 @@ void SpatialMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_grow_enabled", "enable"), &SpatialMaterial::set_grow_enabled);
ClassDB::bind_method(D_METHOD("is_grow_enabled"), &SpatialMaterial::is_grow_enabled);
+ ClassDB::bind_method(D_METHOD("set_metallic_texture_channel", "channel"), &SpatialMaterial::set_metallic_texture_channel);
+ ClassDB::bind_method(D_METHOD("get_metallic_texture_channel"), &SpatialMaterial::get_metallic_texture_channel);
+
+ ClassDB::bind_method(D_METHOD("set_roughness_texture_channel", "channel"), &SpatialMaterial::set_roughness_texture_channel);
+ ClassDB::bind_method(D_METHOD("get_roughness_texture_channel"), &SpatialMaterial::get_roughness_texture_channel);
+
+ ClassDB::bind_method(D_METHOD("set_ao_texture_channel", "channel"), &SpatialMaterial::set_ao_texture_channel);
+ ClassDB::bind_method(D_METHOD("get_ao_texture_channel"), &SpatialMaterial::get_ao_texture_channel);
+
+ ClassDB::bind_method(D_METHOD("set_refraction_texture_channel", "channel"), &SpatialMaterial::set_refraction_texture_channel);
+ ClassDB::bind_method(D_METHOD("get_refraction_texture_channel"), &SpatialMaterial::get_refraction_texture_channel);
+
ADD_GROUP("Flags", "flags_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_transparent"), "set_feature", "get_feature", FEATURE_TRANSPARENT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_unshaded"), "set_flag", "get_flag", FLAG_UNSHADED);
@@ -1490,10 +1566,12 @@ void SpatialMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "metallic", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_metallic", "get_metallic");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "metallic_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_specular", "get_specular");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "metallic_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_METALLIC);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "metallic_texture_channel", PROPERTY_HINT_ENUM, "Red,Green,Blue,Alpha,Gray"), "set_metallic_texture_channel", "get_metallic_texture_channel");
ADD_GROUP("Roughness", "roughness_");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "roughness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_roughness", "get_roughness");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "roughness_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_ROUGHNESS);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "roughness_texture_channel", PROPERTY_HINT_ENUM, "Red,Green,Blue,Alpha,Gray"), "set_roughness_texture_channel", "get_roughness_texture_channel");
ADD_GROUP("Emission", "emission_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_enabled"), "set_feature", "get_feature", FEATURE_EMISSION);
@@ -1527,6 +1605,7 @@ void SpatialMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "ao_enabled"), "set_feature", "get_feature", FEATURE_AMBIENT_OCCLUSION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "ao_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_AMBIENT_OCCLUSION);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "ao_on_uv2"), "set_flag", "get_flag", FLAG_AO_ON_UV2);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "ao_texture_channel", PROPERTY_HINT_ENUM, "Red,Green,Blue,Alpha,Gray"), "set_ao_texture_channel", "get_ao_texture_channel");
ADD_GROUP("Depth", "depth_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "depth_enabled"), "set_feature", "get_feature", FEATURE_DEPTH_MAPPING);
@@ -1545,6 +1624,7 @@ void SpatialMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "refraction_enabled"), "set_feature", "get_feature", FEATURE_REFRACTION);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "refraction_scale", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_refraction", "get_refraction");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "refraction_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_REFRACTION);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "refraction_texture_channel", PROPERTY_HINT_ENUM, "Red,Green,Blue,Alpha,Gray"), "set_refraction_texture_channel", "get_refraction_texture_channel");
ADD_GROUP("Detail", "detail_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "detail_enabled"), "set_feature", "get_feature", FEATURE_DETAIL);
@@ -1638,6 +1718,12 @@ void SpatialMaterial::_bind_methods() {
BIND_CONSTANT(BILLBOARD_ENABLED);
BIND_CONSTANT(BILLBOARD_FIXED_Y);
BIND_CONSTANT(BILLBOARD_PARTICLES);
+
+ BIND_CONSTANT(TEXTURE_CHANNEL_RED);
+ BIND_CONSTANT(TEXTURE_CHANNEL_GREEN);
+ BIND_CONSTANT(TEXTURE_CHANNEL_BLUE);
+ BIND_CONSTANT(TEXTURE_CHANNEL_ALPHA);
+ BIND_CONSTANT(TEXTURE_CHANNEL_GRAYSCALE);
}
SpatialMaterial::SpatialMaterial()
@@ -1672,6 +1758,11 @@ SpatialMaterial::SpatialMaterial()
set_particles_anim_v_frames(1);
set_particles_anim_loop(false);
+ set_metallic_texture_channel(TEXTURE_CHANNEL_RED);
+ set_roughness_texture_channel(TEXTURE_CHANNEL_RED);
+ set_ao_texture_channel(TEXTURE_CHANNEL_RED);
+ set_refraction_texture_channel(TEXTURE_CHANNEL_RED);
+
grow_enabled = false;
set_grow(0.0);
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 7587fc7927..1484b79fc6 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -190,6 +190,14 @@ public:
BILLBOARD_PARTICLES,
};
+ enum TextureChannel {
+ TEXTURE_CHANNEL_RED,
+ TEXTURE_CHANNEL_GREEN,
+ TEXTURE_CHANNEL_BLUE,
+ TEXTURE_CHANNEL_ALPHA,
+ TEXTURE_CHANNEL_GRAYSCALE
+ };
+
private:
union MaterialKey {
@@ -283,6 +291,14 @@ private:
StringName uv2_blend_sharpness;
StringName grow;
+ StringName metallic_texture_channel;
+ StringName roughness_texture_channel;
+ StringName ao_texture_channel;
+ StringName clearcoat_texture_channel;
+ StringName rim_texture_channel;
+ StringName depth_texture_channel;
+ StringName refraction_texture_channel;
+
StringName texture_names[TEXTURE_MAX];
};
@@ -342,6 +358,11 @@ private:
DiffuseMode diffuse_mode;
BillboardMode billboard_mode;
+ TextureChannel metallic_texture_channel;
+ TextureChannel roughness_texture_channel;
+ TextureChannel ao_texture_channel;
+ TextureChannel refraction_texture_channel;
+
bool features[FEATURE_MAX];
Ref<Texture> textures[TEXTURE_MAX];
@@ -478,6 +499,15 @@ public:
void set_grow(float p_grow);
float get_grow() const;
+ void set_metallic_texture_channel(TextureChannel p_channel);
+ TextureChannel get_metallic_texture_channel() const;
+ void set_roughness_texture_channel(TextureChannel p_channel);
+ TextureChannel get_roughness_texture_channel() const;
+ void set_ao_texture_channel(TextureChannel p_channel);
+ TextureChannel get_ao_texture_channel() const;
+ void set_refraction_texture_channel(TextureChannel p_channel);
+ TextureChannel get_refraction_texture_channel() const;
+
static void init_shaders();
static void finish_shaders();
static void flush_changes();
@@ -496,6 +526,7 @@ VARIANT_ENUM_CAST(SpatialMaterial::Flags)
VARIANT_ENUM_CAST(SpatialMaterial::DiffuseMode)
VARIANT_ENUM_CAST(SpatialMaterial::SpecularMode)
VARIANT_ENUM_CAST(SpatialMaterial::BillboardMode)
+VARIANT_ENUM_CAST(SpatialMaterial::TextureChannel)
//////////////////////
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 8478432a04..3932917ebe 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -224,30 +224,22 @@ void SurfaceTool::add_index(int p_index) {
index_array.push_back(p_index);
}
-Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
-
- Ref<ArrayMesh> mesh;
- if (p_existing.is_valid())
- mesh = p_existing;
- else
- mesh.instance();
+Array SurfaceTool::commit_to_arrays() {
int varr_len = vertex_array.size();
- if (varr_len == 0)
- return mesh;
-
- int surface = mesh->get_surface_count();
-
Array a;
a.resize(Mesh::ARRAY_MAX);
for (int i = 0; i < Mesh::ARRAY_MAX; i++) {
- switch (format & (1 << i)) {
+ if (!(format & (1 << i)))
+ continue; //not in format
+
+ switch (i) {
- case Mesh::ARRAY_FORMAT_VERTEX:
- case Mesh::ARRAY_FORMAT_NORMAL: {
+ case Mesh::ARRAY_VERTEX:
+ case Mesh::ARRAY_NORMAL: {
PoolVector<Vector3> array;
array.resize(varr_len);
@@ -273,8 +265,8 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
} break;
- case Mesh::ARRAY_FORMAT_TEX_UV:
- case Mesh::ARRAY_FORMAT_TEX_UV2: {
+ case Mesh::ARRAY_TEX_UV:
+ case Mesh::ARRAY_TEX_UV2: {
PoolVector<Vector2> array;
array.resize(varr_len);
@@ -299,7 +291,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
w = PoolVector<Vector2>::Write();
a[i] = array;
} break;
- case Mesh::ARRAY_FORMAT_TANGENT: {
+ case Mesh::ARRAY_TANGENT: {
PoolVector<float> array;
array.resize(varr_len * 4);
@@ -323,7 +315,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
a[i] = array;
} break;
- case Mesh::ARRAY_FORMAT_COLOR: {
+ case Mesh::ARRAY_COLOR: {
PoolVector<Color> array;
array.resize(varr_len);
@@ -339,7 +331,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
w = PoolVector<Color>::Write();
a[i] = array;
} break;
- case Mesh::ARRAY_FORMAT_BONES: {
+ case Mesh::ARRAY_BONES: {
PoolVector<int> array;
array.resize(varr_len * 4);
@@ -361,7 +353,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
a[i] = array;
} break;
- case Mesh::ARRAY_FORMAT_WEIGHTS: {
+ case Mesh::ARRAY_WEIGHTS: {
PoolVector<float> array;
array.resize(varr_len * 4);
@@ -383,7 +375,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
a[i] = array;
} break;
- case Mesh::ARRAY_FORMAT_INDEX: {
+ case Mesh::ARRAY_INDEX: {
ERR_CONTINUE(index_array.size() == 0);
@@ -398,6 +390,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
}
w = PoolVector<int>::Write();
+
a[i] = array;
} break;
@@ -405,6 +398,26 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
}
}
+ return a;
+}
+
+Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing) {
+
+ Ref<ArrayMesh> mesh;
+ if (p_existing.is_valid())
+ mesh = p_existing;
+ else
+ mesh.instance();
+
+ int varr_len = vertex_array.size();
+
+ if (varr_len == 0)
+ return mesh;
+
+ int surface = mesh->get_surface_count();
+
+ Array a = commit_to_arrays();
+
mesh->add_surface_from_arrays(primitive, a);
if (material.is_valid())
mesh->surface_set_material(surface, material);
@@ -459,12 +472,17 @@ void SurfaceTool::deindex() {
vertex_array.push_back(varr[E->get()]);
}
format &= ~Mesh::ARRAY_FORMAT_INDEX;
+ index_array.clear();
}
void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) {
Array arr = p_existing->surface_get_arrays(p_surface);
ERR_FAIL_COND(arr.size() != VS::ARRAY_MAX);
+ _create_list_from_arrays(arr, r_vertex, r_index, lformat);
+}
+
+void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) {
PoolVector<Vector3> varr = arr[VS::ARRAY_VERTEX];
PoolVector<Vector3> narr = arr[VS::ARRAY_NORMAL];
@@ -536,7 +554,7 @@ void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List<
if (lformat & VS::ARRAY_FORMAT_TANGENT) {
Plane p(tarr[i * 4 + 0], tarr[i * 4 + 1], tarr[i * 4 + 2], tarr[i * 4 + 3]);
v.tangent = p.normal;
- v.binormal = p.normal.cross(last_normal).normalized() * p.d;
+ v.binormal = p.normal.cross(v.tangent).normalized() * p.d;
}
if (lformat & VS::ARRAY_FORMAT_COLOR)
v.color = carr[i];
@@ -580,6 +598,13 @@ void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List<
}
}
+void SurfaceTool::create_from_triangle_arrays(const Array &p_arrays) {
+
+ clear();
+ primitive = Mesh::PRIMITIVE_TRIANGLES;
+ _create_list_from_arrays(p_arrays, &vertex_array, &index_array, format);
+}
+
void SurfaceTool::create_from(const Ref<Mesh> &p_existing, int p_surface) {
clear();
@@ -711,8 +736,9 @@ void SurfaceTool::generate_tangents() {
ERR_FAIL_COND(!res);
format |= Mesh::ARRAY_FORMAT_TANGENT;
- if (indexed)
+ if (indexed) {
index();
+ }
}
void SurfaceTool::generate_normals() {
@@ -784,7 +810,6 @@ void SurfaceTool::generate_normals() {
vertex_hash.clear();
if (E) {
smooth = smooth_groups[count];
- print_line("SMOOTH AT " + itos(count) + ": " + itos(smooth));
}
}
}
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index 753c3626b8..d02e170b02 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -80,6 +80,7 @@ private:
Vector<float> last_weights;
Plane last_tangent;
+ void _create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, int &lformat);
void _create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, int &lformat);
//mikktspace callbacks
@@ -123,6 +124,8 @@ public:
List<Vertex> &get_vertex_array() { return vertex_array; }
+ void create_from_triangle_arrays(const Array &p_arrays);
+ Array commit_to_arrays();
void create_from(const Ref<Mesh> &p_existing, int p_surface);
void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform);
Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>());
diff --git a/servers/arvr/arvr_positional_tracker.cpp b/servers/arvr/arvr_positional_tracker.cpp
index 4215363d16..9f3d01267b 100644
--- a/servers/arvr/arvr_positional_tracker.cpp
+++ b/servers/arvr/arvr_positional_tracker.cpp
@@ -40,6 +40,13 @@ void ARVRPositionalTracker::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tracks_position"), &ARVRPositionalTracker::get_tracks_position);
ClassDB::bind_method(D_METHOD("get_position"), &ARVRPositionalTracker::get_position);
ClassDB::bind_method(D_METHOD("get_transform", "adjust_by_reference_frame"), &ARVRPositionalTracker::get_transform);
+
+ // these functions we don't want to expose to normal users but do need to be callable from GDNative
+ ClassDB::bind_method(D_METHOD("_set_type", "type"), &ARVRPositionalTracker::set_type);
+ ClassDB::bind_method(D_METHOD("_set_name", "name"), &ARVRPositionalTracker::set_name);
+ ClassDB::bind_method(D_METHOD("_set_joy_id", "joy_id"), &ARVRPositionalTracker::set_joy_id);
+ ClassDB::bind_method(D_METHOD("_set_orientation", "orientation"), &ARVRPositionalTracker::set_orientation);
+ ClassDB::bind_method(D_METHOD("_set_rw_position", "rw_position"), &ARVRPositionalTracker::set_rw_position);
};
void ARVRPositionalTracker::set_type(ARVRServer::TrackerType p_type) {
@@ -102,14 +109,36 @@ bool ARVRPositionalTracker::get_tracks_position() const {
void ARVRPositionalTracker::set_position(const Vector3 &p_position) {
_THREAD_SAFE_METHOD_
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL(arvr_server);
+ real_t world_scale = arvr_server->get_world_scale();
+ ERR_FAIL_COND(world_scale == 0);
+
tracks_position = true; // obviously we have this
- position = p_position;
+ rw_position = p_position / world_scale;
};
Vector3 ARVRPositionalTracker::get_position() const {
_THREAD_SAFE_METHOD_
- return position;
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL_V(arvr_server, rw_position);
+ real_t world_scale = arvr_server->get_world_scale();
+
+ return rw_position * world_scale;
+};
+
+void ARVRPositionalTracker::set_rw_position(const Vector3 &p_rw_position) {
+ _THREAD_SAFE_METHOD_
+
+ tracks_position = true; // obviously we have this
+ rw_position = p_rw_position;
+};
+
+Vector3 ARVRPositionalTracker::get_rw_position() const {
+ _THREAD_SAFE_METHOD_
+
+ return rw_position;
};
Transform ARVRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const {
diff --git a/servers/arvr/arvr_positional_tracker.h b/servers/arvr/arvr_positional_tracker.h
index e8c613b29d..dba203b73c 100644
--- a/servers/arvr/arvr_positional_tracker.h
+++ b/servers/arvr/arvr_positional_tracker.h
@@ -56,7 +56,7 @@ private:
bool tracks_orientation; // do we track orientation?
Basis orientation; // our orientation
bool tracks_position; // do we track position?
- Vector3 position; // our position
+ Vector3 rw_position; // our position "in the real world, so without world_scale applied"
protected:
static void _bind_methods();
@@ -73,8 +73,10 @@ public:
void set_orientation(const Basis &p_orientation);
Basis get_orientation() const;
bool get_tracks_position() const;
- void set_position(const Vector3 &p_position);
- Vector3 get_position() const;
+ void set_position(const Vector3 &p_position); // set position with world_scale applied
+ Vector3 get_position() const; // get position with world_scale applied
+ void set_rw_position(const Vector3 &p_rw_position);
+ Vector3 get_rw_position() const;
Transform get_transform(bool p_adjust_by_reference_frame) const;
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 5303aea6d0..0d2550e53b 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -66,7 +66,8 @@ void AudioDriver::audio_server_process(int p_frames, int32_t *p_buffer, bool p_u
void AudioDriver::update_mix_time(int p_frames) {
_mix_amount += p_frames;
- _last_mix_time = OS::get_singleton()->get_ticks_usec();
+ if (OS::get_singleton())
+ _last_mix_time = OS::get_singleton()->get_ticks_usec();
}
double AudioDriver::get_mix_time() const {
diff --git a/servers/physics/area_sw.h b/servers/physics/area_sw.h
index 06e58e3d5a..3dae1db13f 100644
--- a/servers/physics/area_sw.h
+++ b/servers/physics/area_sw.h
@@ -154,6 +154,7 @@ public:
_FORCE_INLINE_ void add_constraint(ConstraintSW *p_constraint) { constraints.insert(p_constraint); }
_FORCE_INLINE_ void remove_constraint(ConstraintSW *p_constraint) { constraints.erase(p_constraint); }
_FORCE_INLINE_ const Set<ConstraintSW *> &get_constraints() const { return constraints; }
+ _FORCE_INLINE_ void clear_constraints() { constraints.clear(); }
void set_monitorable(bool p_monitorable);
_FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp
index 1f32c059a8..e065fae2be 100644
--- a/servers/physics/body_sw.cpp
+++ b/servers/physics/body_sw.cpp
@@ -757,7 +757,8 @@ BodySW::BodySW()
contact_count = 0;
gravity_scale = 1.0;
-
+ linear_damp = -1;
+ angular_damp = -1;
area_angular_damp = 0;
area_linear_damp = 0;
diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h
index c3e051c2d0..512b868570 100644
--- a/servers/physics/body_sw.h
+++ b/servers/physics/body_sw.h
@@ -194,6 +194,7 @@ public:
_FORCE_INLINE_ void add_constraint(ConstraintSW *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; }
_FORCE_INLINE_ void remove_constraint(ConstraintSW *p_constraint) { constraint_map.erase(p_constraint); }
const Map<ConstraintSW *, int> &get_constraint_map() const { return constraint_map; }
+ _FORCE_INLINE_ void clear_constraint_map() { constraint_map.clear(); }
_FORCE_INLINE_ void set_omit_force_integration(bool p_omit_force_integration) { omit_force_integration = p_omit_force_integration; }
_FORCE_INLINE_ bool get_omit_force_integration() const { return omit_force_integration; }
diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp
index 101bd4b185..833c77216e 100644
--- a/servers/physics/physics_server_sw.cpp
+++ b/servers/physics/physics_server_sw.cpp
@@ -222,12 +222,24 @@ void PhysicsServerSW::area_set_space(RID p_area, RID p_space) {
AreaSW *area = area_owner.get(p_area);
ERR_FAIL_COND(!area);
+
SpaceSW *space = NULL;
if (p_space.is_valid()) {
space = space_owner.get(p_space);
ERR_FAIL_COND(!space);
}
+ if (area->get_space() == space)
+ return; //pointless
+
+ for (Set<ConstraintSW *>::Element *E = area->get_constraints().front(); E; E = E->next()) {
+ RID self = E->get()->get_self();
+ if (!self.is_valid())
+ continue;
+ free(self);
+ }
+ area->clear_constraints();
+
area->set_space(space);
};
@@ -471,15 +483,23 @@ void PhysicsServerSW::body_set_space(RID p_body, RID p_space) {
BodySW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
- SpaceSW *space = NULL;
+ SpaceSW *space = NULL;
if (p_space.is_valid()) {
space = space_owner.get(p_space);
ERR_FAIL_COND(!space);
}
if (body->get_space() == space)
- return; //pointles
+ return; //pointless
+
+ while (body->get_constraint_map().size()) {
+ RID self = body->get_constraint_map().front()->key()->get_self();
+ if (!self.is_valid())
+ continue;
+ free(self);
+ }
+ body->clear_constraint_map();
body->set_space(space);
};
@@ -1329,12 +1349,6 @@ void PhysicsServerSW::free(RID p_rid) {
body->remove_shape(0);
}
- while (body->get_constraint_map().size()) {
- RID self = body->get_constraint_map().front()->key()->get_self();
- ERR_FAIL_COND(!self.is_valid());
- free(self);
- }
-
body_owner.free(p_rid);
memdelete(body);
diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp
index 5679fc8f60..094cfa4656 100644
--- a/servers/physics/space_sw.cpp
+++ b/servers/physics/space_sw.cpp
@@ -34,12 +34,12 @@
_FORCE_INLINE_ static bool _match_object_type_query(CollisionObjectSW *p_object, uint32_t p_collision_layer, uint32_t p_type_mask) {
- if (p_object->get_type() == CollisionObjectSW::TYPE_AREA)
- return p_type_mask & PhysicsDirectSpaceState::TYPE_MASK_AREA;
-
if ((p_object->get_collision_layer() & p_collision_layer) == 0)
return false;
+ if (p_object->get_type() == CollisionObjectSW::TYPE_AREA)
+ return p_type_mask & PhysicsDirectSpaceState::TYPE_MASK_AREA;
+
BodySW *body = static_cast<BodySW *>(p_object);
return (1 << body->get_mode()) & p_type_mask;
diff --git a/servers/physics_2d/area_2d_sw.h b/servers/physics_2d/area_2d_sw.h
index 68b3c61e44..6d74a4b0f6 100644
--- a/servers/physics_2d/area_2d_sw.h
+++ b/servers/physics_2d/area_2d_sw.h
@@ -153,6 +153,7 @@ public:
_FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint) { constraints.insert(p_constraint); }
_FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint) { constraints.erase(p_constraint); }
_FORCE_INLINE_ const Set<Constraint2DSW *> &get_constraints() const { return constraints; }
+ _FORCE_INLINE_ void clear_constraints() { constraints.clear(); }
void set_monitorable(bool p_monitorable);
_FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index 9e5deef3f2..412f2f51cd 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/body_2d_sw.h
@@ -181,6 +181,7 @@ public:
_FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; }
_FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint) { constraint_map.erase(p_constraint); }
const Map<Constraint2DSW *, int> &get_constraint_map() const { return constraint_map; }
+ _FORCE_INLINE_ void clear_constraint_map() { constraint_map.clear(); }
_FORCE_INLINE_ void set_omit_force_integration(bool p_omit_force_integration) { omit_force_integration = p_omit_force_integration; }
_FORCE_INLINE_ bool get_omit_force_integration() const { return omit_force_integration; }
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
index 5b6c7e2f38..0330bfa9f3 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
@@ -203,9 +203,11 @@ void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool
if (sz.width * sz.height > large_object_min_surface) {
//unpair all elements, instead of checking all, just check what is already paired, so we at least save from checking static vs static
- for (Map<Element *, PairData *>::Element *E = p_elem->paired.front(); E; E = E->next()) {
-
+ Map<Element *, PairData *>::Element *E = p_elem->paired.front();
+ while (E) {
+ Map<Element *, PairData *>::Element *next = E->next();
_unpair_attempt(p_elem, E->key());
+ E = next;
}
if (large_elements[p_elem].dec() == 0) {
diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp
index c20d0d14a2..add376bfb2 100644
--- a/servers/physics_2d/physics_2d_server_sw.cpp
+++ b/servers/physics_2d/physics_2d_server_sw.cpp
@@ -286,12 +286,24 @@ void Physics2DServerSW::area_set_space(RID p_area, RID p_space) {
Area2DSW *area = area_owner.get(p_area);
ERR_FAIL_COND(!area);
+
Space2DSW *space = NULL;
if (p_space.is_valid()) {
space = space_owner.get(p_space);
ERR_FAIL_COND(!space);
}
+ if (area->get_space() == space)
+ return; //pointless
+
+ for (Set<Constraint2DSW *>::Element *E = area->get_constraints().front(); E; E = E->next()) {
+ RID self = E->get()->get_self();
+ if (!self.is_valid())
+ continue;
+ free(self);
+ }
+ area->clear_constraints();
+
area->set_space(space);
};
@@ -533,6 +545,17 @@ void Physics2DServerSW::body_set_space(RID p_body, RID p_space) {
ERR_FAIL_COND(!space);
}
+ if (body->get_space() == space)
+ return; //pointless
+
+ while (body->get_constraint_map().size()) {
+ RID self = body->get_constraint_map().front()->key()->get_self();
+ if (!self.is_valid())
+ continue;
+ free(self);
+ }
+ body->clear_constraint_map();
+
body->set_space(space);
};
@@ -1073,19 +1096,13 @@ void Physics2DServerSW::free(RID p_rid) {
_clear_query(body->get_direct_state_query());
*/
- body->set_space(NULL);
+ body_set_space(p_rid, RID());
while (body->get_shape_count()) {
body->remove_shape(0);
}
- while (body->get_constraint_map().size()) {
- RID self = body->get_constraint_map().front()->key()->get_self();
- ERR_FAIL_COND(!self.is_valid());
- free(self);
- }
-
body_owner.free(p_rid);
memdelete(body);
diff --git a/thirdparty/misc/base64.h b/thirdparty/misc/base64.h
index 456ef1811b..4c300382c1 100644
--- a/thirdparty/misc/base64.h
+++ b/thirdparty/misc/base64.h
@@ -11,9 +11,8 @@
extern "C" {
-uint32_t base64_encode (char* to, char* from, uint32_t len);
-uint32_t base64_decode (char* to, char* from, uint32_t len);
-
+uint32_t base64_encode(char *to, char *from, uint32_t len);
+uint32_t base64_decode(char *to, char *from, uint32_t len);
};
#endif /* BASE64_H */