diff --git a/doc/classes/ExternalTexture.xml b/doc/classes/ExternalTexture.xml
new file mode 100644
index 00000000000..54b2ad7f81b
--- /dev/null
+++ b/doc/classes/ExternalTexture.xml
@@ -0,0 +1,25 @@
+
+
+
+ Adds support for external textures as defined by https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image_external.txt
+
+
+
+
+
+
+
+
+
+ Returns the external texture name.
+
+
+
+
+
+ External texture size.
+
+
+
+
+
diff --git a/doc/classes/Shader.xml b/doc/classes/Shader.xml
index 91dc9638127..3fbd06ce3d5 100644
--- a/doc/classes/Shader.xml
+++ b/doc/classes/Shader.xml
@@ -55,6 +55,10 @@
Returns the shader's code as the user has written it, not the full generated code used internally.
+
+ Returns the shader's custom defines. Custom defines can be used in Godot to add GLSL preprocessor directives (e.g: extensions) required for the shader logic.
+ [b]Note:[/b] Custom defines are not validated by the Godot shader parser, so care should be taken when using them.
+
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index 00758a73a40..934ca769d46 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -262,6 +262,10 @@ public:
void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) {}
RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { return RID(); }
+ void shader_add_custom_define(RID p_shader, const String &p_define) {}
+ void shader_get_custom_defines(RID p_shader, Vector *p_defines) const {}
+ void shader_clear_custom_defines(RID p_shader) {}
+
/* COMMON MATERIAL API */
RID material_create() { return RID(); }
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index cd6a7d86c63..7440c41fbd8 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -69,6 +69,8 @@ GLuint RasterizerStorageGLES2::system_fbo = 0;
#define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
#define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
+#define _GL_TEXTURE_EXTERNAL_OES 0x8D65
+
#ifdef GLES_OVER_GL
#define _GL_HALF_FLOAT_OES 0x140B
#else
@@ -562,6 +564,10 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
texture->target = GL_TEXTURE_2D;
texture->images.resize(1);
} break;
+ case VS::TEXTURE_TYPE_EXTERNAL: {
+ texture->target = _GL_TEXTURE_EXTERNAL_OES;
+ texture->images.resize(0);
+ } break;
case VS::TEXTURE_TYPE_CUBEMAP: {
texture->target = GL_TEXTURE_CUBE_MAP;
texture->images.resize(6);
@@ -578,44 +584,59 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
}
}
- texture->alloc_width = texture->width;
- texture->alloc_height = texture->height;
- texture->resize_to_po2 = false;
- if (!config.support_npot_repeat_mipmap) {
- int po2_width = next_power_of_2(p_width);
- int po2_height = next_power_of_2(p_height);
+ if (p_type != VS::TEXTURE_TYPE_EXTERNAL) {
+ texture->alloc_width = texture->width;
+ texture->alloc_height = texture->height;
+ texture->resize_to_po2 = false;
+ if (!config.support_npot_repeat_mipmap) {
+ int po2_width = next_power_of_2(p_width);
+ int po2_height = next_power_of_2(p_height);
- bool is_po2 = p_width == po2_width && p_height == po2_height;
+ bool is_po2 = p_width == po2_width && p_height == po2_height;
- if (!is_po2 && (p_flags & VS::TEXTURE_FLAG_REPEAT || p_flags & VS::TEXTURE_FLAG_MIPMAPS)) {
+ if (!is_po2 && (p_flags & VS::TEXTURE_FLAG_REPEAT || p_flags & VS::TEXTURE_FLAG_MIPMAPS)) {
- if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
- //not supported
- ERR_PRINTS("Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture->path + "'. Mipmaps and repeat disabled.");
- texture->flags &= ~(VS::TEXTURE_FLAG_REPEAT | VS::TEXTURE_FLAG_MIPMAPS);
- } else {
- texture->alloc_height = po2_height;
- texture->alloc_width = po2_width;
- texture->resize_to_po2 = true;
+ if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+ //not supported
+ ERR_PRINT("Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture->path + "'. Mipmaps and repeat disabled.");
+ texture->flags &= ~(VS::TEXTURE_FLAG_REPEAT | VS::TEXTURE_FLAG_MIPMAPS);
+ } else {
+ texture->alloc_height = po2_height;
+ texture->alloc_width = po2_width;
+ texture->resize_to_po2 = true;
+ }
}
}
+
+ Image::Format real_format;
+ _get_gl_image_and_format(Ref(),
+ texture->format,
+ texture->flags,
+ real_format,
+ format,
+ internal_format,
+ type,
+ compressed,
+ texture->resize_to_po2);
+
+ texture->gl_format_cache = format;
+ texture->gl_type_cache = type;
+ texture->gl_internal_format_cache = internal_format;
+ texture->data_size = 0;
+ texture->mipmaps = 1;
+
+ texture->compressed = compressed;
}
- Image::Format real_format;
- _get_gl_image_and_format(Ref(), texture->format, texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2);
-
- texture->gl_format_cache = format;
- texture->gl_type_cache = type;
- texture->gl_internal_format_cache = internal_format;
- texture->data_size = 0;
- texture->mipmaps = 1;
-
- texture->compressed = compressed;
-
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
- if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+ if (p_type == VS::TEXTURE_TYPE_EXTERNAL) {
+ glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ } else 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);
}
@@ -635,6 +656,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref &p
ERR_FAIL_COND(texture->render_target);
ERR_FAIL_COND(texture->format != p_image->get_format());
ERR_FAIL_COND(p_image.is_null());
+ ERR_FAIL_COND(texture->type == VS::TEXTURE_TYPE_EXTERNAL);
GLenum type;
GLenum format;
@@ -1624,6 +1646,7 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, Listget();
}
+void RasterizerStorageGLES2::shader_add_custom_define(RID p_shader, const String &p_define) {
+
+ Shader *shader = shader_owner.get(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ shader->shader->add_custom_define(p_define);
+
+ _shader_make_dirty(shader);
+}
+
+void RasterizerStorageGLES2::shader_get_custom_defines(RID p_shader, Vector *p_defines) const {
+
+ Shader *shader = shader_owner.get(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ shader->shader->get_custom_defines(p_defines);
+}
+
+void RasterizerStorageGLES2::shader_clear_custom_defines(RID p_shader) {
+
+ Shader *shader = shader_owner.get(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ shader->shader->clear_custom_defines();
+
+ _shader_make_dirty(shader);
+}
+
/* COMMON MATERIAL API */
void RasterizerStorageGLES2::_material_make_dirty(Material *p_material) const {
diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h
index 83697b9872b..eed877c4750 100644
--- a/drivers/gles2/rasterizer_storage_gles2.h
+++ b/drivers/gles2/rasterizer_storage_gles2.h
@@ -525,6 +525,10 @@ public:
virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture);
virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const;
+ virtual void shader_add_custom_define(RID p_shader, const String &p_define);
+ virtual void shader_get_custom_defines(RID p_shader, Vector *p_defines) const;
+ virtual void shader_clear_custom_defines(RID p_shader);
+
void _update_shader(Shader *p_shader) const;
void update_dirty_shaders();
diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp
index 5dec6f2fee6..6c07a8918d5 100644
--- a/drivers/gles2/shader_compiler_gles2.cpp
+++ b/drivers/gles2/shader_compiler_gles2.cpp
@@ -656,7 +656,8 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
if (var_node->name == "texture") {
// emit texture call
- if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2D) {
+ if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2D ||
+ op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLEREXT) {
code += "texture2D";
} else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBE) {
code += "textureCube";
diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp
index 8bb1ef7f0fe..dc422f70a8f 100644
--- a/drivers/gles2/shader_gles2.cpp
+++ b/drivers/gles2/shader_gles2.cpp
@@ -182,6 +182,16 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
#endif
+#ifdef ANDROID_ENABLED
+ strings.push_back("#define ANDROID_ENABLED\n");
+#endif
+
+ for (int i = 0; i < custom_defines.size(); i++) {
+
+ strings.push_back(custom_defines[i].get_data());
+ strings.push_back("\n");
+ }
+
for (int j = 0; j < conditional_count; j++) {
bool enable = (conditional_version.version & (1 << j)) > 0;
@@ -941,6 +951,10 @@ void ShaderGLES2::use_material(void *p_material) {
} break;
+ case ShaderLanguage::TYPE_SAMPLEREXT: {
+
+ } break;
+
case ShaderLanguage::TYPE_ISAMPLER2D: {
} break;
@@ -1060,6 +1074,10 @@ void ShaderGLES2::use_material(void *p_material) {
} break;
+ case ShaderLanguage::TYPE_SAMPLEREXT: {
+
+ } break;
+
case ShaderLanguage::TYPE_ISAMPLER2D: {
} break;
diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h
index f2953c9ae8e..9716536b7e6 100644
--- a/drivers/gles2/shader_gles2.h
+++ b/drivers/gles2/shader_gles2.h
@@ -246,6 +246,16 @@ public:
custom_defines.push_back(p_define.utf8());
}
+ void get_custom_defines(Vector *p_defines) {
+ for (int i = 0; i < custom_defines.size(); i++) {
+ p_defines->push_back(custom_defines[i].get_data());
+ }
+ }
+
+ void clear_custom_defines() {
+ custom_defines.clear();
+ }
+
virtual ~ShaderGLES2();
};
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 6baf69dc7bc..4364f1ccb19 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -101,6 +101,8 @@
#define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
#define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
+#define _GL_TEXTURE_EXTERNAL_OES 0x8D65
+
#ifndef GLES_OVER_GL
#define glClearDepth glClearDepthf
#endif
@@ -663,6 +665,10 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_
texture->target = GL_TEXTURE_2D;
texture->images.resize(1);
} break;
+ case VS::TEXTURE_TYPE_EXTERNAL: {
+ texture->target = _GL_TEXTURE_EXTERNAL_OES;
+ texture->images.resize(0);
+ } break;
case VS::TEXTURE_TYPE_CUBEMAP: {
texture->target = GL_TEXTURE_CUBE_MAP;
texture->images.resize(6);
@@ -677,39 +683,55 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_
} break;
}
- texture->is_npot_repeat_mipmap = false;
+ if (p_type != VS::TEXTURE_TYPE_EXTERNAL) {
+ texture->is_npot_repeat_mipmap = false;
#ifdef JAVASCRIPT_ENABLED
- // WebGL 2.0 on browsers does not seem to properly support compressed non power-of-two (NPOT)
- // textures with repeat/mipmaps, even though NPOT textures should be supported as per the spec.
- // Force decompressing them to work it around on WebGL 2.0 at a performance cost (GH-33058).
- int po2_width = next_power_of_2(p_width);
- int po2_height = next_power_of_2(p_height);
- bool is_po2 = p_width == po2_width && p_height == po2_height;
+ // WebGL 2.0 on browsers does not seem to properly support compressed non power-of-two (NPOT)
+ // textures with repeat/mipmaps, even though NPOT textures should be supported as per the spec.
+ // Force decompressing them to work it around on WebGL 2.0 at a performance cost (GH-33058).
+ int po2_width = next_power_of_2(p_width);
+ int po2_height = next_power_of_2(p_height);
+ bool is_po2 = p_width == po2_width && p_height == po2_height;
- if (!is_po2 && (p_flags & VS::TEXTURE_FLAG_REPEAT || p_flags & VS::TEXTURE_FLAG_MIPMAPS)) {
- texture->is_npot_repeat_mipmap = true;
- }
+ if (!is_po2 && (p_flags & VS::TEXTURE_FLAG_REPEAT || p_flags & VS::TEXTURE_FLAG_MIPMAPS)) {
+ texture->is_npot_repeat_mipmap = true;
+ }
#endif // JAVASCRIPT_ENABLED
- Image::Format real_format;
- _get_gl_image_and_format(Ref(), texture->format, texture->flags, real_format, format, internal_format, type, compressed, srgb, texture->is_npot_repeat_mipmap);
+ Image::Format real_format;
+ _get_gl_image_and_format(Ref(),
+ texture->format,
+ texture->flags,
+ real_format,
+ format,
+ internal_format,
+ type,
+ compressed,
+ srgb,
+ texture->is_npot_repeat_mipmap);
- texture->alloc_width = texture->width;
- texture->alloc_height = texture->height;
- texture->alloc_depth = texture->depth;
+ texture->alloc_width = texture->width;
+ texture->alloc_height = texture->height;
+ texture->alloc_depth = texture->depth;
- texture->gl_format_cache = format;
- texture->gl_type_cache = type;
- texture->gl_internal_format_cache = internal_format;
- texture->compressed = compressed;
- texture->srgb = srgb;
- texture->data_size = 0;
- texture->mipmaps = 1;
+ texture->gl_format_cache = format;
+ texture->gl_type_cache = type;
+ texture->gl_internal_format_cache = internal_format;
+ texture->compressed = compressed;
+ texture->srgb = srgb;
+ texture->data_size = 0;
+ texture->mipmaps = 1;
+ }
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
- if (p_type == VS::TEXTURE_TYPE_3D || p_type == VS::TEXTURE_TYPE_2D_ARRAY) {
+ if (p_type == VS::TEXTURE_TYPE_EXTERNAL) {
+ glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ } else if (p_type == VS::TEXTURE_TYPE_3D || p_type == VS::TEXTURE_TYPE_2D_ARRAY) {
int width = p_width;
int height = p_height;
@@ -757,6 +779,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref &p
ERR_FAIL_COND(texture->render_target);
ERR_FAIL_COND(texture->format != p_image->get_format());
ERR_FAIL_COND(p_image.is_null());
+ ERR_FAIL_COND(texture->type == VS::TEXTURE_TYPE_EXTERNAL);
GLenum type;
GLenum format;
@@ -788,7 +811,8 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref &p
GLenum blit_target = GL_TEXTURE_2D;
switch (texture->type) {
- case VS::TEXTURE_TYPE_2D: {
+ case VS::TEXTURE_TYPE_2D:
+ case VS::TEXTURE_TYPE_EXTERNAL: {
blit_target = GL_TEXTURE_2D;
} break;
case VS::TEXTURE_TYPE_CUBEMAP: {
@@ -989,6 +1013,7 @@ void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref p_image->get_width() || src_y + src_h > p_image->get_height());
ERR_FAIL_COND(dst_x < 0 || dst_y < 0 || dst_x + src_w > texture->alloc_width || dst_y + src_h > texture->alloc_height);
ERR_FAIL_COND(p_dst_mip < 0 || p_dst_mip >= texture->mipmaps);
+ ERR_FAIL_COND(texture->type == VS::TEXTURE_TYPE_EXTERNAL);
GLenum type;
GLenum format;
@@ -1008,7 +1033,8 @@ void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Reftype) {
- case VS::TEXTURE_TYPE_2D: {
+ case VS::TEXTURE_TYPE_2D:
+ case VS::TEXTURE_TYPE_EXTERNAL: {
blit_target = GL_TEXTURE_2D;
} break;
case VS::TEXTURE_TYPE_CUBEMAP: {
@@ -2466,6 +2492,7 @@ void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, Listget();
}
+void RasterizerStorageGLES3::shader_add_custom_define(RID p_shader, const String &p_define) {
+
+ Shader *shader = shader_owner.get(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ shader->shader->add_custom_define(p_define);
+
+ _shader_make_dirty(shader);
+}
+
+void RasterizerStorageGLES3::shader_get_custom_defines(RID p_shader, Vector *p_defines) const {
+
+ Shader *shader = shader_owner.get(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ shader->shader->get_custom_defines(p_defines);
+}
+
+void RasterizerStorageGLES3::shader_clear_custom_defines(RID p_shader) {
+
+ Shader *shader = shader_owner.get(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ shader->shader->clear_custom_defines();
+
+ _shader_make_dirty(shader);
+}
+
/* COMMON MATERIAL API */
void RasterizerStorageGLES3::_material_make_dirty(Material *p_material) const {
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index bd853852fea..72bdce6ba75 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -533,6 +533,10 @@ public:
virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture);
virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const;
+ virtual void shader_add_custom_define(RID p_shader, const String &p_define);
+ virtual void shader_get_custom_defines(RID p_shader, Vector *p_defines) const;
+ virtual void shader_clear_custom_defines(RID p_shader);
+
void _update_shader(Shader *p_shader) const;
void update_dirty_shaders();
diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp
index 4e4d896bd7e..1bf0d3ddcee 100644
--- a/drivers/gles3/shader_compiler_gles3.cpp
+++ b/drivers/gles3/shader_compiler_gles3.cpp
@@ -86,6 +86,7 @@ static int _get_datatype_size(SL::DataType p_type) {
case SL::TYPE_ISAMPLER3D: return 16;
case SL::TYPE_USAMPLER3D: return 16;
case SL::TYPE_SAMPLERCUBE: return 16;
+ case SL::TYPE_SAMPLEREXT: return 16;
}
ERR_FAIL_V(0);
@@ -125,6 +126,7 @@ static int _get_datatype_alignment(SL::DataType p_type) {
case SL::TYPE_ISAMPLER3D: return 16;
case SL::TYPE_USAMPLER3D: return 16;
case SL::TYPE_SAMPLERCUBE: return 16;
+ case SL::TYPE_SAMPLEREXT: return 16;
}
ERR_FAIL_V(0);
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 5d269e22f0e..beaef70bd97 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -210,9 +210,14 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() {
strings.push_back("#version 300 es\n");
#endif
+#ifdef ANDROID_ENABLED
+ strings.push_back("#define ANDROID_ENABLED\n");
+#endif
+
for (int i = 0; i < custom_defines.size(); i++) {
strings.push_back(custom_defines[i].get_data());
+ strings.push_back("\n");
}
for (int j = 0; j < conditional_count; j++) {
diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h
index 2bfe72fbc05..512fd92872c 100644
--- a/drivers/gles3/shader_gles3.h
+++ b/drivers/gles3/shader_gles3.h
@@ -368,6 +368,16 @@ public:
custom_defines.push_back(p_define.utf8());
}
+ void get_custom_defines(Vector *p_defines) {
+ for (int i = 0; i < custom_defines.size(); i++) {
+ p_defines->push_back(custom_defines[i].get_data());
+ }
+ }
+
+ void clear_custom_defines() {
+ custom_defines.clear();
+ }
+
virtual ~ShaderGLES3();
};
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index c0c6b864a5e..767c8582f7f 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -658,6 +658,7 @@ void register_scene_types() {
ClassDB::register_class();
ClassDB::register_class();
ClassDB::register_class();
+ ClassDB::register_class();
ClassDB::register_class();
ClassDB::register_virtual_class();
ClassDB::register_class();
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 44c2a46065f..1549489203b 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -127,6 +127,27 @@ void Shader::get_default_texture_param_list(List *r_textures) const
}
}
+void Shader::set_custom_defines(const String &p_defines) {
+
+ VS::get_singleton()->shader_clear_custom_defines(shader);
+ VS::get_singleton()->shader_add_custom_define(shader, p_defines);
+}
+
+String Shader::get_custom_defines() {
+ Vector custom_defines;
+ VS::get_singleton()->shader_get_custom_defines(shader, &custom_defines);
+
+ String concatenated_defines;
+ for (int i = 0; i < custom_defines.size(); i++) {
+ if (i != 0) {
+ concatenated_defines += "\n";
+ }
+ concatenated_defines += custom_defines[i];
+ }
+
+ return concatenated_defines;
+}
+
bool Shader::is_text_shader() const {
return true;
}
@@ -149,11 +170,15 @@ void Shader::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_texture_param", "param", "texture"), &Shader::set_default_texture_param);
ClassDB::bind_method(D_METHOD("get_default_texture_param", "param"), &Shader::get_default_texture_param);
+ ClassDB::bind_method(D_METHOD("set_custom_defines", "custom_defines"), &Shader::set_custom_defines);
+ ClassDB::bind_method(D_METHOD("get_custom_defines"), &Shader::get_custom_defines);
+
ClassDB::bind_method(D_METHOD("has_param", "name"), &Shader::has_param);
//ClassDB::bind_method(D_METHOD("get_param_list"),&Shader::get_fragment_code);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_code", "get_code");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "custom_defines", PROPERTY_HINT_MULTILINE_TEXT), "set_custom_defines", "get_custom_defines");
BIND_ENUM_CONSTANT(MODE_SPATIAL);
BIND_ENUM_CONSTANT(MODE_CANVAS_ITEM);
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 67ae436a4c3..10e93e79d84 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -79,6 +79,9 @@ public:
Ref get_default_texture_param(const StringName &p_param) const;
void get_default_texture_param_list(List *r_textures) const;
+ void set_custom_defines(const String &p_defines);
+ String get_custom_defines();
+
virtual bool is_text_shader() const;
_FORCE_INLINE_ StringName remap_param(const StringName &p_param) const {
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 4d23f0eb41a..688bd6877bb 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -2621,3 +2621,64 @@ CameraTexture::CameraTexture() {
CameraTexture::~CameraTexture() {
// nothing to do here yet
}
+
+void ExternalTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &ExternalTexture::set_size);
+ ClassDB::bind_method(D_METHOD("get_external_texture_id"), &ExternalTexture::get_external_texture_id);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
+}
+
+uint32_t ExternalTexture::get_external_texture_id() {
+ return VisualServer::get_singleton()->texture_get_texid(texture);
+}
+
+void ExternalTexture::set_size(const Size2 &p_size) {
+
+ if (p_size.width > 0 && p_size.height > 0) {
+ size = p_size;
+ VisualServer::get_singleton()->texture_set_size_override(texture, size.width, size.height, 0);
+ }
+}
+
+int ExternalTexture::get_width() const {
+ return size.width;
+}
+
+int ExternalTexture::get_height() const {
+ return size.height;
+}
+
+Size2 ExternalTexture::get_size() const {
+ return size;
+}
+
+RID ExternalTexture::get_rid() const {
+ return texture;
+}
+
+bool ExternalTexture::has_alpha() const {
+ return true;
+}
+
+void ExternalTexture::set_flags(uint32_t p_flags) {
+ // not supported
+}
+
+uint32_t ExternalTexture::get_flags() const {
+ // not supported
+ return 0;
+}
+
+ExternalTexture::ExternalTexture() {
+ size = Size2(1.0, 1.0);
+ texture = VisualServer::get_singleton()->texture_create();
+
+ VisualServer::get_singleton()->texture_allocate(texture, size.width, size.height, 0, Image::FORMAT_RGBA8, VS::TEXTURE_TYPE_EXTERNAL, 0);
+ _change_notify();
+ emit_changed();
+}
+
+ExternalTexture::~ExternalTexture() {
+ VisualServer::get_singleton()->free(texture);
+}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index fa698d387b8..3d1bd08d69a 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -772,4 +772,34 @@ public:
~CameraTexture();
};
+// External textures as defined by https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image_external.txt
+class ExternalTexture : public Texture {
+ GDCLASS(ExternalTexture, Texture);
+
+private:
+ RID texture;
+ Size2 size;
+
+protected:
+ static void _bind_methods();
+
+public:
+ uint32_t get_external_texture_id();
+
+ virtual Size2 get_size() const;
+ void set_size(const Size2 &p_size);
+
+ virtual int get_width() const;
+ virtual int get_height() const;
+
+ virtual RID get_rid() const;
+ virtual bool has_alpha() const;
+
+ virtual void set_flags(uint32_t p_flags);
+ virtual uint32_t get_flags() const;
+
+ ExternalTexture();
+ ~ExternalTexture();
+};
+
#endif
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index 0008b809b78..0f528ee161d 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -242,6 +242,10 @@ public:
virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0;
virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0;
+ virtual void shader_add_custom_define(RID p_shader, const String &p_define) = 0;
+ virtual void shader_get_custom_defines(RID p_shader, Vector *p_defines) const = 0;
+ virtual void shader_clear_custom_defines(RID p_shader) = 0;
+
/* COMMON MATERIAL API */
virtual RID material_create() = 0;
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index c144523a36f..f5755aafb6b 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -132,6 +132,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
"TYPE_ISAMPLER3D",
"TYPE_USAMPLER3D",
"TYPE_SAMPLERCUBE",
+ "TYPE_SAMPLEREXT",
"INTERPOLATION_FLAT",
"INTERPOLATION_SMOOTH",
"CONST",
@@ -272,6 +273,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_TYPE_ISAMPLER3D, "isampler3D" },
{ TK_TYPE_USAMPLER3D, "usampler3D" },
{ TK_TYPE_SAMPLERCUBE, "samplerCube" },
+ { TK_TYPE_SAMPLEREXT, "samplerExternalOES" },
{ TK_INTERPOLATION_FLAT, "flat" },
{ TK_INTERPOLATION_SMOOTH, "smooth" },
{ TK_CONST, "const" },
@@ -755,7 +757,8 @@ bool ShaderLanguage::is_token_datatype(TokenType p_type) {
p_type == TK_TYPE_SAMPLER3D ||
p_type == TK_TYPE_ISAMPLER3D ||
p_type == TK_TYPE_USAMPLER3D ||
- p_type == TK_TYPE_SAMPLERCUBE);
+ p_type == TK_TYPE_SAMPLERCUBE ||
+ p_type == TK_TYPE_SAMPLEREXT);
}
ShaderLanguage::DataType ShaderLanguage::get_token_datatype(TokenType p_type) {
@@ -841,6 +844,7 @@ String ShaderLanguage::get_datatype_name(DataType p_type) {
case TYPE_ISAMPLER3D: return "isampler3D";
case TYPE_USAMPLER3D: return "usampler3D";
case TYPE_SAMPLERCUBE: return "samplerCube";
+ case TYPE_SAMPLEREXT: return "samplerExternalOES";
}
return "";
@@ -1983,6 +1987,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
{ "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
{ "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLEREXT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLEREXT, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
{ "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
{ "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
@@ -2002,6 +2008,10 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
{ "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
{ "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLEREXT, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLEREXT, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLEREXT, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLEREXT, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
{ "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 },
@@ -2452,7 +2462,8 @@ bool ShaderLanguage::is_sampler_type(DataType p_type) {
p_type == TYPE_SAMPLER3D ||
p_type == TYPE_ISAMPLER3D ||
p_type == TYPE_USAMPLER3D ||
- p_type == TYPE_SAMPLERCUBE;
+ p_type == TYPE_SAMPLERCUBE ||
+ p_type == TYPE_SAMPLEREXT;
}
Variant ShaderLanguage::constant_value_to_variant(const Vector &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) {
@@ -2546,7 +2557,8 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector *)
+ BIND1(shader_clear_custom_defines, RID)
+
/* COMMON MATERIAL API */
BIND0R(RID, material_create)
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index b1bbed24fdb..3b24b06a966 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/servers/visual/visual_server_wrap_mt.h
@@ -126,6 +126,10 @@ public:
FUNC3(shader_set_default_texture_param, RID, const StringName &, RID)
FUNC2RC(RID, shader_get_default_texture_param, RID, const StringName &)
+ FUNC2(shader_add_custom_define, RID, const String &)
+ FUNC2SC(shader_get_custom_defines, RID, Vector *)
+ FUNC1(shader_clear_custom_defines, RID)
+
/* COMMON MATERIAL API */
FUNCRID(material)
diff --git a/servers/visual_server.h b/servers/visual_server.h
index e7662695a6f..17f43fda74d 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -93,6 +93,7 @@ public:
enum TextureType {
TEXTURE_TYPE_2D,
+ TEXTURE_TYPE_EXTERNAL,
TEXTURE_TYPE_CUBEMAP,
TEXTURE_TYPE_2D_ARRAY,
TEXTURE_TYPE_3D,
@@ -193,6 +194,10 @@ public:
virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0;
virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0;
+ virtual void shader_add_custom_define(RID p_shader, const String &p_define) = 0;
+ virtual void shader_get_custom_defines(RID p_shader, Vector *p_defines) const = 0;
+ virtual void shader_clear_custom_defines(RID p_shader) = 0;
+
/* COMMON MATERIAL API */
enum {