summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/Skeleton2D.xml5
-rw-r--r--doc/classes/VisualShaderNodeScalarUniform.xml25
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp70
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp168
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.h5
-rw-r--r--drivers/gles2/shader_compiler_gles2.cpp11
-rw-r--r--drivers/gles2/shader_compiler_gles2.h1
-rw-r--r--drivers/gles2/shaders/canvas.glsl12
-rw-r--r--drivers/gles2/shaders/scene.glsl12
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp35
-rw-r--r--scene/resources/visual_shader_nodes.cpp81
-rw-r--r--scene/resources/visual_shader_nodes.h32
-rw-r--r--servers/visual/shader_language.cpp14
13 files changed, 429 insertions, 42 deletions
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/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/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index ef0ea96b5f..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 },
@@ -4711,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;