summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYRIGHT.txt52
-rw-r--r--core/math/matrix3.cpp7
-rw-r--r--core/math/quick_hull.cpp2
-rw-r--r--core/math/triangle_mesh.cpp2
-rw-r--r--core/math/vector3.cpp10
-rw-r--r--core/math/vector3.h4
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp9
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp224
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h2
-rw-r--r--drivers/gles3/shaders/cubemap_filter.glsl56
-rw-r--r--drivers/gles3/shaders/scene.glsl68
-rw-r--r--editor/SCsub53
-rw-r--r--editor/editor_node.cpp160
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/import/editor_import_collada.cpp14
-rw-r--r--editor/import/resource_importer_obj.cpp2
-rw-r--r--editor/import/resource_importer_scene.cpp2
-rw-r--r--editor/plugins/curve_editor_plugin.cpp73
-rw-r--r--editor/plugins/curve_editor_plugin.h7
-rw-r--r--editor/plugins/item_list_editor_plugin.cpp40
-rw-r--r--editor/plugins/item_list_editor_plugin.h29
-rw-r--r--editor/plugins/path_editor_plugin.cpp2
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp2
-rw-r--r--editor/scene_tree_dock.cpp134
-rw-r--r--editor/scene_tree_dock.h11
-rw-r--r--editor/scene_tree_editor.cpp167
-rw-r--r--editor/scene_tree_editor.h14
-rw-r--r--editor/settings_config_dialog.cpp4
-rw-r--r--editor/spatial_editor_gizmos.cpp8
-rw-r--r--modules/gdnative/godot/godot_vector3.cpp5
-rw-r--r--modules/gdnative/godot/godot_vector3.h2
-rw-r--r--platform/osx/export/export.cpp343
-rw-r--r--platform/x11/godot_x11.cpp3
-rw-r--r--platform/x11/os_x11.cpp172
-rw-r--r--platform/x11/os_x11.h4
-rw-r--r--scene/2d/node_2d.cpp2
-rw-r--r--scene/3d/mesh_instance.cpp79
-rw-r--r--scene/3d/mesh_instance.h2
-rw-r--r--scene/3d/navigation_mesh.cpp4
-rw-r--r--scene/3d/spatial.cpp13
-rw-r--r--scene/gui/item_list.cpp46
-rw-r--r--scene/gui/item_list.h3
-rwxr-xr-xscene/main/node.cpp98
-rw-r--r--scene/main/node.h19
-rw-r--r--scene/main/scene_tree.cpp18
-rw-r--r--scene/main/scene_tree.h1
-rw-r--r--scene/resources/environment.cpp2
-rw-r--r--scene/resources/material.cpp4
-rw-r--r--scene/resources/primitive_meshes.cpp36
-rw-r--r--servers/visual_server.cpp4
50 files changed, 1489 insertions, 530 deletions
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 698e4b1dc8..84a57d2663 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -41,6 +41,7 @@ Upstream-Contact: Rémi Verschelde <contact@godotengine.org>
Source: https://github.com/godotengine/godot
Files: *
+Comment: Godot Engine
Copyright: 2007-2017, Juan Linietsky, Ariel Manzur.
2014-2017, Godot Engine contributors (cf. AUTHORS.md)
License: Expat
@@ -49,6 +50,7 @@ Files: ./icon.png
./icon.svg
./logo.png
./logo.svg
+Comment: Godot Engine logo
Copyright: Andrea Calabró
License: CC-BY-3.0
@@ -61,21 +63,25 @@ Files: ./platform/android/android_native_app_glue.c
./platform/android/java/src/org/godotengine/godot/input/InputManagerCompat.java
./platform/android/java/src/org/godotengine/godot/input/InputManagerV16.java
./platform/android/java/src/org/godotengine/godot/input/InputManagerV9.java
+Comment: The Android Open Source Project
Copyright: 2008-2013, The Android Open Source Project
License: Apache-2.0
Files: ./platform/android/cpu-features.c
./platform/android/cpu-features.h
+Comment: The Android Open Source Project
Copyright: 2010, The Android Open Source Project
License: BSD-2-clause
Files: ./platform/android/ifaddrs_android.cpp
./platform/android/ifaddrs_android.h
+Comment: The Android Open Source Project
Copyright: 2012-2013, Google Inc.
License: BSD-3-clause
Files: ./platform/android/java/src/com/android/vending/licensing/util/Base64.java
./platform/android/java/src/com/android/vending/licensing/util/Base64DecoderException.java
+Comment: The Android Open Source Project
Copyright: 2002, Google Inc.
License: Apache-2.0
@@ -83,12 +89,14 @@ Files: ./platform/android/power_android.cpp
./platform/osx/power_osx.cpp
./platform/windows/power_windows.cpp
./platform/x11/power_x11.cpp
+Comment: Simple DirectMedia Layer
Copyright: 1997-2017, Sam Lantinga
2007-2017, Juan Linietsky, Ariel Manzur.
2014-2017, Godot Engine contributors (cf. AUTHORS.md)
License: Expat and Zlib
Files: ./platform/uwp/export/export.cpp
+Comment: fb-util-for-appx
Copyright: 2016, Facebook, Inc. All rights reserved.
2007-2017, Juan Linietsky, Ariel Manzur.
2014-2017, Godot Engine contributors (cf. AUTHORS.md)
@@ -104,6 +112,7 @@ Files: ./servers/physics/gjk_epa.cpp
./servers/physics/joints/pin_joint_sw.h
./servers/physics/joints/slider_joint_sw.cpp
./servers/physics/joints/slider_joint_sw.h
+Comment: Bullet Continuous Collision Detection and Physics Library
Copyright: 2003-2008, Erwin Coumans
2007-2017, Juan Linietsky, Ariel Manzur.
2014-2017, Godot Engine contributors (cf. AUTHORS.md)
@@ -111,79 +120,97 @@ License: Expat and Zlib
Files: ./servers/physics/joints/cone_twist_joint_sw.cpp
./servers/physics/joints/cone_twist_joint_sw.h
+Comment: Bullet Continuous Collision Detection and Physics Library
Copyright: 2007, Starbreeze Studios
2007-2017, Juan Linietsky, Ariel Manzur.
2014-2017, Godot Engine contributors (cf. AUTHORS.md)
License: Expat and Zlib
Files: ./thirdparty/b2d_convexdecomp/
+Comment: Box2D (ConvexDecomp)
Copyright: 2007, Eric Jordan
Copyright: 2006-2009, Erin Catto
License: Zlib
Files: ./thirdparty/certs/ca-certificates.crt
+Comment: FIXME
Copyright: FIXME
License: FIXME
Files: ./thirdparty/enet/
+Comment: ENet
Copyright: 2002-2016, Lee Salzman
License: Expat
Files: ./thirdparty/fonts/DroidSans*.ttf
+Comment: DroidSans font
Copyright: 2008, The Android Open Source Project
License: Apache-2.0
Files: ./thirdparty/fonts/source_code_pro.otf
+Comment: Source Code Pro font
Copyright: 2010, 2012, Adobe Systems Incorporated
License: OFL-1.1
Files: ./thirdparty/freetype/
+Comment: The FreeType Project
Copyright: 1996-2016, David Turner, Robert Wilhelm, and Werner Lemberg.
License: FTL
Files: ./thirdparty/glad/
+Comment: glad
Copyright: 2013, David Herberth
License: Expat
Files: ./thirdparty/jpeg_compressor/
+Comment: jpeg-compressor
Copyright: 2012, Rich Geldreich
License: public-domain
Files: ./thirdparty/libogg/
+Comment: OggVorbis
Copyright: 2002, Xiph.org Foundation
License: BSD-3-clause
Files: ./thirdparty/libpng/
+Comment: libpng
Copyright: 1995-1996, Guy Eric Schalnat, Group 42, Inc.
1996-1997, Andreas Dilger
1998-2016, Glenn Randers-Pehrson
License: Zlib
Files: ./thirdparty/libsimplewebm/
+Comment: libsimplewebm
Copyright: 2016, Błażej Szczygieł
License: Expat
Files: ./thirdparty/libsimplewebm/libwebm/
+Comment: The WebM Project
Copyright: 2010, Google Inc.
License: BSD-3-clause
Files: ./thirdparty/libtheora/
+Comment: OggTheora
Copyright: 2002-2009, Xiph.org Foundation
License: BSD-3-clause
Files: ./thirdparty/libvorbis/
+Comment: OggVorbis
Copyright: 2002-2015, Xiph.org Foundation
License: BSD-3-clause
Files: ./thirdparty/libvpx/
+Comment: The WebM Project
Copyright: 2010, The WebM Project authors.
License: BSD-3-clause
-Files: ./thirdparty/libwebp/COPYING
+Files: ./thirdparty/libwebp/
+Comment: WebP codec
Copyright: 2010, Google Inc.
License: BSD-3-clause
Files: ./thirdparty/minizip/
+Comment: MiniZip
Copyright: 1998-2010, Gilles Vollant
2007-2008, Even Rouault
2009-2010, Mathias Svensson
@@ -193,68 +220,82 @@ Files: ./thirdparty/misc/aes256.cpp
./thirdparty/misc/aes256.h
./thirdparty/misc/sha256.c
./thirdparty/misc/sha256.h
+Comment: AES-256 and SHA-256 implementation
Copyright: 2007-2011, Ilya O. Levin
License: ISC
Files: ./thirdparty/misc/base64.c
./thirdparty/misc/base64.h
+Comment: BASE64 conversion methods
Copyright: Ari Edelkind
License: public-domain
Files: ./thirdparty/misc/curl_hostcheck.c
./thirdparty/misc/curl_hostcheck.h
+Comment: curl
Copyright: 1998-2012, Daniel Stenberg et al.
License: curl
Files: ./thirdparty/misc/fastlz.c
./thirdparty/misc/fastlz.h
+Comment: FastLZ
Copyright: 2005-2007, Ariya Hidayat
License: Expat
Files: ./thirdparty/misc/hq2x.cpp
./thirdparty/misc/hq2x.h
+Comment: hq2x implementation
Copyright: 2016, Bruno Ribeiro
License: Apache-2.0
Files: ./thirdparty/misc/md5.cpp
./thirdparty/misc/md5.h
+Comment: MD5 Message Digest Algorithm
Copyright: 1990, RSA Data Security, Inc.
License: RSA-MD
Files: ./thirdparty/misc/mikktspace.c
./thirdparty/misc/mikktspace.h
+Comment: Tangent Space Normal Maps implementation
Copyright: 2011, Morten S. Mikkelsen
License: Zlib
Files: ./thirdparty/misc/pcg.cpp
./thirdparty/misc/pcg.h
+Comment: Minimal PCG32 implementation
Copyright: 2014, M.E. O'Neill
License: Apache-2.0
Files: ./thirdparty/misc/smaz.c
./thirdparty/misc/smaz.h
+Comment: SMAZ
Copyright: 2006-2009, Salvatore Sanfilippo
License: BSD-3-clause
Files: ./thirdparty/misc/stb_truetype.h
./thirdparty/misc/stb_vorbis.c
+Comment: stb libraries
Copyright: 2007-2015, Sean Barrett
License: public-domain
Files: ./thirdparty/misc/triangulator.cpp
./thirdparty/misc/triangulator.h
+Comment: PolyPartition
Copyright: 2011, Ivan Fratric
License: Expat
Files: ./thirdparty/misc/yuv2rgb.h
+Comment: YUV2RGB
Copyright: 2008-2011, Robin Watts
License: BSD-2-clause
Files: ./thirdparty/openssl/
+Comment: The OpenSSL Project
Copyright: 1998-2016, The OpenSSL Project.
License: OpenSSL
Files: ./thirdparty/opus/
+Comment: Opus
Copyright: 2001-2011, Xiph.Org, Skype Limited, Octasic,
Jean-Marc Valin, Timothy B. Terriberry,
CSIRO, Gregory Maxwell, Mark Borgerding,
@@ -262,27 +303,28 @@ Copyright: 2001-2011, Xiph.Org, Skype Limited, Octasic,
License: BSD-3-clause
Files: ./thirdparty/pvrtccompressor/
+Comment: PvrTcCompressor
Copyright: 2014, Jeffrey Lim.
License: BSD-3-clause
-Files: ./thirdparty/rg-etc1/
-Copyright: 2012, Rich Geldreich
-License: Zlib
-
Files: ./thirdparty/rtaudio/
+Comment: RtAudio
Copyright: 2001-2016, Gary P. Scavone
License: Expat
Files: ./thirdparty/squish/
+Comment: libSquish
Copyright: 2006, Simon Brown
License: Expat
Files: ./thirdparty/tinyexr/
+Comment: TinyEXR
Copyright: 2014-2017, Syoyo Fujita
2002, Industrial Light & Magic, a division of Lucas Digital Ltd. LLC
License: BSD-3-Clause
Files: ./thirdparty/zlib/
+Comment: zlib
Copyright: 1995-2017, Jean-loup Gailly and Mark Adler
License: Zlib
diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp
index c733251c3c..b59fecc196 100644
--- a/core/math/matrix3.cpp
+++ b/core/math/matrix3.cpp
@@ -451,9 +451,10 @@ Basis::operator String() const {
}
Basis::operator Quat() const {
-#ifdef MATH_CHECKS
- ERR_FAIL_COND_V(is_rotation() == false, Quat());
-#endif
+ //commenting this check because precision issues cause it to fail when it shouldn't
+ //#ifdef MATH_CHECKS
+ //ERR_FAIL_COND_V(is_rotation() == false, Quat());
+ //#endif
real_t trace = elements[0][0] + elements[1][1] + elements[2][2];
real_t temp[4];
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index 9f594ba4fa..54b97ac38c 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -58,7 +58,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me
for (int i = 0; i < p_points.size(); i++) {
- Vector3 sp = p_points[i].snapped(0.0001);
+ Vector3 sp = p_points[i].snapped(Vector3(0.0001, 0.0001, 0.0001));
if (valid_cache.has(sp)) {
valid_points[i] = false;
//print_line("INVALIDATED: "+itos(i));
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index 08ac08d776..1df3c8c298 100644
--- a/core/math/triangle_mesh.cpp
+++ b/core/math/triangle_mesh.cpp
@@ -117,7 +117,7 @@ void TriangleMesh::create(const PoolVector<Vector3> &p_faces) {
for (int j = 0; j < 3; j++) {
int vidx = -1;
- Vector3 vs = v[j].snapped(0.0001);
+ Vector3 vs = v[j].snapped(Vector3(0.0001, 0.0001, 0.0001));
Map<Vector3, int>::Element *E = db.find(vs);
if (E) {
vidx = E->get();
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index e413cc147d..efffacb36e 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -61,13 +61,13 @@ int Vector3::max_axis() const {
return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0);
}
-void Vector3::snap(real_t p_val) {
+void Vector3::snap(Vector3 p_val) {
- x = Math::stepify(x, p_val);
- y = Math::stepify(y, p_val);
- z = Math::stepify(z, p_val);
+ x = Math::stepify(x, p_val.x);
+ y = Math::stepify(y, p_val.y);
+ z = Math::stepify(z, p_val.z);
}
-Vector3 Vector3::snapped(real_t p_val) const {
+Vector3 Vector3::snapped(Vector3 p_val) const {
Vector3 v = *this;
v.snap(p_val);
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 5f4390fbd1..7dfcedd0da 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -81,8 +81,8 @@ struct Vector3 {
_FORCE_INLINE_ void zero();
- void snap(real_t p_val);
- Vector3 snapped(real_t p_val) const;
+ void snap(Vector3 p_val);
+ Vector3 snapped(Vector3 p_val) const;
void rotate(const Vector3 &p_axis, real_t p_phi);
Vector3 rotated(const Vector3 &p_axis, real_t p_phi) const;
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 96c3da99f0..08ff51866d 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1884,14 +1884,21 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
if (p_base_env) {
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2);
- glBindTexture(GL_TEXTURE_2D, p_base_env);
+ if (storage->config.use_texture_array_environment) {
+ glBindTexture(GL_TEXTURE_2D_ARRAY, p_base_env);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, p_base_env);
+ }
state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, true);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP_ARRAY, storage->config.use_texture_array_environment);
} else {
state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP_ARRAY, false);
}
} else {
state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP_ARRAY, false);
}
state.cull_front = false;
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index b1dc32e1c0..8b86316da8 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -1275,87 +1275,200 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &sky->radiance);
- glBindTexture(GL_TEXTURE_2D, sky->radiance);
- GLuint tmp_fb;
+ if (config.use_texture_array_environment) {
- glGenFramebuffers(1, &tmp_fb);
- glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb);
+ //texture3D
+ glBindTexture(GL_TEXTURE_2D_ARRAY, sky->radiance);
- int size = p_radiance_size;
+ GLuint tmp_fb;
- int lod = 0;
+ glGenFramebuffers(1, &tmp_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb);
- int mipmaps = 6;
+ int size = p_radiance_size;
- int mm_level = mipmaps;
+ int array_level = 6;
- bool use_float = config.hdr_supported;
+ bool use_float = config.hdr_supported;
- GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2;
- GLenum format = GL_RGBA;
- GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV;
+ GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2;
+ GLenum format = GL_RGBA;
+ GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV;
- while (mm_level) {
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, internal_format, size, size * 2, array_level, 0, format, type, NULL);
- glTexImage2D(GL_TEXTURE_2D, lod, internal_format, size, size * 2, 0, format, type, NULL);
- lod++;
- mm_level--;
+ glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- if (size > 1)
- size >>= 1;
- }
+ GLuint tmp_fb2;
+ GLuint tmp_tex;
+ {
+ //generate another one for rendering, as can't read and write from a single texarray it seems
+ glGenFramebuffers(1, &tmp_fb2);
+ glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb2);
+ glGenTextures(1, &tmp_tex);
+ glBindTexture(GL_TEXTURE_2D, tmp_tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size * 2, 0, format, type, NULL);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_tex, 0);
+ glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#ifdef DEBUG_ENABLED
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
+#endif
+ }
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, lod - 1);
+ for (int j = 0; j < array_level; j++) {
- lod = 0;
- mm_level = mipmaps;
+ glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb2);
- size = p_radiance_size;
+ if (j == 0) {
- shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true);
- shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_PANORAMA, true);
- shaders.cubemap_filter.bind();
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true);
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, true);
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE, true);
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID_ARRAY, false);
+ shaders.cubemap_filter.bind();
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(texture->target, texture->tex_id);
+ } else {
- while (mm_level) {
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true);
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false);
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID_ARRAY, true);
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE, false);
+ shaders.cubemap_filter.bind();
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, sky->radiance);
+ shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::SOURCE_ARRAY_INDEX, j - 1); //read from previous to ensure better blur
+ }
+
+ for (int i = 0; i < 2; i++) {
+ glViewport(0, i * size, size, size);
+ glBindVertexArray(resources.quadie_array);
+
+ shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP, i > 0);
+ shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS, j / float(array_level - 1));
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glBindVertexArray(0);
+ }
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tmp_fb);
+ glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, sky->radiance, 0, j);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, tmp_fb2);
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glBlitFramebuffer(0, 0, size, size * 2, 0, 0, size, size * 2, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ }
+
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false);
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, false);
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_DUAL_PARABOLOID_ARRAY, false);
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE, false);
+
+ //restore ranges
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, sky->radiance);
+
+ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
+
+ glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
+ glDeleteFramebuffers(1, &tmp_fb);
+ glDeleteFramebuffers(1, &tmp_fb2);
+ glDeleteTextures(1, &tmp_tex);
+
+ } else {
+ //regular single texture with mipmaps
+ glBindTexture(GL_TEXTURE_2D, sky->radiance);
+
+ GLuint tmp_fb;
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sky->radiance, lod);
+ glGenFramebuffers(1, &tmp_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb);
+
+ int size = p_radiance_size;
+
+ int lod = 0;
+
+ int mipmaps = 6;
+
+ int mm_level = mipmaps;
+
+ bool use_float = config.hdr_supported;
+
+ GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2;
+ GLenum format = GL_RGBA;
+ GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV;
+
+ while (mm_level) {
+
+ glTexImage2D(GL_TEXTURE_2D, lod, internal_format, size, size * 2, 0, format, type, NULL);
+ lod++;
+ mm_level--;
+
+ if (size > 1)
+ size >>= 1;
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, lod - 1);
+
+ lod = 0;
+ mm_level = mipmaps;
+
+ size = p_radiance_size;
+
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, true);
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, true);
+ shaders.cubemap_filter.bind();
+
+ while (mm_level) {
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sky->radiance, lod);
#ifdef DEBUG_ENABLED
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE);
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE);
#endif
- for (int i = 0; i < 2; i++) {
- glViewport(0, i * size, size, size);
- glBindVertexArray(resources.quadie_array);
+ for (int i = 0; i < 2; i++) {
+ glViewport(0, i * size, size, size);
+ glBindVertexArray(resources.quadie_array);
- shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP, i > 0);
- shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS, lod / float(mipmaps - 1));
+ shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP, i > 0);
+ shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS, lod / float(mipmaps - 1));
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glBindVertexArray(0);
- }
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glBindVertexArray(0);
+ }
- if (size > 1)
- size >>= 1;
- lod++;
- mm_level--;
- }
- shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, false);
- shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_PANORAMA, false);
+ if (size > 1)
+ size >>= 1;
+ lod++;
+ mm_level--;
+ }
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID, false);
+ shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false);
- //restore ranges
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, lod - 1);
+ //restore ranges
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, lod - 1);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
- glDeleteFramebuffers(1, &tmp_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
+ glDeleteFramebuffers(1, &tmp_fb);
+ }
}
/* SHADER API */
@@ -6857,6 +6970,7 @@ void RasterizerStorageGLES3::initialize() {
frame.current_rt = NULL;
config.keep_original_textures = false;
config.generate_wireframes = false;
+ config.use_texture_array_environment = GLOBAL_DEF("rendering/quality/texture_array_environments", true);
}
void RasterizerStorageGLES3::finalize() {
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 3f8055d613..d317d27656 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -86,6 +86,8 @@ public:
bool generate_wireframes;
+ bool use_texture_array_environment;
+
Set<String> extensions;
bool keep_original_textures;
diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl
index 2aec6380f5..88a97a04aa 100644
--- a/drivers/gles3/shaders/cubemap_filter.glsl
+++ b/drivers/gles3/shaders/cubemap_filter.glsl
@@ -19,9 +19,16 @@ void main() {
precision highp float;
precision highp int;
-#ifdef USE_PANORAMA
+#ifdef USE_SOURCE_PANORAMA
uniform sampler2D source_panorama; //texunit:0
-#else
+#endif
+
+#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
+uniform sampler2DArray source_dual_paraboloid_array; //texunit:0
+uniform int source_array_index;
+#endif
+
+#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
uniform samplerCube source_cube; //texunit:0
#endif
@@ -169,7 +176,7 @@ vec2 Hammersley(uint i, uint N) {
uniform bool z_flip;
-#ifdef USE_PANORAMA
+#ifdef USE_SOURCE_PANORAMA
vec4 texturePanorama(vec3 normal,sampler2D pano ) {
@@ -189,6 +196,21 @@ vec4 texturePanorama(vec3 normal,sampler2D pano ) {
#endif
+#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
+
+
+vec4 textureDualParaboloidArray(vec3 normal) {
+
+ vec3 norm = normalize(normal);
+ norm.xy/=1.0+abs(norm.z);
+ norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
+ norm.y+=max(0.0,sign(-norm.z))*0.5;
+ return textureLod(source_dual_paraboloid_array, vec3(norm.xy, float(source_array_index) ), 0.0);
+
+}
+
+#endif
+
void main() {
#ifdef USE_DUAL_PARABOLOID
@@ -198,7 +220,7 @@ void main() {
N = normalize(N);
if (!z_flip) {
- N.y=-N.y; //y is flipped to improve blending between both sides
+ //N.y=-N.y; //y is flipped to improve blending between both sides
} else {
N.z=-N.z;
}
@@ -212,13 +234,24 @@ void main() {
#ifdef USE_DIRECT_WRITE
-#ifdef USE_PANORAMA
+#ifdef USE_SOURCE_PANORAMA
frag_color=vec4(texturePanorama(N,source_panorama).rgb,1.0);
-#else
+#endif
+
+#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
+
+ frag_color=vec4(textureDualParaboloidArray(N).rgb,1.0);
+#endif
+
+#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
+
frag_color=vec4(texture(N,source_cube).rgb,1.0);
#endif
+
+
+
#else
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
@@ -233,9 +266,16 @@ void main() {
float ndotl = clamp(dot(N, L),0.0,1.0);
if (ndotl>0.0) {
-#ifdef USE_PANORAMA
+#ifdef USE_SOURCE_PANORAMA
sum.rgb += texturePanorama(H,source_panorama).rgb *ndotl;
-#else
+#endif
+
+#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
+
+ sum.rgb += textureDualParaboloidArray(H).rgb *ndotl;
+#endif
+
+#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
sum.rgb += textureLod(source_cube, H, 0.0).rgb *ndotl;
#endif
sum.a += ndotl;
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 40a295bc83..f94ca6fcba 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -405,7 +405,6 @@ uniform bool no_ambient_light;
#ifdef USE_RADIANCE_MAP
-uniform sampler2D radiance_map; //texunit:-2
layout(std140) uniform Radiance { //ubo:2
@@ -415,6 +414,49 @@ layout(std140) uniform Radiance { //ubo:2
};
+#define RADIANCE_MAX_LOD 5.0
+
+#ifdef USE_RADIANCE_MAP_ARRAY
+
+uniform sampler2DArray radiance_map; //texunit:-2
+
+vec3 textureDualParaboloid(sampler2DArray p_tex, vec3 p_vec,float p_roughness) {
+
+ vec3 norm = normalize(p_vec);
+ norm.xy/=1.0+abs(norm.z);
+ norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
+
+ // we need to lie the derivatives (normg) and assume that DP side is always the same
+ // to get proper texure filtering
+ vec2 normg=norm.xy;
+ norm.y+=max(0.0,sign(norm.z))*0.5;
+
+ // thanks to OpenGL spec using floor(layer + 0.5) for texture arrays,
+ // it's easy to have precision errors using fract() to interpolate layers
+ // as such, using fixed point to ensure it works.
+
+ float index = p_roughness * RADIANCE_MAX_LOD;
+ int indexi = int(index * 256.0);
+ vec3 base = textureGrad(p_tex, vec3(norm.xy, float(indexi/256)),dFdx(normg),dFdy(normg)).xyz;
+ vec3 next = textureGrad(p_tex, vec3(norm.xy, float(indexi/256+1)),dFdx(normg),dFdy(normg)).xyz;
+ return mix(base,next,float(indexi%256)/256.0);
+}
+
+#else
+
+uniform sampler2D radiance_map; //texunit:-2
+
+vec3 textureDualParaboloid(sampler2D p_tex, vec3 p_vec,float p_roughness) {
+
+ vec3 norm = normalize(p_vec);
+ norm.xy/=1.0+abs(norm.z);
+ norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
+ norm.y+=max(0.0,sign(norm.z))*0.5;
+ return textureLod(p_tex, norm.xy, p_roughness * RADIANCE_MAX_LOD).xyz;
+}
+
+#endif
+
#endif
/* Material Uniforms */
@@ -1231,23 +1273,7 @@ void gi_probes_compute(vec3 pos, vec3 normal, float roughness, inout vec3 out_sp
#endif
-vec3 textureDualParabolod(sampler2D p_tex, vec3 p_vec,float p_lod) {
-
- vec3 norm = normalize(p_vec);
- float y_ofs=0.0;
- if (norm.z>=0.0) {
-
- norm.z+=1.0;
- y_ofs+=0.5;
- } else {
- norm.z=1.0 - norm.z;
- norm.y=-norm.y;
- }
- norm.xy/=norm.z;
- norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25+y_ofs);
- return textureLod(p_tex, norm.xy, p_lod).xyz;
-}
void main() {
@@ -1387,15 +1413,11 @@ FRAGMENT_SHADER_CODE
} else {
{
-
-#define RADIANCE_MAX_LOD 5.0
- float lod = roughness * RADIANCE_MAX_LOD;
-
{ //read radiance from dual paraboloid
vec3 ref_vec = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n);
ref_vec=normalize((radiance_inverse_xform * vec4(ref_vec,0.0)).xyz);
- vec3 radiance = textureDualParabolod(radiance_map,ref_vec,lod) * bg_energy;
+ vec3 radiance = textureDualParaboloid(radiance_map,ref_vec,roughness) * bg_energy;
specular_light = radiance;
}
@@ -1407,7 +1429,7 @@ FRAGMENT_SHADER_CODE
{
vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz);
- vec3 env_ambient=textureDualParabolod(radiance_map,ambient_dir,RADIANCE_MAX_LOD) * bg_energy;
+ vec3 env_ambient=textureDualParaboloid(radiance_map,ambient_dir,1.0) * bg_energy;
ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution);
//ambient_light=vec3(0.0,0.0,0.0);
diff --git a/editor/SCsub b/editor/SCsub
index ffdeed1523..47bdec2e0d 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -143,6 +143,9 @@ def make_translations_header(target, source, env):
def make_authors_header(target, source, env):
+ sections = ["Project Founders", "Lead Developer", "Project Manager", "Developers"]
+ sections_id = ["dev_founders", "dev_lead", "dev_manager", "dev_names"]
+
src = source[0].srcnode().abspath
dst = target[0].srcnode().abspath
f = open(src, "rb")
@@ -151,19 +154,53 @@ def make_authors_header(target, source, env):
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("#ifndef _EDITOR_AUTHORS_H\n")
g.write("#define _EDITOR_AUTHORS_H\n")
- g.write("static const char *dev_names[] = {\n")
+ current_section = ""
name_count = -1
+
+ def close_section():
+ g.write("\t0\n")
+ g.write("};\n")
+ g.write("#define " + current_section.upper() + "_COUNT " + str(name_count) + "\n")
+
for line in f:
if name_count >= 0:
if line.startswith(" "):
g.write("\t\"" + line.strip() + "\",\n")
name_count += 1
- elif line.strip() == "## Developers":
- name_count = 0
- g.write("\t0\n")
- g.write("};\n")
- g.write("#define AUTHORS_COUNT " + str(name_count) + "\n")
+ continue
+ if line.startswith("## "):
+ if name_count >= 0:
+ close_section()
+ name_count = -1
+ for i in range(len(sections)):
+ if line.strip().endswith(sections[i]):
+ current_section = sections_id[i]
+ name_count = 0
+ g.write("static const char *" + current_section + "[] = {\n")
+ break
+
+ if name_count >= 0:
+ close_section()
+
+ g.write("#endif\n")
+
+def make_license_header(target, source, env):
+
+ src = source[0].srcnode().abspath
+ dst = target[0].srcnode().abspath
+ f = open(src, "rb")
+ g = open(dst, "wb")
+
+ g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+ g.write("#ifndef _EDITOR_LICENSE_H\n")
+ g.write("#define _EDITOR_LICENSE_H\n")
+ g.write("static const char *about_license =")
+
+ for line in f:
+ g.write("\n\t\"" + line.strip().replace("\"", "\\\"") + "\\n\"")
+
+ g.write(";\n")
g.write("#endif\n")
if (env["tools"] == "yes"):
@@ -216,6 +253,10 @@ if (env["tools"] == "yes"):
env.Depends('#editor/authors.gen.h', "../AUTHORS.md")
env.Command('#editor/authors.gen.h', "../AUTHORS.md", make_authors_header)
+ # License
+ env.Depends('#editor/license.gen.h', "../LICENSE.txt")
+ env.Command('#editor/license.gen.h', "../LICENSE.txt", make_license_header)
+
env.add_source_files(env.editor_sources, "*.cpp")
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 77050acd7c..c52a133e78 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -43,6 +43,7 @@
#include "io/config_file.h"
#include "io/stream_peer_ssl.h"
#include "io/zip_io.h"
+#include "license.gen.h"
#include "main/input_default.h"
#include "message_queue.h"
#include "os/file_access.h"
@@ -416,6 +417,8 @@ void EditorNode::_fs_changed() {
}
}
}
+
+ _mark_unsaved_scenes();
}
void EditorNode::_sources_changed(bool p_exist) {
@@ -978,6 +981,29 @@ void EditorNode::_save_all_scenes() {
_save_default_environment();
}
+void EditorNode::_mark_unsaved_scenes() {
+
+ for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+
+ Node *node = editor_data.get_edited_scene_root(i);
+ if (!node)
+ continue;
+
+ String path = node->get_filename();
+ if (!(path == String() || FileAccess::exists(path))) {
+
+ node->set_filename("");
+ if (i == editor_data.get_edited_scene())
+ set_current_version(-1);
+ else
+ editor_data.set_edited_scene_version(-1, i);
+ }
+ }
+
+ _update_title();
+ _update_scene_tabs();
+}
+
void EditorNode::_import_action(const String &p_action) {
#if 0
import_confirmation->hide();
@@ -2646,7 +2672,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
OS::get_singleton()->shell_open("https://godotengine.org/community");
} break;
case HELP_ABOUT: {
- about->popup_centered_minsize(Size2(500, 130) * EDSCALE);
+ about->popup_centered_minsize(Size2(780, 500) * EDSCALE);
} break;
case SOURCES_REIMPORT: {
@@ -4392,8 +4418,14 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed() && scene_tabs->get_hovered_tab() >= 0) {
- _scene_tab_closed(scene_tabs->get_hovered_tab());
+ if (scene_tabs->get_hovered_tab() >= 0) {
+ if (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed()) {
+ _scene_tab_closed(scene_tabs->get_hovered_tab());
+ }
+ } else {
+ if ((mb->get_button_index() == BUTTON_LEFT && mb->is_doubleclick()) || (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed())) {
+ _menu_option_confirm(FILE_NEW_SCENE, true);
+ }
}
}
}
@@ -6042,52 +6074,82 @@ EditorNode::EditorNode() {
export_template_manager = memnew(ExportTemplateManager);
gui_base->add_child(export_template_manager);
- about = memnew(AcceptDialog);
- about->set_title(TTR("Thanks from the Godot community!"));
- about->get_ok()->set_text(TTR("Thanks!"));
- about->set_hide_on_ok(true);
- gui_base->add_child(about);
- VBoxContainer *vbc = memnew(VBoxContainer);
- HBoxContainer *hbc = memnew(HBoxContainer);
- hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- hbc->set_alignment(BoxContainer::ALIGN_CENTER);
- about->add_child(vbc);
- vbc->add_child(hbc);
- Label *about_text = memnew(Label);
- about_text->set_text(VERSION_FULL_NAME + String::utf8("\n\u00A9 2007-2017 Juan Linietsky, Ariel Manzur.\n\u00A9 2014-2017 ") + TTR("Godot Engine contributors") + "\n");
- TextureRect *logo = memnew(TextureRect);
- logo->set_texture(gui_base->get_icon("Logo", "EditorIcons"));
- hbc->add_child(logo);
- hbc->add_child(about_text);
- TabContainer *tc = memnew(TabContainer);
- tc->set_custom_minimum_size(Vector2(740, 300));
- vbc->add_child(tc);
- ScrollContainer *dev_base = memnew(ScrollContainer);
- dev_base->set_name(TTR("Developers"));
- tc->add_child(dev_base);
- HBoxContainer *dev_hbc = memnew(HBoxContainer);
- dev_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- dev_base->add_child(dev_hbc);
- for (int i = 0; i < 3; i++) {
- Label *dev_label = memnew(Label);
- dev_label->set_h_size_flags(Control::SIZE_EXPAND);
- dev_label->set_v_size_flags(Control::SIZE_FILL);
- dev_hbc->add_child(dev_label);
- }
- int dev_name_index = 0;
- int dev_name_column = 0;
- const int dev_index_max = AUTHORS_COUNT / 3 + (AUTHORS_COUNT % 3 == 0 ? 0 : 1);
- String dev_name = "";
- const char **dev_names_ptr = dev_names;
- while (*dev_names_ptr) {
- dev_name += String::utf8(*dev_names_ptr++);
- if (++dev_name_index == dev_index_max || !*dev_names_ptr) {
- dev_hbc->get_child(dev_name_column)->cast_to<Label>()->set_text(dev_name);
- dev_name_column++;
- dev_name = "";
- dev_name_index = 0;
- } else {
- dev_name += "\n";
+ {
+
+ about = memnew(AcceptDialog);
+ about->set_title(TTR("Thanks from the Godot community!"));
+ about->get_ok()->set_text(TTR("Thanks!"));
+ about->set_hide_on_ok(true);
+ about->set_resizable(true);
+ gui_base->add_child(about);
+
+ VBoxContainer *vbc = memnew(VBoxContainer);
+ HBoxContainer *hbc = memnew(HBoxContainer);
+ hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hbc->set_alignment(BoxContainer::ALIGN_CENTER);
+ hbc->add_constant_override("separation", 30 * EDSCALE);
+ about->add_child(vbc);
+ vbc->add_child(hbc);
+
+ TextureRect *logo = memnew(TextureRect);
+ logo->set_texture(gui_base->get_icon("Logo", "EditorIcons"));
+ hbc->add_child(logo);
+
+ Label *about_text = memnew(Label);
+ about_text->set_text(VERSION_FULL_NAME + String::utf8("\n\u00A9 2007-2017 Juan Linietsky, Ariel Manzur.\n\u00A9 2014-2017 ") +
+ TTR("Godot Engine contributors") + "\n");
+ hbc->add_child(about_text);
+
+ TabContainer *tc = memnew(TabContainer);
+ tc->set_custom_minimum_size(Size2(600, 240) * EDSCALE);
+ tc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ vbc->add_child(tc);
+
+ ScrollContainer *dev_base = memnew(ScrollContainer);
+ dev_base->set_name(TTR("Authors"));
+ dev_base->set_v_size_flags(Control::SIZE_EXPAND);
+ tc->add_child(dev_base);
+
+ TextEdit *license = memnew(TextEdit);
+ license->set_name(TTR("License"));
+ license->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ license->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ license->set_wrap(true);
+ license->set_readonly(true);
+ license->set_text(String::utf8(about_license));
+ tc->add_child(license);
+
+ VBoxContainer *dev_vbc = memnew(VBoxContainer);
+ dev_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ dev_base->add_child(dev_vbc);
+
+ List<String> dev_sections;
+ dev_sections.push_back(TTR("Project Founders"));
+ dev_sections.push_back(TTR("Lead Developer"));
+ dev_sections.push_back(TTR("Project Manager"));
+ dev_sections.push_back(TTR("Developers"));
+
+ const char **dev_src[] = { dev_founders, dev_lead, dev_manager, dev_names };
+
+ for (int i = 0; i < dev_sections.size(); i++) {
+
+ Label *lbl = memnew(Label);
+ lbl->set_text(dev_sections[i]);
+ dev_vbc->add_child(lbl);
+
+ ItemList *il = memnew(ItemList);
+ il->set_max_columns(32);
+ il->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ il->set_custom_minimum_size(Size2(0, i == 3 ? DEV_NAMES_COUNT * 7.6 : 30) * EDSCALE);
+ const char **dev_names_ptr = dev_src[i];
+ while (*dev_names_ptr)
+ il->add_item(String::utf8(*dev_names_ptr++), NULL, false);
+ dev_vbc->add_child(il);
+ il->set_fixed_column_width(240 * EDSCALE);
+
+ HSeparator *hs = memnew(HSeparator);
+ hs->set_modulate(Color(0, 0, 0, 0));
+ dev_vbc->add_child(hs);
}
}
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 5e83cec4a3..24acedbf26 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -529,6 +529,7 @@ private:
bool _find_and_save_resource(RES p_res, Map<RES, bool> &processed, int32_t flags);
bool _find_and_save_edited_subresources(Object *obj, Map<RES, bool> &processed, int32_t flags);
void _save_edited_subresources(Node *scene, Map<RES, bool> &processed, int32_t flags);
+ void _mark_unsaved_scenes();
void _find_node_types(Node *p_node, int &count_2d, int &count_3d);
void _save_scene_with_preview(String p_file);
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index e0a2ea624e..7f91cc86cf 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -554,10 +554,10 @@ static void _generate_tangents_and_binormals(const PoolVector<int> &p_indices, c
tangent = Vector3();
} else {
tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
- (t2 * z1 - t1 * z2) * r)
+ (t2 * z1 - t1 * z2) * r)
.normalized();
binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
- (s1 * z2 - s2 * z1) * r)
+ (s1 * z2 - s2 * z1) * r)
.normalized();
}
@@ -867,7 +867,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
int normal_pos = (normal_src->stride ? normal_src->stride : 3) * p.indices[src + normal_ofs];
ERR_FAIL_INDEX_V(normal_pos, normal_src->array.size(), ERR_INVALID_DATA);
vertex.normal = Vector3(normal_src->array[normal_pos + 0], normal_src->array[normal_pos + 1], normal_src->array[normal_pos + 2]);
- vertex.normal = vertex.normal.snapped(0.001);
+ vertex.normal.snap(Vector3(0.001, 0.001, 0.001));
if (tangent_src && binormal_src) {
@@ -908,12 +908,20 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
#ifndef NO_UP_AXIS_SWAP
if (collada.state.up_axis == Vector3::AXIS_Z) {
+ Vector3 bn = vertex.normal.cross(vertex.tangent.normal) * vertex.tangent.d;
+
SWAP(vertex.vertex.z, vertex.vertex.y);
vertex.vertex.z = -vertex.vertex.z;
SWAP(vertex.normal.z, vertex.normal.y);
vertex.normal.z = -vertex.normal.z;
SWAP(vertex.tangent.normal.z, vertex.tangent.normal.y);
vertex.tangent.normal.z = -vertex.tangent.normal.z;
+ SWAP(bn.z, bn.y);
+ bn.z = -bn.z;
+
+ vertex.tangent.d = vertex.normal.cross(vertex.tangent.normal).dot(bn) > 0 ? 1 : -1;
+
+ print_line("Tangent " + itos(p_i) + ": " + vertex.tangent);
}
#endif
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index 1c5aa95ff1..4a2f37e319 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -188,7 +188,7 @@ Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_s
Vector3 vertex = vertices[vtx];
if (weld_vertices)
- vertex = vertex.snapped(weld_tolerance);
+ vertex.snap(Vector3(weld_tolerance, weld_tolerance, weld_tolerance));
surf_tool->add_vertex(vertex);
}
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 2409f6707d..2ccbd36e18 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -594,7 +594,7 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Array
for (int i = 0; i < 3; i++) {
- Vector3 v = f.vertex[i].snapped(0.01);
+ Vector3 v = f.vertex[i].snapped(Vector3(0.01, 0.01, 0.01));
if (!points.has(v)) {
points.insert(v);
center += v;
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index d729bb7b76..c74eaf21a1 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -774,6 +774,8 @@ CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) {
_toggle_button = _editor_node->add_bottom_panel_item(get_name(), _view);
_toggle_button->hide();
+
+ get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator));
}
CurveEditorPlugin::~CurveEditorPlugin() {
@@ -845,3 +847,74 @@ void CurveEditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("_curve_texture_changed"), &CurveEditorPlugin::_curve_texture_changed);
}
+
+//-----------------------------------
+// Preview generator
+
+bool CurvePreviewGenerator::handles(const String &p_type) const {
+ return p_type == "Curve";
+}
+
+Ref<Texture> CurvePreviewGenerator::generate(const Ref<Resource> &p_from) {
+
+ Ref<Curve> curve_ref = p_from;
+ ERR_FAIL_COND_V(curve_ref.is_null(), Ref<Texture>());
+ Curve &curve = **curve_ref;
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ thumbnail_size *= EDSCALE;
+ Ref<Image> img_ref;
+ img_ref.instance();
+ Image &im = **img_ref;
+
+ im.create(thumbnail_size, thumbnail_size, 0, Image::FORMAT_RGBA8);
+
+ im.lock();
+
+ Color bg_color(0.1, 0.1, 0.1, 1.0);
+ for (int i = 0; i < thumbnail_size; i++) {
+ for (int j = 0; j < thumbnail_size; j++) {
+ im.put_pixel(i, j, bg_color);
+ }
+ }
+
+ Color line_color(0.8, 0.8, 0.8, 1.0);
+ float range_y = curve.get_max_value() - curve.get_min_value();
+
+ int prev_y = 0;
+ for (int x = 0; x < im.get_width(); ++x) {
+
+ float t = static_cast<float>(x) / im.get_width();
+ float v = (curve.interpolate_baked(t) - curve.get_min_value()) / range_y;
+ int y = CLAMP(im.get_height() - v * im.get_height(), 0, im.get_height());
+
+ // Plot point
+ if (y >= 0 && y < im.get_height()) {
+ im.put_pixel(x, y, line_color);
+ }
+
+ // Plot vertical line to fix discontinuity (not 100% correct but enough for a preview)
+ if (x != 0 && Math::abs(y - prev_y) > 1) {
+ int y0, y1;
+ if (y < prev_y) {
+ y0 = y;
+ y1 = prev_y;
+ } else {
+ y0 = prev_y;
+ y1 = y;
+ }
+ for (int ly = y0; ly < y1; ++ly) {
+ im.put_pixel(x, ly, line_color);
+ }
+ }
+
+ prev_y = y;
+ }
+
+ im.unlock();
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
+
+ ptex->create_from_image(img_ref, 0);
+ return ptex;
+}
diff --git a/editor/plugins/curve_editor_plugin.h b/editor/plugins/curve_editor_plugin.h
index a4952dfb28..040c298a92 100644
--- a/editor/plugins/curve_editor_plugin.h
+++ b/editor/plugins/curve_editor_plugin.h
@@ -143,4 +143,11 @@ private:
ToolButton *_toggle_button;
};
+class CurvePreviewGenerator : public EditorResourcePreviewGenerator {
+ GDCLASS(CurvePreviewGenerator, EditorResourcePreviewGenerator)
+public:
+ bool handles(const String &p_type) const;
+ Ref<Texture> generate(const Ref<Resource> &p_from);
+};
+
#endif // CURVE_EDITOR_PLUGIN_H
diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp
index 7f56286f08..f567abc5b1 100644
--- a/editor/plugins/item_list_editor_plugin.cpp
+++ b/editor/plugins/item_list_editor_plugin.cpp
@@ -193,6 +193,45 @@ ItemListPopupMenuPlugin::ItemListPopupMenuPlugin() {
}
///////////////////////////////////////////////////////////////
+
+void ItemListItemListPlugin::set_object(Object *p_object) {
+
+ pp = p_object->cast_to<ItemList>();
+}
+
+bool ItemListItemListPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("ItemList");
+}
+
+int ItemListItemListPlugin::get_flags() const {
+
+ return FLAG_ICON | FLAG_ENABLE;
+}
+
+void ItemListItemListPlugin::add_item() {
+
+ pp->add_item(vformat(TTR("Item %d"), pp->get_item_count()));
+ _change_notify();
+}
+
+int ItemListItemListPlugin::get_item_count() const {
+
+ return pp->get_item_count();
+}
+
+void ItemListItemListPlugin::erase(int p_idx) {
+
+ pp->remove_item(p_idx);
+ _change_notify();
+}
+
+ItemListItemListPlugin::ItemListItemListPlugin() {
+
+ pp = NULL;
+}
+
+///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
@@ -373,6 +412,7 @@ ItemListEditorPlugin::ItemListEditorPlugin(EditorNode *p_node) {
item_list_editor->hide();
item_list_editor->add_plugin(memnew(ItemListOptionButtonPlugin));
item_list_editor->add_plugin(memnew(ItemListPopupMenuPlugin));
+ item_list_editor->add_plugin(memnew(ItemListItemListPlugin));
}
ItemListEditorPlugin::~ItemListEditorPlugin() {
diff --git a/editor/plugins/item_list_editor_plugin.h b/editor/plugins/item_list_editor_plugin.h
index 042e88839f..4fed8e49f5 100644
--- a/editor/plugins/item_list_editor_plugin.h
+++ b/editor/plugins/item_list_editor_plugin.h
@@ -167,6 +167,35 @@ public:
///////////////////////////////////////////////////////////////
+class ItemListItemListPlugin : public ItemListPlugin {
+
+ GDCLASS(ItemListItemListPlugin, ItemListPlugin);
+
+ ItemList *pp;
+
+public:
+ virtual void set_object(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual int get_flags() const;
+
+ virtual void set_item_text(int p_idx, const String &p_text) { pp->set_item_text(p_idx, p_text); }
+ virtual String get_item_text(int p_idx) const { return pp->get_item_text(p_idx); }
+
+ virtual void set_item_icon(int p_idx, const Ref<Texture> &p_tex) { pp->set_item_icon(p_idx, p_tex); }
+ virtual Ref<Texture> get_item_icon(int p_idx) const { return pp->get_item_icon(p_idx); }
+
+ virtual void set_item_enabled(int p_idx, int p_enabled) { pp->set_item_disabled(p_idx, !p_enabled); }
+ virtual bool is_item_enabled(int p_idx) const { return !pp->is_item_disabled(p_idx); }
+
+ virtual void add_item();
+ virtual int get_item_count() const;
+ virtual void erase(int p_idx);
+
+ ItemListItemListPlugin();
+};
+
+///////////////////////////////////////////////////////////////
+
class ItemListEditor : public HBoxContainer {
GDCLASS(ItemListEditor, HBoxContainer);
diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp
index 877707d77b..3524c34d62 100644
--- a/editor/plugins/path_editor_plugin.cpp
+++ b/editor/plugins/path_editor_plugin.cpp
@@ -104,7 +104,7 @@ void PathSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_p
if (SpatialEditor::get_singleton()->is_snap_enabled()) {
float snap = SpatialEditor::get_singleton()->get_translate_snap();
- inters.snap(snap);
+ inters.snap(Vector3(snap, snap, snap));
}
Vector3 local = gi.xform(inters);
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index c55bef1b03..995d13f6a8 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -1180,7 +1180,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (_edit.snap || spatial_editor->is_snap_enabled()) {
snap = spatial_editor->get_translate_snap();
- motion.snap(snap);
+ motion.snap(Vector3(snap, snap, snap));
}
//set_message("Translating: "+motion);
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index da2d22b900..886474200e 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -658,7 +658,91 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
}
} break;
-
+ case TOOL_SCENE_EDITABLE_CHILDREN: {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ if (List<Node *>::Element *e = selection.front()) {
+ if (Node *node = e->get()) {
+ bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node);
+ editable = !editable;
+
+ EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, editable);
+ menu->set_item_checked(18, editable);
+ if (editable) {
+ node->set_scene_instance_load_placeholder(false);
+ menu->set_item_checked(19, false);
+ }
+ scene_tree->update_tree();
+ }
+ }
+ } break;
+ case TOOL_SCENE_USE_PLACEHOLDER: {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ if (List<Node *>::Element *e = selection.front()) {
+ if (Node *node = e->get()) {
+ bool placeholder = node->get_scene_instance_load_placeholder();
+ placeholder = !placeholder;
+ if (placeholder)
+ EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, false);
+
+ node->set_scene_instance_load_placeholder(placeholder);
+ menu->set_item_checked(18, false);
+ menu->set_item_checked(19, placeholder);
+ scene_tree->update_tree();
+ }
+ }
+ } break;
+ case TOOL_SCENE_CLEAR_INSTANCING: {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ if (List<Node *>::Element *e = selection.front()) {
+ if (Node *node = e->get()) {
+ Node *root = EditorNode::get_singleton()->get_edited_scene();
+ UndoRedo *undo_redo = &editor_data->get_undo_redo();
+ if (!root)
+ break;
+
+ ERR_FAIL_COND(node->get_filename() == String());
+
+ undo_redo->create_action("Discard Instancing");
+ undo_redo->add_do_method(node, "set_filename", "");
+ undo_redo->add_undo_method(node, "set_filename", node->get_filename());
+ _node_replace_owner(node, node, root);
+ undo_redo->add_do_method(scene_tree, "update_tree");
+ undo_redo->add_undo_method(scene_tree, "update_tree");
+ undo_redo->commit_action();
+ }
+ }
+ } break;
+ case TOOL_SCENE_OPEN: {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ if (List<Node *>::Element *e = selection.front()) {
+ if (Node *node = e->get()) {
+ scene_tree->emit_signal("open", node->get_filename());
+ }
+ }
+ } break;
+ case TOOL_SCENE_CLEAR_INHERITANCE: {
+ clear_inherit_confirm->popup_centered_minsize();
+ } break;
+ case TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM: {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ if (List<Node *>::Element *e = selection.front()) {
+ if (Node *node = e->get()) {
+ node->set_scene_inherited_state(Ref<SceneState>());
+ scene_tree->update_tree();
+ EditorNode::get_singleton()->get_property_editor()->update_tree();
+ }
+ }
+ } break;
+ case TOOL_SCENE_OPEN_INHERITED: {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ if (List<Node *>::Element *e = selection.front()) {
+ if (Node *node = e->get()) {
+ if (node && node->get_scene_inherited_state().is_valid()) {
+ scene_tree->emit_signal("open", node->get_scene_inherited_state()->get_path());
+ }
+ }
+ }
+ } break;
default: {
if (p_tool >= EDIT_SUBRESOURCE_BASE) {
@@ -702,6 +786,29 @@ void SceneTreeDock::_notification(int p_what) {
EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", this, "_selection_changed");
} break;
+
+ case NOTIFICATION_ENTER_TREE: {
+ clear_inherit_confirm->connect("confirmed", this, "_tool_selected", varray(TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM));
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ clear_inherit_confirm->disconnect("confirmed", this, "_tool_selected");
+ } break;
+ }
+}
+
+void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root) {
+
+ if (p_base != p_node) {
+ if (p_node->get_owner() == p_base) {
+ UndoRedo *undo_redo = &editor_data->get_undo_redo();
+ undo_redo->add_do_method(p_node, "set_owner", p_root);
+ undo_redo->add_undo_method(p_node, "set_owner", p_base);
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _node_replace_owner(p_base, p_node->get_child(i), p_root);
}
}
@@ -1769,6 +1876,26 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->add_icon_shortcut(get_icon("CreateNewSceneFrom", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/save_branch_as_scene"), TOOL_NEW_SCENE_FROM);
menu->add_separator();
menu->add_icon_shortcut(get_icon("CopyNodePath", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH);
+ bool is_external = (selection[0]->get_filename() != "");
+ if (is_external) {
+ bool is_inherited = selection[0]->get_scene_inherited_state() != NULL;
+ bool is_top_level = selection[0]->get_owner() == NULL;
+ if (is_inherited) {
+ menu->add_separator();
+ menu->add_item(TTR("Clear Inheritance"), TOOL_SCENE_CLEAR_INHERITANCE);
+ menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN_INHERITED);
+ } else if (!is_top_level) {
+ menu->add_separator();
+ bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(selection[0]);
+ bool placeholder = selection[0]->get_scene_instance_load_placeholder();
+ menu->add_check_item(TTR("Editable Children"), TOOL_SCENE_EDITABLE_CHILDREN);
+ menu->add_check_item(TTR("Load As Placeholder"), TOOL_SCENE_USE_PLACEHOLDER);
+ menu->add_item(TTR("Discard Instancing"), TOOL_SCENE_CLEAR_INSTANCING);
+ menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN);
+ menu->set_item_checked(18, editable);
+ menu->set_item_checked(19, placeholder);
+ }
+ }
}
menu->add_separator();
menu->add_icon_shortcut(get_icon("Remove", "EditorIcons"), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), KEY_DELETE), TOOL_ERASE);
@@ -1978,6 +2105,11 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
first_enter = true;
restore_script_editor_on_drag = false;
+ clear_inherit_confirm = memnew(ConfirmationDialog);
+ clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)"));
+ clear_inherit_confirm->get_ok()->set_text(TTR("Clear!"));
+ add_child(clear_inherit_confirm);
+
vbc->add_constant_override("separation", 4);
set_process_input(true);
}
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index 79e01e7571..5872c5a25d 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -70,7 +70,14 @@ class SceneTreeDock : public VBoxContainer {
TOOL_MULTI_EDIT,
TOOL_ERASE,
TOOL_COPY_NODE_PATH,
- TOOL_BUTTON_MAX
+ TOOL_BUTTON_MAX,
+ TOOL_SCENE_EDITABLE_CHILDREN,
+ TOOL_SCENE_USE_PLACEHOLDER,
+ TOOL_SCENE_CLEAR_INSTANCING,
+ TOOL_SCENE_OPEN,
+ TOOL_SCENE_CLEAR_INHERITANCE,
+ TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM,
+ TOOL_SCENE_OPEN_INHERITED
};
enum {
@@ -112,6 +119,7 @@ class SceneTreeDock : public VBoxContainer {
TextureRect *filter_icon;
PopupMenu *menu;
+ ConfirmationDialog *clear_inherit_confirm;
bool first_enter;
@@ -127,6 +135,7 @@ class SceneTreeDock : public VBoxContainer {
void _do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform);
void _set_owners(Node *p_owner, const Array &p_nodes);
+ void _node_replace_owner(Node *p_base, Node *p_node, Node *p_root);
void _load_request(const String &p_path);
void _script_open_request(const Ref<Script> &p_script);
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index d4e5714c0d..d12d8b5528 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -44,110 +44,6 @@ Node *SceneTreeEditor::get_scene_node() {
return get_tree()->get_edited_scene_root();
}
-void SceneTreeEditor::_subscene_option(int p_idx) {
-
- Object *obj = ObjectDB::get_instance(instance_node);
- if (!obj)
- return;
- Node *node = obj->cast_to<Node>();
- if (!node)
- return;
-
- switch (p_idx) {
-
- case SCENE_MENU_EDITABLE_CHILDREN: {
-
- bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node);
- editable = !editable;
-
- //node->set_instance_children_editable(editable);
- EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, editable);
- instance_menu->set_item_checked(0, editable);
- if (editable) {
- node->set_scene_instance_load_placeholder(false);
- instance_menu->set_item_checked(1, false);
- }
-
- _update_tree();
-
- } break;
- case SCENE_MENU_USE_PLACEHOLDER: {
-
- bool placeholder = node->get_scene_instance_load_placeholder();
- placeholder = !placeholder;
-
- //node->set_instance_children_editable(editable);
- if (placeholder) {
- EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, false);
- }
- node->set_scene_instance_load_placeholder(placeholder);
- instance_menu->set_item_checked(0, false);
- instance_menu->set_item_checked(1, placeholder);
-
- _update_tree();
-
- } break;
- case SCENE_MENU_OPEN: {
-
- emit_signal("open", node->get_filename());
- } break;
- case SCENE_MENU_CLEAR_INHERITANCE: {
- clear_inherit_confirm->popup_centered_minsize();
- } break;
- case SCENE_MENU_CLEAR_INSTANCING: {
-
- Node *root = EditorNode::get_singleton()->get_edited_scene();
- if (!root)
- break;
-
- ERR_FAIL_COND(node->get_filename() == String());
-
- undo_redo->create_action("Discard Instancing");
-
- undo_redo->add_do_method(node, "set_filename", "");
- undo_redo->add_undo_method(node, "set_filename", node->get_filename());
-
- _node_replace_owner(node, node, root);
-
- undo_redo->add_do_method(this, "update_tree");
- undo_redo->add_undo_method(this, "update_tree");
-
- undo_redo->commit_action();
-
- } break;
- case SCENE_MENU_OPEN_INHERITED: {
- if (node && node->get_scene_inherited_state().is_valid()) {
- emit_signal("open", node->get_scene_inherited_state()->get_path());
- }
- } break;
- case SCENE_MENU_CLEAR_INHERITANCE_CONFIRM: {
- if (node && node->get_scene_inherited_state().is_valid()) {
- node->set_scene_inherited_state(Ref<SceneState>());
- update_tree();
- EditorNode::get_singleton()->get_property_editor()->update_tree();
- }
-
- } break;
- }
-}
-
-void SceneTreeEditor::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root) {
-
- if (p_base != p_node) {
-
- if (p_node->get_owner() == p_base) {
-
- undo_redo->add_do_method(p_node, "set_owner", p_root);
- undo_redo->add_undo_method(p_node, "set_owner", p_base);
- }
- }
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
-
- _node_replace_owner(p_base, p_node->get_child(i), p_root);
- }
-}
-
void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_id) {
TreeItem *item = p_item->cast_to<TreeItem>();
@@ -159,38 +55,13 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
ERR_FAIL_COND(!n);
if (p_id == BUTTON_SUBSCENE) {
- //open scene request
- Rect2 item_rect = tree->get_item_rect(item, 0);
- item_rect.position.y -= tree->get_scroll().y;
- item_rect.position += tree->get_global_position();
-
if (n == get_scene_node()) {
- inheritance_menu->set_position(item_rect.position + Vector2(0, item_rect.size.y));
- inheritance_menu->set_size(Vector2(item_rect.size.x, 0));
- inheritance_menu->popup();
- instance_node = n->get_instance_ID();
-
- } else {
- instance_menu->set_position(item_rect.position + Vector2(0, item_rect.size.y));
- instance_menu->set_size(Vector2(item_rect.size.x, 0));
- if (EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(n))
- instance_menu->set_item_checked(0, true);
- else
- instance_menu->set_item_checked(0, false);
-
- if (n->get_owner() == get_scene_node()) {
- instance_menu->set_item_checked(1, n->get_scene_instance_load_placeholder());
- instance_menu->set_item_disabled(1, false);
- } else {
-
- instance_menu->set_item_checked(1, false);
- instance_menu->set_item_disabled(1, true);
+ if (n && n->get_scene_inherited_state().is_valid()) {
+ emit_signal("open", n->get_scene_inherited_state()->get_path());
}
-
- instance_menu->popup();
- instance_node = n->get_instance_ID();
+ } else {
+ emit_signal("open", n->get_filename());
}
- //emit_signal("open",n->get_filename());
} else if (p_id == BUTTON_SCRIPT) {
RefPtr script = n->get_script();
if (!script.is_null())
@@ -472,7 +343,7 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
void SceneTreeEditor::_update_visibility_color(Node *p_node, TreeItem *p_item) {
if (p_node->is_class("CanvasItem") || p_node->is_class("Spatial")) {
Color color(1, 1, 1, 1);
- bool visible_on_screen = p_node->call("is_visible");
+ bool visible_on_screen = p_node->call("is_visible_in_tree");
if (!visible_on_screen) {
color = Color(0.6, 0.6, 0.6, 1);
}
@@ -633,10 +504,7 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->connect("node_removed", this, "_node_removed");
get_tree()->connect("node_configuration_warning_changed", this, "_warning_changed");
- instance_menu->set_item_icon(5, get_icon("Load", "EditorIcons"));
tree->connect("item_collapsed", this, "_cell_collapsed");
- inheritance_menu->set_item_icon(2, get_icon("Load", "EditorIcons"));
- clear_inherit_confirm->connect("confirmed", this, "_subscene_option", varray(SCENE_MENU_CLEAR_INHERITANCE_CONFIRM));
EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed");
@@ -649,7 +517,6 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->disconnect("tree_changed", this, "_tree_changed");
get_tree()->disconnect("node_removed", this, "_node_removed");
tree->disconnect("item_collapsed", this, "_cell_collapsed");
- clear_inherit_confirm->disconnect("confirmed", this, "_subscene_option");
get_tree()->disconnect("node_configuration_warning_changed", this, "_warning_changed");
EditorSettings::get_singleton()->disconnect("settings_changed", this, "_editor_settings_changed");
}
@@ -1059,7 +926,6 @@ void SceneTreeEditor::_bind_methods() {
ClassDB::bind_method("_selection_changed", &SceneTreeEditor::_selection_changed);
ClassDB::bind_method("_cell_button_pressed", &SceneTreeEditor::_cell_button_pressed);
ClassDB::bind_method("_cell_collapsed", &SceneTreeEditor::_cell_collapsed);
- ClassDB::bind_method("_subscene_option", &SceneTreeEditor::_subscene_option);
ClassDB::bind_method("_rmb_select", &SceneTreeEditor::_rmb_select);
ClassDB::bind_method("_warning_changed", &SceneTreeEditor::_warning_changed);
@@ -1145,29 +1011,6 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope
updating_tree = false;
blocked = 0;
- instance_menu = memnew(PopupMenu);
- instance_menu->add_check_item(TTR("Editable Children"), SCENE_MENU_EDITABLE_CHILDREN);
- instance_menu->add_check_item(TTR("Load As Placeholder"), SCENE_MENU_USE_PLACEHOLDER);
- instance_menu->add_separator();
- instance_menu->add_item(TTR("Discard Instancing"), SCENE_MENU_CLEAR_INSTANCING);
- instance_menu->add_separator();
- instance_menu->add_item(TTR("Open in Editor"), SCENE_MENU_OPEN);
- instance_menu->connect("id_pressed", this, "_subscene_option");
- add_child(instance_menu);
-
- inheritance_menu = memnew(PopupMenu);
- inheritance_menu->add_item(TTR("Clear Inheritance"), SCENE_MENU_CLEAR_INHERITANCE);
- inheritance_menu->add_separator();
- inheritance_menu->add_item(TTR("Open in Editor"), SCENE_MENU_OPEN_INHERITED);
- inheritance_menu->connect("id_pressed", this, "_subscene_option");
-
- add_child(inheritance_menu);
-
- clear_inherit_confirm = memnew(ConfirmationDialog);
- clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)"));
- clear_inherit_confirm->get_ok()->set_text(TTR("Clear!"));
- add_child(clear_inherit_confirm);
-
update_timer = memnew(Timer);
update_timer->connect("timeout", this, "_update_tree");
update_timer->set_one_shot(true);
diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h
index ec7115afed..c6283af7b5 100644
--- a/editor/scene_tree_editor.h
+++ b/editor/scene_tree_editor.h
@@ -56,27 +56,14 @@ class SceneTreeEditor : public Control {
BUTTON_GROUPS = 7,
};
- enum {
- SCENE_MENU_EDITABLE_CHILDREN,
- SCENE_MENU_USE_PLACEHOLDER,
- SCENE_MENU_OPEN,
- SCENE_MENU_CLEAR_INHERITANCE,
- SCENE_MENU_OPEN_INHERITED,
- SCENE_MENU_CLEAR_INHERITANCE_CONFIRM,
- SCENE_MENU_CLEAR_INSTANCING,
- };
-
Tree *tree;
Node *selected;
- PopupMenu *instance_menu;
- PopupMenu *inheritance_menu;
ObjectID instance_node;
String filter;
AcceptDialog *error;
AcceptDialog *warning;
- ConfirmationDialog *clear_inherit_confirm;
int blocked;
@@ -119,7 +106,6 @@ class SceneTreeEditor : public Control {
void _node_script_changed(Node *p_node);
void _node_visibility_changed(Node *p_node);
void _update_visibility_color(Node *p_node, TreeItem *p_item);
- void _subscene_option(int p_idx);
void _node_replace_owner(Node *p_base, Node *p_node, Node *p_root);
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 563de78415..6f613981b8 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -382,10 +382,6 @@ EditorSettingsDialog::EditorSettingsDialog() {
press_a_key->add_child(l);
press_a_key->connect("gui_input", this, "_wait_for_key");
press_a_key->connect("confirmed", this, "_press_a_key_confirm");
- //Button *load = memnew( Button );
-
- //load->set_text("Load..");
- //hbc->add_child(load);
//get_ok()->set_text("Apply");
set_hide_on_ok(true);
diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
index 76df9eb1ff..62fa93ac23 100644
--- a/editor/spatial_editor_gizmos.cpp
+++ b/editor/spatial_editor_gizmos.cpp
@@ -1279,8 +1279,8 @@ void RoomSpatialGizmo::redraw() {
for (int j = 0; j < 3; j++) {
_EdgeKey ek;
- ek.from = r[i].vertex[j].snapped(CMP_EPSILON);
- ek.to = r[i].vertex[(j + 1) % 3].snapped(CMP_EPSILON);
+ ek.from = r[i].vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
+ ek.to = r[i].vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
if (ek.from < ek.to)
SWAP(ek.from, ek.to);
@@ -2463,8 +2463,8 @@ void NavigationMeshSpatialGizmo::redraw() {
tw[tidx++] = f.vertex[j];
_EdgeKey ek;
- ek.from = f.vertex[j].snapped(CMP_EPSILON);
- ek.to = f.vertex[(j + 1) % 3].snapped(CMP_EPSILON);
+ ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
+ ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
if (ek.from < ek.to)
SWAP(ek.from, ek.to);
diff --git a/modules/gdnative/godot/godot_vector3.cpp b/modules/gdnative/godot/godot_vector3.cpp
index f9942af6e5..adca0d1e2a 100644
--- a/modules/gdnative/godot/godot_vector3.cpp
+++ b/modules/gdnative/godot/godot_vector3.cpp
@@ -90,11 +90,12 @@ godot_vector3 GDAPI godot_vector3_inverse(const godot_vector3 *p_self) {
return dest;
}
-godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_real p_by) {
+godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_vector3 *p_by) {
godot_vector3 dest;
const Vector3 *self = (const Vector3 *)p_self;
+ const Vector3 *snap_axis = (const Vector3 *)p_by;
- *((Vector3 *)&dest) = self->snapped(p_by);
+ *((Vector3 *)&dest) = self->snapped(*snap_axis);
return dest;
}
diff --git a/modules/gdnative/godot/godot_vector3.h b/modules/gdnative/godot/godot_vector3.h
index 8e2aed8173..98d9ddf6ac 100644
--- a/modules/gdnative/godot/godot_vector3.h
+++ b/modules/gdnative/godot/godot_vector3.h
@@ -70,7 +70,7 @@ godot_vector3 GDAPI godot_vector3_normalized(const godot_vector3 *p_self);
godot_vector3 GDAPI godot_vector3_inverse(const godot_vector3 *p_self);
-godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_real p_by);
+godot_vector3 GDAPI godot_vector3_snapped(const godot_vector3 *p_self, const godot_vector3 *p_by);
godot_vector3 GDAPI godot_vector3_rotated(const godot_vector3 *p_self, const godot_vector3 *p_axis, const godot_real p_phi);
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 066adde780..9d3493cb49 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -41,6 +41,7 @@
#include "platform/osx/logo.gen.h"
#include "string.h"
#include "version.h"
+#include <sys/stat.h>
class EditorExportPlatformOSX : public EditorExportPlatform {
@@ -52,6 +53,10 @@ class EditorExportPlatformOSX : public EditorExportPlatform {
void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary);
void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
+#ifdef OSX_ENABLED
+ Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+ Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
+#endif
protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features);
@@ -61,7 +66,11 @@ public:
virtual String get_name() const { return "Mac OSX"; }
virtual Ref<Texture> get_logo() const { return logo; }
+#ifdef OSX_ENABLED
+ virtual String get_binary_extension() const { return "dmg"; }
+#else
virtual String get_binary_extension() const { return "zip"; }
+#endif
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
@@ -90,6 +99,11 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false));
+
+#ifdef OSX_ENABLED
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements"), ""));
+#endif
}
void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
@@ -177,21 +191,62 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset
}
}
+#ifdef OSX_ENABLED
+/**
+ If we're running the OSX version of the Godot editor we'll:
+ - export our application bundle to a temporary folder
+ - attempt to code sign it
+ - and then wrap it up in a DMG
+**/
+
+Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ List<String> args;
+ if (p_preset->get("codesign/entitlements") != "") {
+ /* this should point to our entitlements.plist file that sandboxes our application, I don't know if this should also be placed in our app bundle */
+ args.push_back("-entitlements");
+ args.push_back(p_preset->get("codesign/entitlements"));
+ }
+ args.push_back("-s");
+ args.push_back(p_preset->get("codesign/identity"));
+ args.push_back("-v"); /* provide some more feedback */
+ args.push_back(p_path);
+ Error err = OS::get_singleton()->execute("/usr/bin/codesign", args, true);
+ ERR_FAIL_COND_V(err, err);
+
+ return OK;
+}
+
+Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) {
+ List<String> args;
+ args.push_back("create");
+ args.push_back(p_dmg_path);
+ args.push_back("-volname");
+ args.push_back(p_pkg_name);
+ args.push_back("-fs");
+ args.push_back("HFS+");
+ args.push_back("-srcfolder");
+ args.push_back(p_app_path_name);
+ Error err = OS::get_singleton()->execute("/usr/bin/hdiutil", args, true);
+ ERR_FAIL_COND_V(err, err);
+
+ return OK;
+}
+
Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- String src_pkg;
+ String src_pkg_name;
- EditorProgress ep("export", "Exporting for OSX", 104);
+ EditorProgress ep("export", "Exporting for OSX", 3);
if (p_debug)
- src_pkg = p_preset->get("custom_package/debug");
+ src_pkg_name = p_preset->get("custom_package/debug");
else
- src_pkg = p_preset->get("custom_package/release");
+ src_pkg_name = p_preset->get("custom_package/release");
- if (src_pkg == "") {
+ if (src_pkg_name == "") {
String err;
- src_pkg = find_export_template("osx.zip", &err);
- if (src_pkg == "") {
+ src_pkg_name = find_export_template("osx.zip", &err);
+ if (src_pkg_name == "") {
EditorNode::add_io_error(err);
return ERR_FILE_NOT_FOUND;
}
@@ -202,20 +257,15 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
ep.step("Creating app", 0);
- unzFile pkg = unzOpen2(src_pkg.utf8().get_data(), &io);
- if (!pkg) {
+ unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
+ if (!src_pkg_zip) {
- EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg);
+ EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name);
return ERR_FILE_NOT_FOUND;
}
- ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN);
- int ret = unzGoToFirstFile(pkg);
-
- zlib_filefunc_def io2 = io;
- FileAccess *dst_f = NULL;
- io2.opaque = &dst_f;
- zipFile dpkg = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2);
+ ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN);
+ int ret = unzGoToFirstFile(src_pkg_zip);
String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + ".";
int bits_mode = p_preset->get("application/bits_mode");
@@ -230,14 +280,34 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
else
pkg_name = "Unnamed";
+ // We're on OSX so we can export to DMG, but first we create our application bundle
+ String tmp_app_path_name = p_path.get_base_dir() + "/" + pkg_name + ".app";
+ print_line("Exporting to " + tmp_app_path_name);
+ DirAccess *tmp_app_path = DirAccess::create_for_path(tmp_app_path_name);
+ ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE)
+
+ ///@TODO We should delete the existing application bundle especially if we attempt to code sign it, but what is a safe way to do this? Maybe call system function so it moves to trash?
+ // tmp_app_path->erase_contents_recursive();
+
+ // Create our folder structure or rely on unzip?
+ print_line("Creating " + tmp_app_path_name + "/Contents/MacOS");
+ Error dir_err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS");
+ ERR_FAIL_COND_V(dir_err, ERR_CANT_CREATE)
+ print_line("Creating " + tmp_app_path_name + "/Contents/Resources");
+ dir_err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
+ ERR_FAIL_COND_V(dir_err, ERR_CANT_CREATE)
+
+ /* Now process our template */
bool found_binary = false;
+ int total_size = 0;
while (ret == UNZ_OK) {
+ bool is_execute = false;
//get filename
unz_file_info info;
char fname[16384];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+ ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0);
String file = fname;
@@ -246,9 +316,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
data.resize(info.uncompressed_size);
//read
- unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptr(), data.size());
- unzCloseCurrentFile(pkg);
+ unzOpenCurrentFile(src_pkg_zip);
+ unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size());
+ unzCloseCurrentFile(src_pkg_zip);
//write
@@ -261,10 +331,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (file.begins_with("Contents/MacOS/godot_")) {
if (file != "Contents/MacOS/" + binary_to_use) {
- ret = unzGoToNextFile(pkg);
+ ret = unzGoToNextFile(src_pkg_zip);
continue; //ignore!
}
found_binary = true;
+ is_execute = true;
file = "Contents/MacOS/" + pkg_name;
}
@@ -288,11 +359,206 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
//bleh?
}
- file = pkg_name + ".app/" + file;
+ if (data.size() > 0) {
+ print_line("ADDING: " + file + " size: " + itos(data.size()));
+ total_size += data.size();
+
+ /* write it into our application bundle */
+ file = tmp_app_path_name + "/" + file;
+
+ /* write the file, need to add chmod */
+ FileAccess *f = FileAccess::open(file, FileAccess::WRITE);
+ ERR_FAIL_COND_V(!f, ERR_CANT_CREATE)
+ f->store_buffer(data.ptr(), data.size());
+ f->close();
+ memdelete(f);
+
+ if (is_execute) {
+ // we need execute rights on this file
+ chmod(file.utf8().get_data(), 0755);
+ } else {
+ // seems to already be set correctly
+ // chmod(file.utf8().get_data(), 0644);
+ }
+ }
+
+ ret = unzGoToNextFile(src_pkg_zip);
+ }
+
+ /* we're done with our source zip */
+ unzClose(src_pkg_zip);
+
+ if (!found_binary) {
+ ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive.");
+ unzClose(src_pkg_zip);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ ep.step("Making PKG", 1);
+
+ String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck";
+ Error err = save_pack(p_preset, pack_path);
+ // chmod(pack_path.utf8().get_data(), 0644);
+
+ if (err) {
+ return err;
+ }
+
+ /* see if we can code sign our new package */
+ if (p_preset->get("codesign/identity") != "") {
+ ep.step("Code signing bundle", 2);
+
+ /* the order in which we code sign is important, this is a bit of a shame or we could do this in our loop that extracts the files from our ZIP */
+
+ // start with our application
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name);
+ ERR_FAIL_COND_V(err, err);
+
+ ///@TODO we should check the contents of /Contents/Frameworks for frameworks to sign
+
+ // we should probably loop through all resources and sign them?
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Resources/icon.icns");
+ ERR_FAIL_COND_V(err, err);
+ err = _code_sign(p_preset, pack_path);
+ ERR_FAIL_COND_V(err, err);
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Info.plist");
+ ERR_FAIL_COND_V(err, err);
+ }
+
+ /* and finally create a DMG */
+ ep.step("Making DMG", 3);
+ err = _create_dmg(p_path, pkg_name, tmp_app_path_name);
+ ERR_FAIL_COND_V(err, err);
+
+ return OK;
+}
+
+#else
+
+/**
+ When exporting for OSX from any other platform we don't have access to code signing or creating DMGs so we'll wrap the bundle into a zip file.
+
+ Should probably find a nicer way to have just one export method instead of duplicating the method like this but I would the code got very
+ messy with switches inside of it.
+**/
+Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+
+ String src_pkg_name;
+
+ EditorProgress ep("export", "Exporting for OSX", 104);
+
+ if (p_debug)
+ src_pkg_name = p_preset->get("custom_package/debug");
+ else
+ src_pkg_name = p_preset->get("custom_package/release");
+
+ if (src_pkg_name == "") {
+ String err;
+ src_pkg_name = find_export_template("osx.zip", &err);
+ if (src_pkg_name == "") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ FileAccess *src_f = NULL;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+ ep.step("Creating app", 0);
+
+ unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
+ if (!src_pkg_zip) {
+
+ EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN);
+ int ret = unzGoToFirstFile(src_pkg_zip);
+
+ String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + ".";
+ int bits_mode = p_preset->get("application/bits_mode");
+ binary_to_use += String(bits_mode == 0 ? "fat" : bits_mode == 1 ? "64" : "32");
+
+ print_line("binary: " + binary_to_use);
+ String pkg_name;
+ if (p_preset->get("application/name") != "")
+ pkg_name = p_preset->get("application/name"); // app_name
+ else if (String(GlobalConfig::get_singleton()->get("application/name")) != "")
+ pkg_name = String(GlobalConfig::get_singleton()->get("application/name"));
+ else
+ pkg_name = "Unnamed";
+
+ /* Open our destination zip file */
+ zlib_filefunc_def io2 = io;
+ FileAccess *dst_f = NULL;
+ io2.opaque = &dst_f;
+ zipFile dst_pkg_zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2);
+
+ bool found_binary = false;
+
+ while (ret == UNZ_OK) {
+
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0);
+
+ String file = fname;
+
+ print_line("READ: " + file);
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(src_pkg_zip);
+ unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size());
+ unzCloseCurrentFile(src_pkg_zip);
+
+ //write
+
+ file = file.replace_first("osx_template.app/", "");
+
+ if (file == "Contents/Info.plist") {
+ print_line("parse plist");
+ _fix_plist(p_preset, data, pkg_name);
+ }
+
+ if (file.begins_with("Contents/MacOS/godot_")) {
+ if (file != "Contents/MacOS/" + binary_to_use) {
+ ret = unzGoToNextFile(src_pkg_zip);
+ continue; //ignore!
+ }
+ found_binary = true;
+ file = "Contents/MacOS/" + pkg_name;
+ }
+
+ if (file == "Contents/Resources/icon.icns") {
+ //see if there is an icon
+ String iconpath;
+ if (p_preset->get("application/icon") != "")
+ iconpath = p_preset->get("application/icon");
+ else
+ iconpath = GlobalConfig::get_singleton()->get("application/icon");
+ print_line("icon? " + iconpath);
+ if (iconpath != "") {
+ Ref<Image> icon;
+ icon.instance();
+ icon->load(iconpath);
+ if (!icon->empty()) {
+ print_line("loaded?");
+ _make_icon(icon, data);
+ }
+ }
+ //bleh?
+ }
if (data.size() > 0) {
print_line("ADDING: " + file + " size: " + itos(data.size()));
+ /* add it to our zip file */
+ file = pkg_name + ".app/" + file;
+
zip_fileinfo fi;
fi.tmz_date.tm_hour = info.tmu_date.tm_hour;
fi.tmz_date.tm_min = info.tmu_date.tm_min;
@@ -304,7 +570,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
fi.internal_fa = info.internal_fa;
fi.external_fa = info.external_fa;
- int err = zipOpenNewFileInZip(dpkg,
+ int err = zipOpenNewFileInZip(dst_pkg_zip,
file.utf8().get_data(),
&fi,
NULL,
@@ -316,37 +582,37 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
Z_DEFAULT_COMPRESSION);
print_line("OPEN ERR: " + itos(err));
- err = zipWriteInFileInZip(dpkg, data.ptr(), data.size());
+ err = zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size());
print_line("WRITE ERR: " + itos(err));
- zipCloseFileInZip(dpkg);
+ zipCloseFileInZip(dst_pkg_zip);
}
- ret = unzGoToNextFile(pkg);
+ ret = unzGoToNextFile(src_pkg_zip);
}
if (!found_binary) {
ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive.");
- zipClose(dpkg, NULL);
- unzClose(pkg);
+ zipClose(dst_pkg_zip, NULL);
+ unzClose(src_pkg_zip);
return ERR_FILE_NOT_FOUND;
}
ep.step("Making PKG", 1);
- String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/data.pck";
+ String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/" + pkg_name + ".pck";
Error err = save_pack(p_preset, pack_path);
if (err) {
- zipClose(dpkg, NULL);
- unzClose(pkg);
+ zipClose(dst_pkg_zip, NULL);
+ unzClose(src_pkg_zip);
return err;
}
{
//write datapack
- zipOpenNewFileInZip(dpkg,
- (pkg_name + ".app/Contents/Resources/data.pck").utf8().get_data(),
+ zipOpenNewFileInZip(dst_pkg_zip,
+ (pkg_name + ".app/Contents/Resources/" + pkg_name + ".pck").utf8().get_data(),
NULL,
NULL,
0,
@@ -366,17 +632,18 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
int r = pf->get_buffer(buf, BSIZE);
if (r <= 0)
break;
- zipWriteInFileInZip(dpkg, buf, r);
+ zipWriteInFileInZip(dst_pkg_zip, buf, r);
}
- zipCloseFileInZip(dpkg);
+ zipCloseFileInZip(dst_pkg_zip);
memdelete(pf);
}
- zipClose(dpkg, NULL);
- unzClose(pkg);
+ zipClose(dst_pkg_zip, NULL);
+ unzClose(src_pkg_zip);
return OK;
}
+#endif
bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
diff --git a/platform/x11/godot_x11.cpp b/platform/x11/godot_x11.cpp
index b293b1bebb..6f418b213f 100644
--- a/platform/x11/godot_x11.cpp
+++ b/platform/x11/godot_x11.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include <limits.h>
+#include <locale.h>
#include <stdlib.h>
#include <unistd.h>
@@ -38,6 +39,8 @@ int main(int argc, char *argv[]) {
OS_X11 os;
+ setlocale(LC_CTYPE, "");
+
char *cwd = (char *)malloc(PATH_MAX);
getcwd(cwd, PATH_MAX);
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 2eebc96d2c..383abffe46 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -68,6 +68,8 @@
#undef CursorShape
+#include <X11/XKBlib.h>
+
int OS_X11::get_video_driver_count() const {
return 1;
}
@@ -93,6 +95,7 @@ const char *OS_X11::get_audio_driver_name(int p_driver) const {
void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
+ long im_event_mask = 0;
last_button_state = 0;
xmbstring = NULL;
@@ -113,7 +116,32 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
/** XLIB INITIALIZATION **/
x11_display = XOpenDisplay(NULL);
- char *modifiers = XSetLocaleModifiers("@im=none");
+ Bool xkb_dar = False;
+ if (x11_display) {
+ XAutoRepeatOn(x11_display);
+ xkb_dar = XkbSetDetectableAutoRepeat(x11_display, True, NULL);
+ }
+
+ char *modifiers = NULL;
+
+ // Try to support IME if detectable auto-repeat is supported
+
+ if (xkb_dar == True) {
+
+// Xutf8LookupString will be used later instead of XmbLookupString before
+// the multibyte sequences can be converted to unicode string.
+
+#ifdef X_HAVE_UTF8_STRING
+ modifiers = XSetLocaleModifiers("");
+#endif
+ }
+
+ if (modifiers == NULL) {
+ if (is_stdout_verbose()) {
+ WARN_PRINT("IME is disabled");
+ }
+ modifiers = XSetLocaleModifiers("@im=none");
+ }
if (modifiers == NULL) {
WARN_PRINT("Error setting locale modifiers");
}
@@ -153,6 +181,14 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
WARN_PRINT("XOpenIM failed");
xim_style = 0L;
} else {
+ ::XIMCallback im_destroy_callback;
+ im_destroy_callback.client_data = (::XPointer)(this);
+ im_destroy_callback.callback = (::XIMProc)(xim_destroy_callback);
+ if (XSetIMValues(xim, XNDestroyCallback, &im_destroy_callback,
+ NULL) != NULL) {
+ WARN_PRINT("Error setting XIM destroy callback");
+ }
+
::XIMStyles *xim_styles = NULL;
xim_style = 0L;
char *imvalret = NULL;
@@ -303,7 +339,8 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
StructureNotifyMask |
SubstructureNotifyMask | SubstructureRedirectMask |
FocusChangeMask | PropertyChangeMask |
- ColormapChangeMask | OwnerGrabButtonMask;
+ ColormapChangeMask | OwnerGrabButtonMask |
+ im_event_mask;
XChangeWindowAttributes(x11_display, x11_window, CWEventMask, &new_attr);
@@ -327,6 +364,16 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
if (xim && xim_style) {
xic = XCreateIC(xim, XNInputStyle, xim_style, XNClientWindow, x11_window, XNFocusWindow, x11_window, (char *)NULL);
+ if (XGetICValues(xic, XNFilterEvents, &im_event_mask, NULL) != NULL) {
+ WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value");
+ XDestroyIC(xic);
+ xic = NULL;
+ }
+ if (xic) {
+ XSetICFocus(xic);
+ } else {
+ WARN_PRINT("XCreateIC couldn't create xic");
+ }
} else {
xic = NULL;
@@ -445,6 +492,33 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
_ensure_data_dir();
}
+void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data,
+ ::XPointer call_data) {
+
+ WARN_PRINT("Input method stopped");
+ OS_X11 *os = reinterpret_cast<OS_X11 *>(client_data);
+ os->xim = NULL;
+ os->xic = NULL;
+}
+
+void OS_X11::set_ime_position(short x, short y) {
+
+ if (!xic) {
+ return;
+ }
+ ::XPoint spot;
+ spot.x = x;
+ spot.y = y;
+ XVaNestedList preedit_attr = XVaCreateNestedList(0,
+ XNSpotLocation, &spot,
+ NULL);
+ XSetICValues(xic,
+ XNPreeditAttributes, preedit_attr,
+ NULL);
+ XFree(preedit_attr);
+ return;
+}
+
void OS_X11::finalize() {
if (main_loop)
@@ -492,8 +566,12 @@ void OS_X11::finalize() {
XcursorImageDestroy(img[i]);
};
- XDestroyIC(xic);
- XCloseIM(xim);
+ if (xic) {
+ XDestroyIC(xic);
+ }
+ if (xim) {
+ XCloseIM(xim);
+ }
XCloseDisplay(x11_display);
if (xmbstring)
@@ -1041,9 +1119,61 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
xmblen = 8;
}
+ keysym_unicode = keysym_keycode;
+
if (xkeyevent->type == KeyPress && xic) {
Status status;
+#ifdef X_HAVE_UTF8_STRING
+ int utf8len = 8;
+ char *utf8string = (char *)memalloc(sizeof(char) * utf8len);
+ int utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string,
+ utf8len - 1, &keysym_unicode, &status);
+ if (status == XBufferOverflow) {
+ utf8len = utf8bytes + 1;
+ utf8string = (char *)memrealloc(utf8string, utf8len);
+ utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string,
+ utf8len - 1, &keysym_unicode, &status);
+ }
+ utf8string[utf8bytes] = '\0';
+
+ if (status == XLookupChars) {
+ bool keypress = xkeyevent->type == KeyPress;
+ unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
+ if (keycode >= 'a' && keycode <= 'z')
+ keycode -= 'a' - 'A';
+
+ String tmp;
+ tmp.parse_utf8(utf8string, utf8bytes);
+ for (int i = 0; i < tmp.length(); i++) {
+ Ref<InputEventKey> k;
+ k.instance();
+ if (keycode == 0 && tmp[i] == 0) {
+ continue;
+ }
+
+ get_key_modifier_state(xkeyevent->state, k);
+
+ k->set_unicode(tmp[i]);
+
+ k->set_pressed(keypress);
+
+ k->set_scancode(keycode);
+
+ k->set_echo(false);
+
+ if (k->get_scancode() == KEY_BACKTAB) {
+ //make it consistent across platforms.
+ k->set_scancode(KEY_TAB);
+ k->set_shift(true);
+ }
+
+ input->parse_input_event(k);
+ }
+ return;
+ }
+ memfree(utf8string);
+#else
do {
int mnbytes = XmbLookupString(xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status);
@@ -1054,6 +1184,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
xmbstring = (char *)memrealloc(xmbstring, xmblen);
}
} while (status == XBufferOverflow);
+#endif
}
/* Phase 2, obtain a pigui keycode from the keysym */
@@ -1082,11 +1213,6 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
bool keypress = xkeyevent->type == KeyPress;
- if (xkeyevent->type == KeyPress && xic) {
- if (XFilterEvent((XEvent *)xkeyevent, x11_window))
- return;
- }
-
if (keycode == 0 && unicode == 0)
return;
@@ -1112,6 +1238,8 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
if (xkeyevent->type != KeyPress) {
+ p_echo = false;
+
// make sure there are events pending,
// so this call won't block.
if (XPending(x11_display) > 0) {
@@ -1172,6 +1300,18 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
k->set_metakey(false);
}
+ bool last_is_pressed = Input::get_singleton()->is_key_pressed(k->get_scancode());
+ if (k->is_pressed()) {
+ if (last_is_pressed) {
+ k->set_echo(true);
+ }
+ } else {
+ //ignore
+ if (last_is_pressed == false) {
+ return;
+ }
+ }
+
//printf("key: %x\n",k->get_scancode());
input->parse_input_event(k);
}
@@ -1253,6 +1393,10 @@ void OS_X11::process_xevents() {
XEvent event;
XNextEvent(x11_display, &event);
+ if (XFilterEvent(&event, None)) {
+ continue;
+ }
+
switch (event.type) {
case Expose:
Main::force_redraw();
@@ -1295,6 +1439,9 @@ void OS_X11::process_xevents() {
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime);
}
+ if (xic) {
+ XSetICFocus(xic);
+ }
break;
case FocusOut:
@@ -1308,9 +1455,16 @@ void OS_X11::process_xevents() {
}
XUngrabPointer(x11_display, CurrentTime);
}
+ if (xic) {
+ XUnsetICFocus(xic);
+ }
break;
case ConfigureNotify:
+ if (xic) {
+ // Not portable.
+ set_ime_position(0, 1);
+ }
/* call resizeGLScene only if our window-size changed */
if ((event.xconfigure.width == current_videomode.width) &&
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index d62186e5bd..b253934a05 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -113,6 +113,10 @@ class OS_X11 : public OS_Unix {
::XIC xic;
::XIM xim;
::XIMStyle xim_style;
+ static void xim_destroy_callback(::XIM im, ::XPointer client_data,
+ ::XPointer call_data);
+ void set_ime_position(short x, short y);
+
Point2i last_mouse_pos;
bool last_mouse_pos_valid;
Point2i last_click_pos;
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 6fe1dd73fe..bd6ab99801 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -319,7 +319,7 @@ void Node2D::set_global_scale(const Size2 &p_scale) {
CanvasItem *pi = get_parent_item();
if (pi) {
const Size2 parent_global_scale = pi->get_global_transform().get_scale();
- set_scale(p_scale - parent_global_scale);
+ set_scale(p_scale / parent_global_scale);
} else {
set_scale(p_scale);
}
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index a0d9c26430..62e1a95209 100644
--- a/scene/3d/mesh_instance.cpp
+++ b/scene/3d/mesh_instance.cpp
@@ -32,6 +32,7 @@
#include "body_shape.h"
#include "core_string_names.h"
#include "physics_body.h"
+#include "scene/resources/material.h"
#include "scene/scene_string_names.h"
#include "skeleton.h"
bool MeshInstance::_set(const StringName &p_name, const Variant &p_value) {
@@ -274,6 +275,81 @@ void MeshInstance::_mesh_changed() {
materials.resize(mesh->get_surface_count());
}
+void MeshInstance::create_debug_tagents() {
+
+ Vector<Vector3> lines;
+ Vector<Color> colors;
+
+ Ref<Mesh> mesh = get_mesh();
+ if (!mesh.is_valid())
+ return;
+
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ Array arrays = mesh->surface_get_arrays(i);
+ Vector<Vector3> verts = arrays[Mesh::ARRAY_VERTEX];
+ Vector<Vector3> norms = arrays[Mesh::ARRAY_NORMAL];
+ if (norms.size() == 0)
+ continue;
+ Vector<float> tangents = arrays[Mesh::ARRAY_TANGENT];
+ if (tangents.size() == 0)
+ continue;
+
+ for (int j = 0; j < verts.size(); j++) {
+ Vector3 v = verts[j];
+ Vector3 n = norms[j];
+ Vector3 t = Vector3(tangents[j * 4 + 0], tangents[j * 4 + 1], tangents[j * 4 + 2]);
+ Vector3 b = (n.cross(t)).normalized() * tangents[j * 4 + 3];
+
+ lines.push_back(v); //normal
+ colors.push_back(Color(0, 0, 1)); //color
+ lines.push_back(v + n * 0.04); //normal
+ colors.push_back(Color(0, 0, 1)); //color
+
+ lines.push_back(v); //tangent
+ colors.push_back(Color(1, 0, 0)); //color
+ lines.push_back(v + t * 0.04); //tangent
+ colors.push_back(Color(1, 0, 0)); //color
+
+ lines.push_back(v); //binormal
+ colors.push_back(Color(0, 1, 0)); //color
+ lines.push_back(v + b * 0.04); //binormal
+ colors.push_back(Color(0, 1, 0)); //color
+ }
+ }
+
+ if (lines.size()) {
+
+ Ref<SpatialMaterial> sm;
+ sm.instance();
+
+ sm->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+ sm->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+ sm->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+
+ Ref<ArrayMesh> am;
+ am.instance();
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[Mesh::ARRAY_VERTEX] = lines;
+ a[Mesh::ARRAY_COLOR] = colors;
+
+ am->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a);
+ am->surface_set_material(0, sm);
+
+ MeshInstance *mi = memnew(MeshInstance);
+ mi->set_mesh(am);
+ mi->set_name("DebugTangents");
+ add_child(mi);
+#ifdef TOOLS_ENABLED
+
+ if (this == get_tree()->get_edited_scene_root())
+ mi->set_owner(this);
+ else
+ mi->set_owner(get_owner());
+#endif
+ }
+}
+
void MeshInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mesh", "mesh:Mesh"), &MeshInstance::set_mesh);
@@ -290,6 +366,9 @@ void MeshInstance::_bind_methods() {
ClassDB::set_method_flags("MeshInstance", "create_convex_collision", METHOD_FLAGS_DEFAULT);
ClassDB::bind_method(D_METHOD("_mesh_changed"), &MeshInstance::_mesh_changed);
+ ClassDB::bind_method(D_METHOD("create_debug_tagents"), &MeshInstance::create_debug_tagents);
+ ClassDB::set_method_flags("MeshInstance", "create_debug_tagents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
+
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton"), "set_skeleton_path", "get_skeleton_path");
}
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
index c11c52b76d..be328084af 100644
--- a/scene/3d/mesh_instance.h
+++ b/scene/3d/mesh_instance.h
@@ -83,6 +83,8 @@ public:
Node *create_convex_collision_node();
void create_convex_collision();
+ void create_debug_tagents();
+
virtual Rect3 get_aabb() const;
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index 82f6f665db..4c93bcfb5e 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -149,8 +149,8 @@ Ref<Mesh> NavigationMesh::get_debug_mesh() {
tw[tidx++] = f.vertex[j];
_EdgeKey ek;
- ek.from = f.vertex[j].snapped(CMP_EPSILON);
- ek.to = f.vertex[(j + 1) % 3].snapped(CMP_EPSILON);
+ ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
+ ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
if (ek.from < ek.to)
SWAP(ek.from, ek.to);
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index 3debbf02c3..20c2cc1eb5 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -541,10 +541,7 @@ void Spatial::show() {
if (!is_inside_tree())
return;
- if (!data.parent || is_visible_in_tree()) {
-
- _propagate_visibility_changed();
- }
+ _propagate_visibility_changed();
}
void Spatial::hide() {
@@ -552,14 +549,14 @@ void Spatial::hide() {
if (!data.visible)
return;
- bool was_visible = is_visible_in_tree();
data.visible = false;
- if (!data.parent || was_visible) {
+ if (!is_inside_tree())
+ return;
- _propagate_visibility_changed();
- }
+ _propagate_visibility_changed();
}
+
bool Spatial::is_visible_in_tree() const {
const Spatial *s = this;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 2f0c7b9aaf..160b7b151a 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -1223,6 +1223,36 @@ Vector<int> ItemList::get_selected_items() {
return selected;
}
+void ItemList::_set_items(const Array &p_items) {
+
+ ERR_FAIL_COND(p_items.size() % 3);
+ clear();
+
+ for (int i = 0; i < p_items.size(); i += 3) {
+
+ String text = p_items[i + 0];
+ Ref<Texture> icon = p_items[i + 1];
+ bool disabled = p_items[i + 2];
+
+ int idx = get_item_count();
+ add_item(text, icon);
+ set_item_disabled(idx, disabled);
+ }
+}
+
+Array ItemList::_get_items() const {
+
+ Array items;
+ for (int i = 0; i < get_item_count(); i++) {
+
+ items.push_back(get_item_text(i));
+ items.push_back(get_item_icon(i));
+ items.push_back(is_item_disabled(i));
+ }
+
+ return items;
+}
+
void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_item", "text", "icon:Texture", "selectable"), &ItemList::add_item, DEFVAL(Variant()), DEFVAL(true));
@@ -1302,6 +1332,22 @@ void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("_scroll_changed"), &ItemList::_scroll_changed);
ClassDB::bind_method(D_METHOD("_gui_input"), &ItemList::_gui_input);
+ ClassDB::bind_method(D_METHOD("_set_items"), &ItemList::_set_items);
+ ClassDB::bind_method(D_METHOD("_get_items"), &ItemList::_get_items);
+
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_items", "_get_items");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Multi"), "set_select_mode", "get_select_mode");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
+ ADD_PROPERTYNO(PropertyInfo(Variant::INT, "max_text_lines"), "set_max_text_lines", "get_max_text_lines");
+ ADD_GROUP("Columns", "");
+ ADD_PROPERTYNO(PropertyInfo(Variant::INT, "max_columns"), "set_max_columns", "get_max_columns");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "same_column_width"), "set_same_column_width", "is_same_column_width");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "fixed_column_width"), "set_fixed_column_width", "get_fixed_column_width");
+ ADD_GROUP("Icon", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_mode", PROPERTY_HINT_ENUM, "Top,Left"), "set_icon_mode", "get_icon_mode");
+ ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "icon_scale"), "set_icon_scale", "get_icon_scale");
+
BIND_CONSTANT(ICON_MODE_TOP);
BIND_CONSTANT(ICON_MODE_LEFT);
BIND_CONSTANT(SELECT_SINGLE);
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index c7abc2990f..9cb7016b60 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -103,6 +103,9 @@ private:
real_t icon_scale;
+ Array _get_items() const;
+ void _set_items(const Array &p_items);
+
void _scroll_changed(double);
void _gui_input(const Ref<InputEvent> &p_event);
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 0c65c44392..61e563143c 100755
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -37,7 +37,6 @@
#include "viewport.h"
VARIANT_ENUM_CAST(Node::PauseMode);
-VARIANT_ENUM_CAST(Node::NetworkMode);
VARIANT_ENUM_CAST(Node::RPCMode);
void Node::_notification(int p_notification) {
@@ -77,16 +76,6 @@ void Node::_notification(int p_notification) {
data.pause_owner = this;
}
- if (data.network_mode == NETWORK_MODE_INHERIT) {
-
- if (data.parent)
- data.network_owner = data.parent->data.network_owner;
- else
- data.network_owner = NULL;
- } else {
- data.network_owner = this;
- }
-
if (data.input)
add_to_group("_vp_input" + itos(get_viewport()->get_instance_ID()));
if (data.unhandled_input)
@@ -108,7 +97,6 @@ void Node::_notification(int p_notification) {
remove_from_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_ID()));
data.pause_owner = NULL;
- data.network_owner = NULL;
if (data.path_cache) {
memdelete(data.path_cache);
data.path_cache = NULL;
@@ -472,69 +460,28 @@ void Node::_propagate_pause_owner(Node *p_owner) {
}
}
-void Node::set_network_mode(NetworkMode p_mode) {
+void Node::set_network_master(int p_peer_id, bool p_recursive) {
- if (data.network_mode == p_mode)
- return;
+ data.network_master = p_peer_id;
- bool prev_inherits = data.network_mode == NETWORK_MODE_INHERIT;
- data.network_mode = p_mode;
- if (!is_inside_tree())
- return; //pointless
- if ((data.network_mode == NETWORK_MODE_INHERIT) == prev_inherits)
- return; ///nothing changed
-
- Node *owner = NULL;
-
- if (data.network_mode == NETWORK_MODE_INHERIT) {
+ if (p_recursive) {
+ for (int i = 0; i < data.children.size(); i++) {
- if (data.parent)
- owner = data.parent->data.network_owner;
- } else {
- owner = this;
+ data.children[i]->set_network_master(p_peer_id, true);
+ }
}
-
- _propagate_network_owner(owner);
}
-Node::NetworkMode Node::get_network_mode() const {
+int Node::get_network_master() const {
- return data.network_mode;
+ return data.network_master;
}
bool Node::is_network_master() const {
ERR_FAIL_COND_V(!is_inside_tree(), false);
- switch (data.network_mode) {
- case NETWORK_MODE_INHERIT: {
-
- if (data.network_owner)
- return data.network_owner->is_network_master();
- else
- return get_tree()->is_network_server();
- } break;
- case NETWORK_MODE_MASTER: {
-
- return true;
- } break;
- case NETWORK_MODE_SLAVE: {
- return false;
- } break;
- }
-
- return false;
-}
-
-void Node::_propagate_network_owner(Node *p_owner) {
-
- if (data.network_mode != NETWORK_MODE_INHERIT)
- return;
- data.network_owner = p_owner;
- for (int i = 0; i < data.children.size(); i++) {
-
- data.children[i]->_propagate_network_owner(p_owner);
- }
+ return get_tree()->get_network_unique_id() == data.network_master;
}
/***** RPC CONFIG ********/
@@ -962,7 +909,7 @@ void Node::rset_unreliable_id(int p_peer_id, const StringName &p_property, const
//////////// end of rpc
-bool Node::can_call_rpc(const StringName &p_method) const {
+bool Node::can_call_rpc(const StringName &p_method, int p_from) const {
const Map<StringName, RPCMode>::Element *E = data.rpc_methods.find(p_method);
if (E) {
@@ -982,7 +929,7 @@ bool Node::can_call_rpc(const StringName &p_method) const {
return is_network_master();
} break;
case RPC_MODE_SLAVE: {
- return !is_network_master();
+ return !is_network_master() && p_from == get_network_master();
} break;
}
}
@@ -1006,16 +953,16 @@ bool Node::can_call_rpc(const StringName &p_method) const {
return is_network_master();
} break;
case ScriptInstance::RPC_MODE_SLAVE: {
- return !is_network_master();
+ return !is_network_master() && p_from == get_network_master();
} break;
}
}
- ERR_PRINTS("RPC on unauthorized method attempted: " + String(p_method) + " on base: " + String(Variant(this)));
+ ERR_PRINTS("RPC from " + itos(p_from) + " on unauthorized method attempted: " + String(p_method) + " on base: " + String(Variant(this)));
return false;
}
-bool Node::can_call_rset(const StringName &p_property) const {
+bool Node::can_call_rset(const StringName &p_property, int p_from) const {
const Map<StringName, RPCMode>::Element *E = data.rpc_properties.find(p_property);
if (E) {
@@ -1035,7 +982,7 @@ bool Node::can_call_rset(const StringName &p_property) const {
return is_network_master();
} break;
case RPC_MODE_SLAVE: {
- return !is_network_master();
+ return !is_network_master() && p_from == get_network_master();
} break;
}
}
@@ -1059,12 +1006,12 @@ bool Node::can_call_rset(const StringName &p_property) const {
return is_network_master();
} break;
case ScriptInstance::RPC_MODE_SLAVE: {
- return !is_network_master();
+ return !is_network_master() && p_from == get_network_master();
} break;
}
}
- ERR_PRINTS("RSET on unauthorized property attempted: " + String(p_property) + " on base: " + String(Variant(this)));
+ ERR_PRINTS("RSET from " + itos(p_from) + " on unauthorized property attempted: " + String(p_property) + " on base: " + String(Variant(this)));
return false;
}
@@ -2845,8 +2792,8 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("request_ready"), &Node::request_ready);
- ClassDB::bind_method(D_METHOD("set_network_mode", "mode"), &Node::set_network_mode);
- ClassDB::bind_method(D_METHOD("get_network_mode"), &Node::get_network_mode);
+ ClassDB::bind_method(D_METHOD("set_network_master", "id", "recursive"), &Node::set_network_master, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("get_network_master"), &Node::get_network_master);
ClassDB::bind_method(D_METHOD("is_network_master"), &Node::is_network_master);
@@ -2902,10 +2849,6 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS);
BIND_CONSTANT(NOTIFICATION_INTERNAL_FIXED_PROCESS);
- BIND_CONSTANT(NETWORK_MODE_INHERIT);
- BIND_CONSTANT(NETWORK_MODE_MASTER);
- BIND_CONSTANT(NETWORK_MODE_SLAVE);
-
BIND_CONSTANT(RPC_MODE_DISABLED);
BIND_CONSTANT(RPC_MODE_REMOTE);
BIND_CONSTANT(RPC_MODE_SYNC);
@@ -2977,8 +2920,7 @@ Node::Node() {
data.unhandled_key_input = false;
data.pause_mode = PAUSE_MODE_INHERIT;
data.pause_owner = NULL;
- data.network_mode = NETWORK_MODE_INHERIT;
- data.network_owner = NULL;
+ data.network_master = 1; //server by default
data.path_cache = NULL;
data.parent_owned = false;
data.in_constructor = true;
diff --git a/scene/main/node.h b/scene/main/node.h
index ffd2b7ce5f..7baa65c022 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -61,13 +61,6 @@ public:
DUPLICATE_USE_INSTANCING = 8
};
- enum NetworkMode {
-
- NETWORK_MODE_INHERIT,
- NETWORK_MODE_MASTER,
- NETWORK_MODE_SLAVE
- };
-
enum RPCMode {
RPC_MODE_DISABLED, //no rpc for this method, calls to this will be blocked (default)
@@ -122,8 +115,7 @@ private:
PauseMode pause_mode;
Node *pause_owner;
- NetworkMode network_mode;
- Node *network_owner;
+ int network_master;
Map<StringName, RPCMode> rpc_methods;
Map<StringName, RPCMode> rpc_properties;
@@ -173,7 +165,6 @@ private:
void _propagate_validate_owner();
void _print_stray_nodes();
void _propagate_pause_owner(Node *p_owner);
- void _propagate_network_owner(Node *p_owner);
Array _get_node_and_resource(const NodePath &p_path);
void _duplicate_signals(const Node *p_original, Node *p_copy) const;
@@ -393,8 +384,8 @@ public:
bool is_displayed_folded() const;
/* NETWORK */
- void set_network_mode(NetworkMode p_mode);
- NetworkMode get_network_mode() const;
+ void set_network_master(int p_peer_id, bool p_recursive = true);
+ int get_network_master() const;
bool is_network_master() const;
void rpc_config(const StringName &p_method, RPCMode p_mode); // config a local method for RPC
@@ -414,8 +405,8 @@ public:
void rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value);
- bool can_call_rpc(const StringName &p_method) const;
- bool can_call_rset(const StringName &p_property) const;
+ bool can_call_rpc(const StringName &p_method, int p_from) const;
+ bool can_call_rset(const StringName &p_property, int p_from) const;
Node();
~Node();
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 479abccda6..1e5735de97 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1763,6 +1763,16 @@ int SceneTree::get_network_unique_id() const {
return network_peer->get_unique_id();
}
+Vector<int> SceneTree::get_network_connected_peers() const {
+ ERR_FAIL_COND_V(!network_peer.is_valid(), Vector<int>());
+
+ Vector<int> ret;
+ for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) {
+ ret.push_back(E->get());
+ }
+
+ return ret;
+}
void SceneTree::set_refuse_new_network_connections(bool p_refuse) {
ERR_FAIL_COND(!network_peer.is_valid());
network_peer->set_refuse_new_connections(p_refuse);
@@ -1973,6 +1983,7 @@ void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int
Node *node = NULL;
if (target & 0x80000000) {
+ //use full path (not cached yet)
int ofs = target & 0x7FFFFFFF;
ERR_FAIL_COND(ofs >= p_packet_len);
@@ -1988,7 +1999,7 @@ void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int
ERR_FAIL_COND(node == NULL);
}
} else {
-
+ //use cached path
int id = target;
Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from);
@@ -2023,7 +2034,7 @@ void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int
if (packet_type == NETWORK_COMMAND_REMOTE_CALL) {
- if (!node->can_call_rpc(name))
+ if (!node->can_call_rpc(name, p_from))
return;
int ofs = len_end + 1;
@@ -2060,7 +2071,7 @@ void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int
} else {
- if (!node->can_call_rset(name))
+ if (!node->can_call_rset(name, p_from))
return;
int ofs = len_end + 1;
@@ -2236,6 +2247,7 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_network_peer", "peer:NetworkedMultiplayerPeer"), &SceneTree::set_network_peer);
ClassDB::bind_method(D_METHOD("is_network_server"), &SceneTree::is_network_server);
ClassDB::bind_method(D_METHOD("has_network_peer"), &SceneTree::has_network_peer);
+ ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &SceneTree::get_network_connected_peers);
ClassDB::bind_method(D_METHOD("get_network_unique_id"), &SceneTree::get_network_unique_id);
ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &SceneTree::set_refuse_new_network_connections);
ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &SceneTree::is_refusing_new_network_connections);
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 2ea79bf945..76a4becdbc 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -451,6 +451,7 @@ public:
bool is_network_server() const;
bool has_network_peer() const;
int get_network_unique_id() const;
+ Vector<int> get_network_connected_peers() const;
void set_refuse_new_network_connections(bool p_refuse);
bool is_refusing_new_network_connections() const;
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 24e3977de8..b9dc428c2d 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -818,7 +818,7 @@ float Environment::get_fog_height_curve() const {
void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_background", "mode"), &Environment::set_background);
- ClassDB::bind_method(D_METHOD("set_sky", "sky:CubeMap"), &Environment::set_sky);
+ ClassDB::bind_method(D_METHOD("set_sky", "sky:Sky"), &Environment::set_sky);
ClassDB::bind_method(D_METHOD("set_sky_scale", "scale"), &Environment::set_sky_scale);
ClassDB::bind_method(D_METHOD("set_bg_color", "color"), &Environment::set_bg_color);
ClassDB::bind_method(D_METHOD("set_bg_energy", "energy"), &Environment::set_bg_energy);
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 3934467855..6209f99d9d 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -452,7 +452,7 @@ void SpatialMaterial::_update_shader() {
if (features[FEATURE_DEPTH_MAPPING]) {
code += "\t{\n";
- code += "\t\tvec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT,BINORMAL,NORMAL));\n";
+ code += "\t\tvec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT,-BINORMAL,NORMAL));\n"; //binormal is negative due to mikktpsace
if (deep_parallax) {
code += "\t\tfloat num_layers = mix(float(depth_max_layers),float(depth_min_layers), abs(dot(vec3(0.0, 0.0, 1.0), view_dir)));\n";
@@ -1265,7 +1265,7 @@ void SpatialMaterial::_bind_methods() {
ADD_GROUP("Anisotropy", "anisotropy_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anisotropy_enabled"), "set_feature", "get_feature", FEATURE_ANISOTROPY);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "anisotropy", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_anisotropy", "get_anisotropy");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "anisotropy", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_anisotropy", "get_anisotropy");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anisotropy_flowmap", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_FLOWMAP);
ADD_GROUP("Ambient Occlusion", "ao_");
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 6e41cef4a0..81cfd0e5f0 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -171,7 +171,9 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) {
float onethird = 1.0 / 3.0;
float twothirds = 2.0 / 3.0;
- set_aabb(Rect3(Vector3(-radius, (mid_height * -0.5) - radius, -radius), Vector3(radius * 2.0, mid_height + (2.0 * radius), radius * 2.0)));
+ // note, this has been aligned with our collision shape but I've left the descriptions as top/middle/bottom
+
+ set_aabb(Rect3(Vector3(-radius, -radius, (mid_height * -0.5) - radius), Vector3(radius * 2.0, radius * 2.0, mid_height + (2.0 * radius))));
PoolVector<Vector3> points;
PoolVector<Vector3> normals;
@@ -195,19 +197,19 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) {
v /= (rings + 1);
w = sin(0.5 * Math_PI * v);
- y = radius * cos(0.5 * Math_PI * v);
+ z = radius * cos(0.5 * Math_PI * v);
for (i = 0; i <= radial_segments; i++) {
u = i;
u /= radial_segments;
x = sin(u * (Math_PI * 2.0));
- z = cos(u * (Math_PI * 2.0));
+ y = -cos(u * (Math_PI * 2.0));
- Vector3 p = Vector3(x * radius * w, y, z * radius * w);
- points.push_back(p + Vector3(0.0, 0.5 * mid_height, 0.0));
+ Vector3 p = Vector3(x * radius * w, y * radius * w, z);
+ points.push_back(p + Vector3(0.0, 0.0, 0.5 * mid_height));
normals.push_back(p.normalized());
- ADD_TANGENT(-z, 0.0, x, -1.0)
+ ADD_TANGENT(y, -x, 0.0, -1.0)
uvs.push_back(Vector2(u, v * onethird));
point++;
@@ -233,20 +235,20 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) {
v = j;
v /= (rings + 1);
- y = mid_height * v;
- y = (mid_height * 0.5) - y;
+ z = mid_height * v;
+ z = (mid_height * 0.5) - z;
for (i = 0; i <= radial_segments; i++) {
u = i;
u /= radial_segments;
x = sin(u * (Math_PI * 2.0));
- z = cos(u * (Math_PI * 2.0));
+ y = -cos(u * (Math_PI * 2.0));
- Vector3 p = Vector3(x * radius, y, z * radius);
+ Vector3 p = Vector3(x * radius, y * radius, z);
points.push_back(p);
- normals.push_back(Vector3(x, 0.0, z));
- ADD_TANGENT(-z, 0.0, x, -1.0)
+ normals.push_back(Vector3(x, y, 0.0));
+ ADD_TANGENT(y, -x, 0.0, -1.0)
uvs.push_back(Vector2(u, onethird + (v * onethird)));
point++;
@@ -275,19 +277,19 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) {
v /= (rings + 1);
v += 1.0;
w = sin(0.5 * Math_PI * v);
- y = radius * cos(0.5 * Math_PI * v);
+ z = radius * cos(0.5 * Math_PI * v);
for (i = 0; i <= radial_segments; i++) {
float u = i;
u /= radial_segments;
x = sin(u * (Math_PI * 2.0));
- z = cos(u * (Math_PI * 2.0));
+ y = -cos(u * (Math_PI * 2.0));
- Vector3 p = Vector3(x * radius * w, y, z * radius * w);
- points.push_back(p + Vector3(0.0, -0.5 * mid_height, 0.0));
+ Vector3 p = Vector3(x * radius * w, y * radius * w, z);
+ points.push_back(p + Vector3(0.0, 0.0, -0.5 * mid_height));
normals.push_back(p.normalized());
- ADD_TANGENT(-z, 0.0, x, -1.0)
+ ADD_TANGENT(y, -x, 0.0, -1.0)
uvs.push_back(Vector2(u, twothirds + ((v - 1.0) * onethird)));
point++;
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index eb0848ff50..c833f4eabd 100644
--- a/servers/visual_server.cpp
+++ b/servers/visual_server.cpp
@@ -1262,9 +1262,9 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector<uint8_
for (int j = 0; j < p_vertex_len; j++) {
- const uint8_t *v = (const uint8_t *)&r[j * total_elem_size + offsets[i]];
+ const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
for (int k = 0; k < 4; k++) {
- w[j * 4 + k] = float(v[k] / 255.0) * 2.0 - 1.0;
+ w[j * 4 + k] = float(v[k] / 127.0);
}
}
} else {