diff options
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 { |