diff options
26 files changed, 573 insertions, 103 deletions
diff --git a/core/math/rect2.h b/core/math/rect2.h index 9017377770..0d2e7eb6e5 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -60,6 +60,19 @@ struct Rect2 { return true; } + inline bool intersects_touch(const Rect2 &p_rect) const { + if (position.x > (p_rect.position.x + p_rect.size.width)) + return false; + if ((position.x + size.width) < p_rect.position.x) + return false; + if (position.y > (p_rect.position.y + p_rect.size.height)) + return false; + if ((position.y + size.height) < p_rect.position.y) + return false; + + return true; + } + inline real_t distance_to(const Vector2 &p_point) const { real_t dist = 0.0; diff --git a/doc/classes/Skeleton2D.xml b/doc/classes/Skeleton2D.xml index ccae59d72c..558ba84068 100644 --- a/doc/classes/Skeleton2D.xml +++ b/doc/classes/Skeleton2D.xml @@ -4,6 +4,7 @@ Skeleton for 2D characters and animated objects. </brief_description> <description> + Skeleton2D parents a hierarchy of [Bone2D] objects. It is a requirement of [Bone2D]. Skeleton2D holds a reference to the rest pose of its children and acts as a single point of access to its bones. </description> <tutorials> <link>https://docs.godotengine.org/en/latest/tutorials/animation/2d_skeletons.html</link> @@ -15,19 +16,21 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns a [Bone2D] from the node hierarchy parented by Skeleton2D. The object to return is identified by the parameter [code]idx[/code]. Bones are indexed by descending the node hierarchy from top to bottom, adding the children of each branch before moving to the next sibling. </description> </method> <method name="get_bone_count" qualifiers="const"> <return type="int"> </return> <description> - Returns the amount of bones in the skeleton. + Returns the number of [Bone2D] nodes in the node hierarchy parented by Skeleton2D. </description> </method> <method name="get_skeleton" qualifiers="const"> <return type="RID"> </return> <description> + Returns the [RID] of a Skeleton2D instance. </description> </method> </methods> diff --git a/doc/classes/VisualShaderNodeScalarUniform.xml b/doc/classes/VisualShaderNodeScalarUniform.xml index d1a4742555..fab766d3f9 100644 --- a/doc/classes/VisualShaderNodeScalarUniform.xml +++ b/doc/classes/VisualShaderNodeScalarUniform.xml @@ -1,13 +1,38 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualShaderNodeScalarUniform" inherits="VisualShaderNodeUniform" version="4.0"> <brief_description> + A scalar uniform to be used within the visual shader graph. </brief_description> <description> + Translated to [code]uniform float[/code] in the shader language. </description> <tutorials> </tutorials> <methods> </methods> + <members> + <member name="hint" type="int" setter="set_hint" getter="get_hint" enum="VisualShaderNodeScalarUniform.Hint" default="0"> + A hint applied to the uniform, which controls the values it can take when set through the inspector. + </member> + <member name="max" type="float" setter="set_max" getter="get_max" default="1.0"> + Minimum value for range hints. Used if [member hint] is set to [constant HINT_RANGE] or [constant HINT_RANGE_STEP]. + </member> + <member name="min" type="float" setter="set_min" getter="get_min" default="0.0"> + Maximum value for range hints. Used if [member hint] is set to [constant HINT_RANGE] or [constant HINT_RANGE_STEP]. + </member> + <member name="step" type="float" setter="set_step" getter="get_step" default="0.1"> + Step (increment) value for the range hint with step. Used if [member hint] is set to [constant HINT_RANGE_STEP]. + </member> + </members> <constants> + <constant name="HINT_NONE" value="0" enum="Hint"> + No hint used. + </constant> + <constant name="HINT_RANGE" value="1" enum="Hint"> + A range hint for scalar value, which limits possible input values between [member min] and [member max]. Translated to [code]hint_range(min, max)[/code] in shader code. + </constant> + <constant name="HINT_RANGE_STEP" value="2" enum="Hint"> + A range hint for scalar value with step, which limits possible input values between [member min] and [member max], with a step (increment) of [member step]). Translated to [code]hint_range(min, max, step)[/code] in shader code. + </constant> </constants> </class> diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index c0ba93db6a..bb6a45e240 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -53,6 +53,11 @@ #endif #endif +#if !defined(GLES_OVER_GL) +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_TEXTURE_3D 0x806F +#endif + static const GLenum _cube_side_enum[6] = { GL_TEXTURE_CUBE_MAP_NEGATIVE_X, @@ -1343,6 +1348,7 @@ bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m const Pair<StringName, RID> *textures = p_material->textures.ptr(); const ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptr(); + const ShaderLanguage::DataType *texture_types = p_material->shader->texture_types.ptr(); state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TEXTURE_SIZE, p_skeleton_tex_size); @@ -1356,22 +1362,66 @@ bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m if (!t) { - switch (texture_hints[i]) { - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); + GLenum target = GL_TEXTURE_2D; + GLuint tex = 0; + switch (texture_types[i]) { + case ShaderLanguage::TYPE_ISAMPLER2D: + case ShaderLanguage::TYPE_USAMPLER2D: + case ShaderLanguage::TYPE_SAMPLER2D: { + + switch (texture_hints[i]) { + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { + tex = storage->resources.black_tex; + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { + tex = storage->resources.aniso_tex; + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { + tex = storage->resources.normal_tex; + } break; + default: { + tex = storage->resources.white_tex; + } break; + } + + } break; + + case ShaderLanguage::TYPE_SAMPLERCUBE: { + // TODO } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { - glBindTexture(GL_TEXTURE_2D, storage->resources.aniso_tex); + + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: + case ShaderLanguage::TYPE_SAMPLER3D: { + + target = GL_TEXTURE_3D; + tex = storage->resources.white_tex_3d; + + //switch (texture_hints[i]) { + // TODO + //} + } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { - glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); + + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER2DARRAY: { + + target = GL_TEXTURE_2D_ARRAY; + tex = storage->resources.white_tex_array; + + //switch (texture_hints[i]) { + // TODO + //} + } break; + default: { - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - } break; + } } + glBindTexture(target, tex); continue; } diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 828f6907e3..a1c5d20a14 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -103,6 +103,13 @@ PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT #define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT #define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleEXT +PFNGLTEXIMAGE3DOESPROC glTexImage3DOES; +PFNGLTEXSUBIMAGE3DOESPROC glTexSubImage3DOES; +PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC glCompressedTexSubImage3DOES; +#define glTexImage3D glTexImage3DOES +#define glTexSubImage3D glTexSubImage3DOES +#define glCompressedTexSubImage3D glCompressedTexSubImage3DOES + #elif defined(UWP_ENABLED) #include <GLES2/gl2ext.h> #define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleANGLE @@ -113,6 +120,11 @@ PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT #define GL_MAX_SAMPLES 0x8D57 #endif //!GLES_OVER_GL +#if !defined(GLES_OVER_GL) +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_TEXTURE_3D 0x806F +#endif + void RasterizerStorageGLES2::bind_quad_array() const { glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); @@ -566,11 +578,23 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ texture->target = GL_TEXTURE_CUBE_MAP; texture->images.resize(6); } break; - case VS::TEXTURE_TYPE_2D_ARRAY: + case VS::TEXTURE_TYPE_2D_ARRAY: { + if (config.texture_array_supported) { + texture->target = GL_TEXTURE_2D_ARRAY; + texture->images.resize(p_depth_3d); + } else { + WARN_PRINT_ONCE("Texture Arrays not supported on this hardware."); + return; + } + } break; case VS::TEXTURE_TYPE_3D: { - texture->target = GL_TEXTURE_3D; - ERR_PRINT("3D textures and Texture Arrays are not supported in GLES2. Please switch to the GLES3 backend."); - return; + if (config.texture_3d_supported) { + texture->target = GL_TEXTURE_3D; + texture->images.resize(p_depth_3d); + } else { + WARN_PRINT_ONCE("3D textures not supported on this hardware."); + return; + } } break; default: { ERR_PRINT("Unknown texture type!"); @@ -615,7 +639,42 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ glActiveTexture(GL_TEXTURE0); glBindTexture(texture->target, texture->tex_id); - if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { +#if defined(GLES_OVER_GL) || defined(ANDROID_ENABLED) + if ((p_type == VS::TEXTURE_TYPE_3D && config.texture_3d_supported) || (p_type == VS::TEXTURE_TYPE_2D_ARRAY && config.texture_array_supported)) { + + int width = p_width; + int height = p_height; + int depth = p_depth_3d; + + int mipmaps = 0; + + while (width > 0 || height > 0 || (p_type == VS::TEXTURE_TYPE_3D && depth > 0)) { + width = MAX(1, width); + height = MAX(1, height); + depth = MAX(1, depth); + + glTexImage3D(texture->target, mipmaps, internal_format, width, height, depth, 0, format, type, NULL); + + width /= 2; + height /= 2; + + if (p_type == VS::TEXTURE_TYPE_3D) { + depth /= 2; + } + + mipmaps++; + + if (!(p_flags & VS::TEXTURE_FLAG_MIPMAPS)) + break; + } +#ifdef GLES_OVER_GL + glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1); +#endif + + } else +#endif + if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { //prealloc if video glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, NULL); } @@ -627,8 +686,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND(!texture); - if (texture->target == GL_TEXTURE_3D) { - // Target is set to a 3D texture or array texture, exit early to avoid spamming errors + if ((texture->type == VS::TEXTURE_TYPE_2D_ARRAY && !config.texture_array_supported) || (texture->type == VS::TEXTURE_TYPE_3D && !config.texture_3d_supported)) { return; } ERR_FAIL_COND(!texture->active); @@ -673,7 +731,23 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p } } - GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D; + GLenum blit_target = GL_TEXTURE_2D; + + switch (texture->type) { + case VS::TEXTURE_TYPE_2D: { + blit_target = GL_TEXTURE_2D; + } break; + case VS::TEXTURE_TYPE_CUBEMAP: { + ERR_FAIL_INDEX(p_layer, 6); + blit_target = _cube_side_enum[p_layer]; + } break; + case VS::TEXTURE_TYPE_2D_ARRAY: { + blit_target = GL_TEXTURE_2D_ARRAY; + } break; + case VS::TEXTURE_TYPE_3D: { + blit_target = GL_TEXTURE_3D; + } break; + } texture->data_size = img->get_data().size(); PoolVector<uint8_t>::Read read = img->get_data().read(); @@ -730,23 +804,41 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p int size, ofs; img->get_mipmap_offset_and_size(i, ofs, size); + if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) { - if (compressed) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + if (compressed) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - int bw = w; - int bh = h; + int bw = w; + int bh = h; - glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); - } else { + glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); + } else { + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { + glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]); + } else { + glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); + } + } + } +#if defined(GLES_OVER_GL) || defined(ANDROID_ENABLED) + else { + if (texture->compressed) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { - glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]); + int bw = w; + int bh = h; + + glCompressedTexSubImage3D(blit_target, i, 0, 0, p_layer, bw, bh, 1, internal_format, size, &read[ofs]); } else { - glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glTexSubImage3D(blit_target, i, 0, 0, p_layer, w, h, 1, format, type, &read[ofs]); } } +#endif tsize += size; @@ -1492,6 +1584,7 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { p_shader->texture_count = gen_code.texture_uniforms.size(); p_shader->texture_hints = gen_code.texture_hints; + p_shader->texture_types = gen_code.texture_types; p_shader->uses_vertex_time = gen_code.uses_vertex_time; p_shader->uses_fragment_time = gen_code.uses_fragment_time; @@ -1639,11 +1732,19 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn case ShaderLanguage::TYPE_SAMPLER2DARRAY: case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: { + + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "TextureArray"; + } break; + case ShaderLanguage::TYPE_SAMPLER3D: case ShaderLanguage::TYPE_ISAMPLER3D: case ShaderLanguage::TYPE_USAMPLER3D: { - // Not implemented in GLES2 + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "Texture3D"; } break; } @@ -5795,6 +5896,8 @@ void RasterizerStorageGLES2::initialize() { config.depth_type = GL_UNSIGNED_INT; #ifdef GLES_OVER_GL + config.texture_3d_supported = true; + config.texture_array_supported = config.extensions.has("GL_EXT_texture_array"); config.float_texture_supported = true; config.s3tc_supported = true; config.pvrtc_supported = false; @@ -5802,6 +5905,8 @@ void RasterizerStorageGLES2::initialize() { config.support_npot_repeat_mipmap = true; config.depth_buffer_internalformat = GL_DEPTH_COMPONENT24; #else + config.texture_3d_supported = config.extensions.has("GL_OES_texture_3D"); + config.texture_array_supported = false; config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float"); config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc"); config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") || config.extensions.has("WEBGL_compressed_texture_etc1"); @@ -5840,6 +5945,9 @@ void RasterizerStorageGLES2::initialize() { void *gles2_lib = dlopen("libGLESv2.so", RTLD_LAZY); glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glRenderbufferStorageMultisampleEXT"); glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glFramebufferTexture2DMultisampleEXT"); + glTexImage3DOES = (PFNGLTEXIMAGE3DOESPROC)dlsym(gles2_lib, "glTexImage3DOES"); + glTexSubImage3DOES = (PFNGLTEXSUBIMAGE3DOESPROC)dlsym(gles2_lib, "glTexSubImage3DOES"); + glCompressedTexSubImage3DOES = (PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC)dlsym(gles2_lib, "glCompressedTexSubImage3DOES"); #endif #endif @@ -6062,6 +6170,26 @@ void RasterizerStorageGLES2::initialize() { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, anisotexdata); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); + +#if defined(GLES_OVER_GL) || defined(ANDROID_ENABLED) + glGenTextures(1, &resources.white_tex_3d); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_3D, resources.white_tex_3d); + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 2, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); + +#ifdef GLES_OVER_GL + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); +#endif + + glGenTextures(1, &resources.white_tex_array); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D_ARRAY, resources.white_tex_array); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 8, 8, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 8, 8, 1, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); + glBindTexture(GL_TEXTURE_2D, 0); +#endif } // skeleton buffer diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 83697b9872..d006d2e7f4 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -71,6 +71,8 @@ public: Set<String> extensions; + bool texture_3d_supported; + bool texture_array_supported; bool float_texture_supported; bool s3tc_supported; bool etc1_supported; @@ -109,6 +111,8 @@ public: GLuint black_tex; GLuint normal_tex; GLuint aniso_tex; + GLuint white_tex_3d; + GLuint white_tex_array; GLuint mipmap_blur_fbo; GLuint mipmap_blur_color; @@ -414,6 +418,7 @@ public: Map<StringName, RID> default_textures; + Vector<ShaderLanguage::DataType> texture_types; Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints; bool valid; diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 5dec6f2fee..b4b9b70abc 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -305,6 +305,7 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener r_gen_code.texture_uniforms.resize(max_texture_uniforms); r_gen_code.texture_hints.resize(max_texture_uniforms); + r_gen_code.texture_types.resize(max_texture_uniforms); r_gen_code.uniforms.resize(max_uniforms + max_texture_uniforms); @@ -332,6 +333,7 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener if (SL::is_sampler_type(E->get().type)) { r_gen_code.texture_uniforms.write[E->get().texture_order] = E->key(); r_gen_code.texture_hints.write[E->get().texture_order] = E->get().hint; + r_gen_code.texture_types.write[E->get().texture_order] = E->get().type; } else { r_gen_code.uniforms.write[E->get().order] = E->key(); } @@ -660,6 +662,10 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener code += "texture2D"; } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBE) { code += "textureCube"; + } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER3D) { + code += "texture3D"; + } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2DARRAY) { + code += "texture2DArray"; } } else if (var_node->name == "textureLod") { @@ -669,6 +675,10 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener code += "texture2DLod"; } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBE) { code += "textureCubeLod"; + } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER3D) { + code += "texture3DLod"; + } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2DARRAY) { + code += "texture2DArrayLod"; } } else if (var_node->name == "mix") { @@ -869,6 +879,7 @@ Error ShaderCompilerGLES2::compile(VS::ShaderMode p_mode, const String &p_code, r_gen_code.uniforms.clear(); r_gen_code.texture_uniforms.clear(); r_gen_code.texture_hints.clear(); + r_gen_code.texture_types.clear(); r_gen_code.vertex = String(); r_gen_code.vertex_global = String(); r_gen_code.fragment = String(); diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h index 683c8bf3c4..15cfac9f03 100644 --- a/drivers/gles2/shader_compiler_gles2.h +++ b/drivers/gles2/shader_compiler_gles2.h @@ -54,6 +54,7 @@ public: Vector<CharString> custom_defines; Vector<StringName> uniforms; Vector<StringName> texture_uniforms; + Vector<ShaderLanguage::DataType> texture_types; Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints; String vertex_global; diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index afce403a9f..3b685b3f0b 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -10,6 +10,12 @@ precision highp float; precision highp int; #endif +#ifndef USE_GLES_OVER_GL +#extension GL_OES_texture_3D : enable +#else +#extension GL_EXT_texture_array : enable +#endif + uniform highp mat4 projection_matrix; /* clang-format on */ @@ -229,6 +235,12 @@ VERTEX_SHADER_CODE /* clang-format off */ [fragment] +#ifndef USE_GLES_OVER_GL +#extension GL_OES_texture_3D : enable +#else +#extension GL_EXT_texture_array : enable +#endif + // texture2DLodEXT and textureCubeLodEXT are fragment shader specific. // Do not copy these defines in the vertex section. #ifndef USE_GLES_OVER_GL diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index ac7a8796a3..84aadcbbc3 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -10,6 +10,12 @@ precision highp float; precision highp int; #endif +#ifndef USE_GLES_OVER_GL +#extension GL_OES_texture_3D : enable +#else +#extension GL_EXT_texture_array : enable +#endif + /* clang-format on */ #include "stdlib.glsl" /* clang-format off */ @@ -672,6 +678,12 @@ VERTEX_SHADER_CODE /* clang-format off */ [fragment] +#ifndef USE_GLES_OVER_GL +#extension GL_OES_texture_3D : enable +#else +#extension GL_EXT_texture_array : enable +#endif + // texture2DLodEXT and textureCubeLodEXT are fragment shader specific. // Do not copy these defines in the vertex section. #ifndef USE_GLES_OVER_GL diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index e334d4b093..fb095692bc 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -556,6 +556,7 @@ void VisualShaderEditor::_update_graph() { } Ref<VisualShaderNodeUniform> uniform = vsnode; + Ref<VisualShaderNodeScalarUniform> scalar_uniform = vsnode; if (uniform.is_valid()) { graph->add_child(node); _update_created_node(node); @@ -570,7 +571,9 @@ void VisualShaderEditor::_update_graph() { //shortcut VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0); node->set_slot(0, false, VisualShaderNode::PORT_TYPE_SCALAR, Color(), true, port_right, type_color[port_right]); - continue; + if (!scalar_uniform.is_valid()) { + continue; + } } port_offset++; } @@ -582,11 +585,16 @@ void VisualShaderEditor::_update_graph() { } } - if (custom_editor && vsnode->get_output_port_count() > 0 && vsnode->get_output_port_name(0) == "" && (vsnode->get_input_port_count() == 0 || vsnode->get_input_port_name(0) == "")) { + if (custom_editor && !scalar_uniform.is_valid() && vsnode->get_output_port_count() > 0 && vsnode->get_output_port_name(0) == "" && (vsnode->get_input_port_count() == 0 || vsnode->get_input_port_name(0) == "")) { //will be embedded in first port } else if (custom_editor) { + port_offset++; node->add_child(custom_editor); + if (scalar_uniform.is_valid()) { + custom_editor->call_deferred("_show_prop_names", true); + continue; + } custom_editor = NULL; } @@ -2972,6 +2980,13 @@ public: bool updating; Ref<VisualShaderNode> node; Vector<EditorProperty *> properties; + Vector<Label *> prop_names; + + void _show_prop_names(bool p_show) { + for (int i = 0; i < prop_names.size(); i++) { + prop_names[i]->set_visible(p_show); + } + } void setup(Ref<Resource> p_parent_resource, Vector<EditorProperty *> p_properties, const Vector<StringName> &p_names, Ref<VisualShaderNode> p_node) { parent_resource = p_parent_resource; @@ -2981,7 +2996,20 @@ public: for (int i = 0; i < p_properties.size(); i++) { - add_child(p_properties[i]); + HBoxContainer *hbox = memnew(HBoxContainer); + hbox->set_h_size_flags(SIZE_EXPAND_FILL); + add_child(hbox); + + Label *prop_name = memnew(Label); + String prop_name_str = p_names[i]; + prop_name_str = prop_name_str.capitalize() + ":"; + prop_name->set_text(prop_name_str); + prop_name->set_visible(false); + hbox->add_child(prop_name); + prop_names.push_back(prop_name); + + p_properties[i]->set_h_size_flags(SIZE_EXPAND_FILL); + hbox->add_child(p_properties[i]); bool res_prop = Object::cast_to<EditorPropertyResource>(p_properties[i]); if (res_prop) { @@ -3003,6 +3031,7 @@ public: ClassDB::bind_method("_refresh_request", &VisualShaderNodePluginDefaultEditor::_refresh_request); ClassDB::bind_method("_resource_selected", &VisualShaderNodePluginDefaultEditor::_resource_selected); ClassDB::bind_method("_open_inspector", &VisualShaderNodePluginDefaultEditor::_open_inspector); + ClassDB::bind_method("_show_prop_names", &VisualShaderNodePluginDefaultEditor::_show_prop_names); } }; diff --git a/misc/dist/html/fixed-size.html b/misc/dist/html/fixed-size.html index 1cc6fd715e..6c6a3a5d2d 100644 --- a/misc/dist/html/fixed-size.html +++ b/misc/dist/html/fixed-size.html @@ -2,6 +2,7 @@ <html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang=""> <head> <meta charset="utf-8" /> + <link id='-gd-engine-icon' rel='icon' type='image/png' href='favicon.png' /> <title></title> <style type="text/css"> diff --git a/misc/dist/html/full-size.html b/misc/dist/html/full-size.html index 9269227d02..92b65257d4 100644 --- a/misc/dist/html/full-size.html +++ b/misc/dist/html/full-size.html @@ -3,6 +3,7 @@ <head> <meta charset='utf-8' /> <meta name='viewport' content='width=device-width, user-scalable=no' /> + <link id='-gd-engine-icon' rel='icon' type='image/png' href='favicon.png' /> <title></title> <style type='text/css'> diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index cf1fc3f175..00c7e87568 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -363,8 +363,10 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { }; float VideoStreamPlaybackTheora::get_time() const { - - return time - AudioServer::get_singleton()->get_output_latency() - delay_compensation; //-((get_total())/(float)vi.rate); + // FIXME: AudioServer output latency was fixed in af9bb0e, previously it used to + // systematically return 0. Now that it gives a proper latency, it broke this + // code where the delay compensation likely never really worked. + return time - /* AudioServer::get_singleton()->get_output_latency() - */ delay_compensation; }; Ref<Texture> VideoStreamPlaybackTheora::get_texture() const { diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp index 41f9e67672..2763d30bb5 100644 --- a/modules/webm/video_stream_webm.cpp +++ b/modules/webm/video_stream_webm.cpp @@ -393,17 +393,22 @@ int VideoStreamPlaybackWebm::get_mix_rate() const { inline bool VideoStreamPlaybackWebm::has_enough_video_frames() const { if (video_frames_pos > 0) { - - const double audio_delay = AudioServer::get_singleton()->get_output_latency(); + // FIXME: AudioServer output latency was fixed in af9bb0e, previously it used to + // systematically return 0. Now that it gives a proper latency, it broke this + // code where the delay compensation likely never really worked. + //const double audio_delay = AudioServer::get_singleton()->get_output_latency(); const double video_time = video_frames[video_frames_pos - 1]->time; - return video_time >= time + audio_delay + delay_compensation; + return video_time >= time + /* audio_delay + */ delay_compensation; } return false; } bool VideoStreamPlaybackWebm::should_process(WebMFrame &video_frame) { - const double audio_delay = AudioServer::get_singleton()->get_output_latency(); - return video_frame.time >= time + audio_delay + delay_compensation; + // FIXME: AudioServer output latency was fixed in af9bb0e, previously it used to + // systematically return 0. Now that it gives a proper latency, it broke this + // code where the delay compensation likely never really worked. + //const double audio_delay = AudioServer::get_singleton()->get_output_latency(); + return video_frame.time >= time + /* audio_delay + */ delay_compensation; } void VideoStreamPlaybackWebm::delete_pointers() { diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 9b93d4f140..c1cb8bcb58 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -86,7 +86,7 @@ public: ERR_FAIL_COND_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", "Invalid method or HTTP version."); String filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export"); - String basereq = "/tmp_js_export"; + const String basereq = "/tmp_js_export"; String ctype = ""; if (req[1] == basereq + ".html") { filepath += ".html"; @@ -97,8 +97,13 @@ public: } else if (req[1] == basereq + ".pck") { filepath += ".pck"; ctype = "application/octet-stream"; - } else if (req[1] == basereq + ".png") { - filepath += ".png"; + } else if (req[1] == basereq + ".png" || req[1] == "/favicon.png") { + // Also allow serving the generated favicon for a smoother loading experience. + if (req[1] == "/favicon.png") { + filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png"); + } else { + filepath += ".png"; + } ctype = "image/png"; } else if (req[1] == basereq + ".wasm") { filepath += ".wasm"; @@ -470,11 +475,10 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese } Ref<Image> splash; - String splash_path = GLOBAL_GET("application/boot_splash/image"); - splash_path = splash_path.strip_edges(); + const String splash_path = String(GLOBAL_GET("application/boot_splash/image")).strip_edges(); if (!splash_path.empty()) { splash.instance(); - Error err = splash->load(splash_path); + const Error err = splash->load(splash_path); if (err) { EditorNode::get_singleton()->show_warning(TTR("Could not read boot splash image file:") + "\n" + splash_path + "\n" + TTR("Using default boot splash image.")); splash.unref(); @@ -483,11 +487,32 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese if (splash.is_null()) { splash = Ref<Image>(memnew(Image(boot_splash_png))); } - String png_path = p_path.get_base_dir().plus_file(p_path.get_file().get_basename() + ".png"); - if (splash->save_png(png_path) != OK) { - EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + png_path); + const String splash_png_path = p_path.get_base_dir().plus_file(p_path.get_file().get_basename() + ".png"); + if (splash->save_png(splash_png_path) != OK) { + EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + splash_png_path); return ERR_FILE_CANT_WRITE; } + + // Save a favicon that can be accessed without waiting for the project to finish loading. + // This way, the favicon can be displayed immediately when loading the page. + Ref<Image> favicon; + const String favicon_path = String(GLOBAL_GET("application/config/icon")).strip_edges(); + if (!favicon_path.empty()) { + favicon.instance(); + const Error err = favicon->load(favicon_path); + if (err) { + favicon.unref(); + } + } + + if (favicon.is_valid()) { + const String favicon_png_path = p_path.get_base_dir().plus_file("favicon.png"); + if (favicon->save_png(favicon_png_path) != OK) { + EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + favicon_png_path); + return ERR_FILE_CANT_WRITE; + } + } + return OK; } @@ -536,9 +561,8 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese return OK; } - String basepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export"); - String path = basepath + ".html"; - Error err = export_project(p_preset, true, path, p_debug_flags); + const String basepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export"); + Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags); if (err != OK) { // Export generates several files, clean them up on failure. DirAccess::remove_file_or_error(basepath + ".html"); @@ -546,13 +570,14 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese DirAccess::remove_file_or_error(basepath + ".pck"); DirAccess::remove_file_or_error(basepath + ".png"); DirAccess::remove_file_or_error(basepath + ".wasm"); + DirAccess::remove_file_or_error(EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png")); return err; } - IP_Address bind_ip; - uint16_t bind_port = EDITOR_GET("export/web/http_port"); + const uint16_t bind_port = EDITOR_GET("export/web/http_port"); // Resolve host if needed. - String bind_host = EDITOR_GET("export/web/http_host"); + const String bind_host = EDITOR_GET("export/web/http_host"); + IP_Address bind_ip; if (bind_host.is_valid_ip_address()) { bind_ip = bind_host; } else { diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index f59e3461b1..acb1b0b5a0 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "cpu_particles_2d.h" - +#include "core/core_string_names.h" #include "scene/2d/canvas_item.h" #include "scene/2d/particles_2d.h" #include "scene/resources/particles_material.h" @@ -169,10 +169,20 @@ void CPUParticles2D::_update_mesh_texture() { vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, tex_size.y)); vertices.push_back(-tex_size * 0.5 + Vector2(0, tex_size.y)); PoolVector<Vector2> uvs; - uvs.push_back(Vector2(0, 0)); - uvs.push_back(Vector2(1, 0)); - uvs.push_back(Vector2(1, 1)); - uvs.push_back(Vector2(0, 1)); + AtlasTexture *atlas_texure = Object::cast_to<AtlasTexture>(*texture); + if (atlas_texure && atlas_texure->get_atlas().is_valid()) { + Rect2 region_rect = atlas_texure->get_region(); + Size2 atlas_size = atlas_texure->get_atlas()->get_size(); + uvs.push_back(Vector2(region_rect.position.x / atlas_size.x, region_rect.position.y / atlas_size.y)); + uvs.push_back(Vector2((region_rect.position.x + region_rect.size.x) / atlas_size.x, region_rect.position.y / atlas_size.y)); + uvs.push_back(Vector2((region_rect.position.x + region_rect.size.x) / atlas_size.x, (region_rect.position.y + region_rect.size.y) / atlas_size.y)); + uvs.push_back(Vector2(region_rect.position.x / atlas_size.x, (region_rect.position.y + region_rect.size.y) / atlas_size.y)); + } else { + uvs.push_back(Vector2(0, 0)); + uvs.push_back(Vector2(1, 0)); + uvs.push_back(Vector2(1, 1)); + uvs.push_back(Vector2(0, 1)); + } PoolVector<Color> colors; colors.push_back(Color(1, 1, 1, 1)); colors.push_back(Color(1, 1, 1, 1)); @@ -198,12 +208,29 @@ void CPUParticles2D::_update_mesh_texture() { } void CPUParticles2D::set_texture(const Ref<Texture> &p_texture) { + if (p_texture == texture) + return; + + if (texture.is_valid()) + texture->disconnect(CoreStringNames::get_singleton()->changed, this, "_texture_changed"); texture = p_texture; + + if (texture.is_valid()) + texture->connect(CoreStringNames::get_singleton()->changed, this, "_texture_changed"); + update(); _update_mesh_texture(); } +void CPUParticles2D::_texture_changed() { + + if (texture.is_valid()) { + update(); + _update_mesh_texture(); + } +} + Ref<Texture> CPUParticles2D::get_texture() const { return texture; @@ -1315,6 +1342,7 @@ void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles2D::convert_from_particles); ClassDB::bind_method(D_METHOD("_update_render_thread"), &CPUParticles2D::_update_render_thread); + ClassDB::bind_method(D_METHOD("_texture_changed"), &CPUParticles2D::_texture_changed); ADD_GROUP("Emission Shape", "emission_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape"); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 085ec99ea0..d59b94bcbb 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -186,6 +186,8 @@ private: void _set_redraw(bool p_redraw); + void _texture_changed(); + protected: static void _bind_methods(); void _notification(int p_what); diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index bb5260b15e..079907db07 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -266,7 +266,7 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const { if (dragging) - return (vertical ? CURSOR_VSIZE : CURSOR_HSIZE); + return (vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT); if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) { @@ -275,11 +275,11 @@ Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const if (vertical) { if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep) - return CURSOR_VSIZE; + return CURSOR_VSPLIT; } else { if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep) - return CURSOR_HSIZE; + return CURSOR_HSPLIT; } } diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index daf770e92a..8f0e0058ea 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -3039,6 +3039,11 @@ String VisualShaderNodeScalarUniform::get_output_port_name(int p_port) const { } String VisualShaderNodeScalarUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + if (hint == HINT_RANGE) { + return "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ");\n"; + } else if (hint == HINT_RANGE_STEP) { + return "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ");\n"; + } return "uniform float " + get_uniform_name() + ";\n"; } @@ -3046,7 +3051,83 @@ String VisualShaderNodeScalarUniform::generate_code(Shader::Mode p_mode, VisualS return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } +void VisualShaderNodeScalarUniform::set_hint(Hint p_hint) { + hint = p_hint; + emit_changed(); +} + +VisualShaderNodeScalarUniform::Hint VisualShaderNodeScalarUniform::get_hint() const { + return hint; +} + +void VisualShaderNodeScalarUniform::set_min(float p_value) { + hint_range_min = p_value; + emit_changed(); +} + +float VisualShaderNodeScalarUniform::get_min() const { + return hint_range_min; +} + +void VisualShaderNodeScalarUniform::set_max(float p_value) { + hint_range_max = p_value; + emit_changed(); +} + +float VisualShaderNodeScalarUniform::get_max() const { + return hint_range_max; +} + +void VisualShaderNodeScalarUniform::set_step(float p_value) { + hint_range_step = p_value; + emit_changed(); +} + +float VisualShaderNodeScalarUniform::get_step() const { + return hint_range_step; +} + +void VisualShaderNodeScalarUniform::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeScalarUniform::set_hint); + ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeScalarUniform::get_hint); + + ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeScalarUniform::set_min); + ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeScalarUniform::get_min); + + ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeScalarUniform::set_max); + ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeScalarUniform::get_max); + + ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeScalarUniform::set_step); + ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeScalarUniform::get_step); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range+Step"), "set_hint", "get_hint"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "min"), "set_min", "get_min"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "max"), "set_max", "get_max"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "step"), "set_step", "get_step"); + + BIND_ENUM_CONSTANT(HINT_NONE); + BIND_ENUM_CONSTANT(HINT_RANGE); + BIND_ENUM_CONSTANT(HINT_RANGE_STEP); +} + +Vector<StringName> VisualShaderNodeScalarUniform::get_editable_properties() const { + Vector<StringName> props; + props.push_back("hint"); + if (hint == HINT_RANGE || hint == HINT_RANGE_STEP) { + props.push_back("min"); + props.push_back("max"); + } + if (hint == HINT_RANGE_STEP) { + props.push_back("step"); + } + return props; +} + VisualShaderNodeScalarUniform::VisualShaderNodeScalarUniform() { + hint = HINT_NONE; + hint_range_min = 0.0; + hint_range_max = 1.0; + hint_range_step = 0.1; } ////////////// Boolean Uniform diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index cca37273d9..3d57fd0efc 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -1301,6 +1301,22 @@ class VisualShaderNodeScalarUniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeScalarUniform, VisualShaderNodeUniform); public: + enum Hint { + HINT_NONE, + HINT_RANGE, + HINT_RANGE_STEP, + }; + +private: + Hint hint; + float hint_range_min; + float hint_range_max; + float hint_range_step; + +protected: + static void _bind_methods(); + +public: virtual String get_caption() const; virtual int get_input_port_count() const; @@ -1314,9 +1330,25 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty + void set_hint(Hint p_hint); + Hint get_hint() const; + + void set_min(float p_value); + float get_min() const; + + void set_max(float p_value); + float get_max() const; + + void set_step(float p_value); + float get_step() const; + + virtual Vector<StringName> get_editable_properties() const; + VisualShaderNodeScalarUniform(); }; +VARIANT_ENUM_CAST(VisualShaderNodeScalarUniform::Hint) + /////////////////////////////////////// class VisualShaderNodeBooleanUniform : public VisualShaderNodeUniform { diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 1c84e97196..2a5a5040b6 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "audio_server.h" + #include "core/io/resource_loader.h" #include "core/os/file_access.h" #include "core/os/os.h" @@ -36,14 +37,11 @@ #include "scene/resources/audio_stream_sample.h" #include "servers/audio/audio_driver_dummy.h" #include "servers/audio/effects/audio_effect_compressor.h" -#ifdef TOOLS_ENABLED +#ifdef TOOLS_ENABLED #define MARK_EDITED set_edited(true); - #else - #define MARK_EDITED - #endif AudioDriver *AudioDriver::singleton = NULL; @@ -1405,8 +1403,6 @@ AudioServer::AudioServer() { mix_frames = 0; channel_count = 0; to_mix = 0; - output_latency = 0; - output_latency_ticks = 0; #ifdef DEBUG_ENABLED prof_time = 0; #endif diff --git a/servers/audio_server.h b/servers/audio_server.h index 815200c811..eff66d4008 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -240,9 +240,6 @@ private: Mutex *audio_data_lock; - float output_latency; - uint64_t output_latency_ticks; - void init_channels_and_buffers(); void _mix_step(); diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 14d2f6d086..98ccfcfc68 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -1969,14 +1969,14 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true }, { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, - { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true }, - { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, + { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false }, + { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true }, { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true }, { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, - { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true }, - { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, + { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false }, + { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true }, { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true }, @@ -2006,10 +2006,10 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, - { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, + { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, - { "textureLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, + { "textureLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true }, { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false }, @@ -2986,14 +2986,32 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons bool is_const = false; int array_size = 0; - if (!_find_identifier(p_block, p_builtin_types, identifier, &data_type, &ident_type, &is_const, &array_size)) { - _set_error("Unknown identifier in expression: " + String(identifier)); - return NULL; - } + if (p_block && p_block->block_tag != SubClassTag::TAG_GLOBAL) { + int idx = 0; + bool found = false; - if (ident_type == IDENTIFIER_FUNCTION) { - _set_error("Can't use function as identifier: " + String(identifier)); - return NULL; + while (builtin_func_defs[idx].name) { + if (builtin_func_defs[idx].tag == p_block->block_tag && builtin_func_defs[idx].name == identifier) { + found = true; + break; + } + idx++; + } + if (!found) { + _set_error("Unknown identifier in expression: " + String(identifier)); + return NULL; + } + } else { + + if (!_find_identifier(p_block, p_builtin_types, identifier, &data_type, &ident_type, &is_const, &array_size)) { + _set_error("Unknown identifier in expression: " + String(identifier)); + return NULL; + } + + if (ident_type == IDENTIFIER_FUNCTION) { + _set_error("Can't use function as identifier: " + String(identifier)); + return NULL; + } } Node *index_expression = NULL; @@ -3009,7 +3027,9 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (tk.type == TK_PERIOD) { completion_class = TAG_ARRAY; + p_block->block_tag = SubClassTag::TAG_ARRAY; call_expression = _parse_and_reduce_expression(p_block, p_builtin_types); + p_block->block_tag = SubClassTag::TAG_GLOBAL; if (!call_expression) return NULL; data_type = call_expression->get_datatype(); @@ -3281,9 +3301,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons _set_error("Index out of range (0-1)"); return NULL; } - } else { - _set_error("Only integer constants are allowed as index at the moment"); - return NULL; } switch (expr->get_datatype()) { @@ -3307,9 +3324,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons _set_error("Index out of range (0-2)"); return NULL; } - } else { - _set_error("Only integer constants are allowed as index at the moment"); - return NULL; } switch (expr->get_datatype()) { @@ -3332,9 +3346,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons _set_error("Index out of range (0-3)"); return NULL; } - } else { - _set_error("Only integer constants are allowed as index at the moment"); - return NULL; } switch (expr->get_datatype()) { @@ -4700,10 +4711,8 @@ Error ShaderLanguage::_validate_datatype(DataType p_type) { case TYPE_UVEC4: case TYPE_ISAMPLER2D: case TYPE_USAMPLER2D: - case TYPE_SAMPLER3D: case TYPE_ISAMPLER3D: case TYPE_USAMPLER3D: - case TYPE_SAMPLER2DARRAY: case TYPE_USAMPLER2DARRAY: case TYPE_ISAMPLER2DARRAY: invalid_type = true; diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index e5c3c6852c..f7b02ab70b 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -279,6 +279,11 @@ public: ARGUMENT_QUALIFIER_INOUT, }; + enum SubClassTag { + TAG_GLOBAL, + TAG_ARRAY, + }; + struct Node { Node *next; @@ -431,6 +436,7 @@ public: }; int block_type; + SubClassTag block_tag; struct Variable { DataType type; @@ -449,6 +455,7 @@ public: parent_function(NULL), parent_block(NULL), block_type(BLOCK_TYPE_STANDART), + block_tag(SubClassTag::TAG_GLOBAL), single_statement(false) {} }; @@ -713,11 +720,6 @@ private: bool _validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message = NULL); bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = NULL); - enum SubClassTag { - TAG_GLOBAL, - TAG_ARRAY, - }; - struct BuiltinFuncDef { enum { MAX_ARGS = 5 }; const char *name; diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index e07e188ec6..c90e061eb7 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -168,7 +168,7 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor VisualServerRaster::redraw_request(); } - if ((!ci->commands.empty() && p_clip_rect.intersects(global_rect)) || ci->vp_render || ci->copy_back_buffer) { + if ((!ci->commands.empty() && p_clip_rect.intersects_touch(global_rect)) || ci->vp_render || ci->copy_back_buffer) { //something to draw? ci->final_transform = xform; ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a); |