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 {