2022-03-12 11:19:59 +00:00
/*************************************************************************/
/* texture_storage.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
# ifdef GLES3_ENABLED
# include "texture_storage.h"
# include "config.h"
2022-05-18 15:04:41 +00:00
# include "drivers/gles3/effects/copy_effects.h"
2022-03-12 11:19:59 +00:00
2022-09-04 14:56:24 +00:00
# ifdef ANDROID_ENABLED
# define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
# endif
2022-03-12 11:19:59 +00:00
using namespace GLES3 ;
TextureStorage * TextureStorage : : singleton = nullptr ;
TextureStorage * TextureStorage : : get_singleton ( ) {
return singleton ;
}
2022-02-20 00:08:53 +00:00
static const GLenum _cube_side_enum [ 6 ] = {
GL_TEXTURE_CUBE_MAP_NEGATIVE_X ,
GL_TEXTURE_CUBE_MAP_POSITIVE_X ,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y ,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y ,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z ,
} ;
2022-03-12 11:19:59 +00:00
TextureStorage : : TextureStorage ( ) {
singleton = this ;
2022-04-07 14:00:51 +00:00
system_fbo = 0 ;
2022-02-20 00:08:53 +00:00
{ //create default textures
{ // White Textures
2022-04-07 14:00:51 +00:00
2022-07-22 18:06:19 +00:00
Ref < Image > image = Image : : create_empty ( 4 , 4 , true , Image : : FORMAT_RGBA8 ) ;
2022-02-20 00:08:53 +00:00
image - > fill ( Color ( 1 , 1 , 1 , 1 ) ) ;
2022-05-10 17:02:44 +00:00
image - > generate_mipmaps ( ) ;
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
default_gl_textures [ DEFAULT_GL_TEXTURE_WHITE ] = texture_allocate ( ) ;
texture_2d_initialize ( default_gl_textures [ DEFAULT_GL_TEXTURE_WHITE ] , image ) ;
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
Vector < Ref < Image > > images ;
images . push_back ( image ) ;
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
default_gl_textures [ DEFAULT_GL_TEXTURE_2D_ARRAY_WHITE ] = texture_allocate ( ) ;
texture_2d_layered_initialize ( default_gl_textures [ DEFAULT_GL_TEXTURE_2D_ARRAY_WHITE ] , images , RS : : TEXTURE_LAYERED_2D_ARRAY ) ;
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
for ( int i = 0 ; i < 3 ; i + + ) {
images . push_back ( image ) ;
}
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
default_gl_textures [ DEFAULT_GL_TEXTURE_3D_WHITE ] = texture_allocate ( ) ;
texture_3d_initialize ( default_gl_textures [ DEFAULT_GL_TEXTURE_3D_WHITE ] , image - > get_format ( ) , 4 , 4 , 4 , false , images ) ;
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
for ( int i = 0 ; i < 2 ; i + + ) {
images . push_back ( image ) ;
}
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
default_gl_textures [ DEFAULT_GL_TEXTURE_CUBEMAP_WHITE ] = texture_allocate ( ) ;
texture_2d_layered_initialize ( default_gl_textures [ DEFAULT_GL_TEXTURE_CUBEMAP_WHITE ] , images , RS : : TEXTURE_LAYERED_CUBEMAP ) ;
}
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
{ // black
2022-07-22 18:06:19 +00:00
Ref < Image > image = Image : : create_empty ( 4 , 4 , true , Image : : FORMAT_RGBA8 ) ;
2022-02-20 00:08:53 +00:00
image - > fill ( Color ( 0 , 0 , 0 , 1 ) ) ;
2022-05-10 17:02:44 +00:00
image - > generate_mipmaps ( ) ;
2022-02-20 00:08:53 +00:00
default_gl_textures [ DEFAULT_GL_TEXTURE_BLACK ] = texture_allocate ( ) ;
texture_2d_initialize ( default_gl_textures [ DEFAULT_GL_TEXTURE_BLACK ] , image ) ;
Vector < Ref < Image > > images ;
for ( int i = 0 ; i < 4 ; i + + ) {
images . push_back ( image ) ;
}
default_gl_textures [ DEFAULT_GL_TEXTURE_3D_BLACK ] = texture_allocate ( ) ;
texture_3d_initialize ( default_gl_textures [ DEFAULT_GL_TEXTURE_3D_BLACK ] , image - > get_format ( ) , 4 , 4 , 4 , false , images ) ;
for ( int i = 0 ; i < 2 ; i + + ) {
images . push_back ( image ) ;
}
default_gl_textures [ DEFAULT_GL_TEXTURE_CUBEMAP_BLACK ] = texture_allocate ( ) ;
texture_2d_layered_initialize ( default_gl_textures [ DEFAULT_GL_TEXTURE_CUBEMAP_BLACK ] , images , RS : : TEXTURE_LAYERED_CUBEMAP ) ;
}
2022-04-07 14:00:51 +00:00
2021-08-14 16:29:52 +00:00
{ // transparent black
2022-07-22 18:06:19 +00:00
Ref < Image > image = Image : : create_empty ( 4 , 4 , true , Image : : FORMAT_RGBA8 ) ;
2021-08-14 16:29:52 +00:00
image - > fill ( Color ( 0 , 0 , 0 , 0 ) ) ;
image - > generate_mipmaps ( ) ;
default_gl_textures [ DEFAULT_GL_TEXTURE_TRANSPARENT ] = texture_allocate ( ) ;
texture_2d_initialize ( default_gl_textures [ DEFAULT_GL_TEXTURE_TRANSPARENT ] , image ) ;
}
2022-02-20 00:08:53 +00:00
{
2022-07-22 18:06:19 +00:00
Ref < Image > image = Image : : create_empty ( 4 , 4 , true , Image : : FORMAT_RGBA8 ) ;
2022-02-20 00:08:53 +00:00
image - > fill ( Color ( 0.5 , 0.5 , 1 , 1 ) ) ;
2022-05-10 17:02:44 +00:00
image - > generate_mipmaps ( ) ;
2022-02-20 00:08:53 +00:00
default_gl_textures [ DEFAULT_GL_TEXTURE_NORMAL ] = texture_allocate ( ) ;
texture_2d_initialize ( default_gl_textures [ DEFAULT_GL_TEXTURE_NORMAL ] , image ) ;
}
{
2022-07-22 18:06:19 +00:00
Ref < Image > image = Image : : create_empty ( 4 , 4 , true , Image : : FORMAT_RGBA8 ) ;
2022-02-20 00:08:53 +00:00
image - > fill ( Color ( 1.0 , 0.5 , 1 , 1 ) ) ;
2022-05-10 17:02:44 +00:00
image - > generate_mipmaps ( ) ;
2022-02-20 00:08:53 +00:00
default_gl_textures [ DEFAULT_GL_TEXTURE_ANISO ] = texture_allocate ( ) ;
texture_2d_initialize ( default_gl_textures [ DEFAULT_GL_TEXTURE_ANISO ] , image ) ;
}
{
unsigned char pixel_data [ 4 * 4 * 4 ] ;
for ( int i = 0 ; i < 16 ; i + + ) {
pixel_data [ i * 4 + 0 ] = 0 ;
pixel_data [ i * 4 + 1 ] = 0 ;
pixel_data [ i * 4 + 2 ] = 0 ;
pixel_data [ i * 4 + 3 ] = 0 ;
}
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
default_gl_textures [ DEFAULT_GL_TEXTURE_2D_UINT ] = texture_allocate ( ) ;
Texture texture ;
texture . width = 4 ;
texture . height = 4 ;
texture . format = Image : : FORMAT_RGBA8 ;
texture . type = Texture : : TYPE_2D ;
texture . target = GL_TEXTURE_2D ;
texture . active = true ;
glGenTextures ( 1 , & texture . tex_id ) ;
texture_owner . initialize_rid ( default_gl_textures [ DEFAULT_GL_TEXTURE_2D_UINT ] , texture ) ;
glBindTexture ( GL_TEXTURE_2D , texture . tex_id ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8UI , 4 , 4 , 0 , GL_RGBA_INTEGER , GL_UNSIGNED_BYTE , pixel_data ) ;
texture . gl_set_filter ( RS : : CANVAS_ITEM_TEXTURE_FILTER_NEAREST ) ;
}
{
uint16_t pixel_data [ 4 * 4 ] ;
for ( int i = 0 ; i < 16 ; i + + ) {
pixel_data [ i ] = Math : : make_half_float ( 1.0f ) ;
2022-04-07 14:00:51 +00:00
}
2022-02-20 00:08:53 +00:00
default_gl_textures [ DEFAULT_GL_TEXTURE_DEPTH ] = texture_allocate ( ) ;
Texture texture ;
texture . width = 4 ;
texture . height = 4 ;
texture . format = Image : : FORMAT_RGBA8 ;
texture . type = Texture : : TYPE_2D ;
texture . target = GL_TEXTURE_2D ;
texture . active = true ;
glGenTextures ( 1 , & texture . tex_id ) ;
texture_owner . initialize_rid ( default_gl_textures [ DEFAULT_GL_TEXTURE_DEPTH ] , texture ) ;
glBindTexture ( GL_TEXTURE_2D , texture . tex_id ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_DEPTH_COMPONENT16 , 4 , 4 , 0 , GL_DEPTH_COMPONENT , GL_UNSIGNED_SHORT , pixel_data ) ;
texture . gl_set_filter ( RS : : CANVAS_ITEM_TEXTURE_FILTER_NEAREST ) ;
2022-04-07 14:00:51 +00:00
}
}
2022-06-21 00:08:33 +00:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2022-10-13 00:55:01 +00:00
{ // Atlas Texture initialize.
uint8_t pixel_data [ 4 * 4 * 4 ] ;
for ( int i = 0 ; i < 16 ; i + + ) {
pixel_data [ i * 4 + 0 ] = 0 ;
pixel_data [ i * 4 + 1 ] = 0 ;
pixel_data [ i * 4 + 2 ] = 0 ;
pixel_data [ i * 4 + 3 ] = 255 ;
}
glGenTextures ( 1 , & texture_atlas . texture ) ;
glBindTexture ( GL_TEXTURE_2D , texture_atlas . texture ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , 4 , 4 , 0 , GL_RGBA , GL_UNSIGNED_BYTE , pixel_data ) ;
}
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2022-06-21 00:08:33 +00:00
# ifdef GLES_OVER_GL
glEnable ( GL_PROGRAM_POINT_SIZE ) ;
# endif
2022-03-12 11:19:59 +00:00
}
TextureStorage : : ~ TextureStorage ( ) {
singleton = nullptr ;
2022-02-20 00:08:53 +00:00
for ( int i = 0 ; i < DEFAULT_GL_TEXTURE_MAX ; i + + ) {
texture_free ( default_gl_textures [ i ] ) ;
}
2022-10-13 00:55:01 +00:00
glDeleteTextures ( 1 , & texture_atlas . texture ) ;
texture_atlas . texture = 0 ;
glDeleteFramebuffers ( 1 , & texture_atlas . framebuffer ) ;
texture_atlas . framebuffer = 0 ;
2022-03-12 11:19:59 +00:00
}
2022-05-10 17:02:44 +00:00
//TODO, move back to storage
2022-03-12 11:19:59 +00:00
bool TextureStorage : : can_create_resources_async ( ) const {
return false ;
}
2022-04-07 14:00:51 +00:00
/* Canvas Texture API */
RID TextureStorage : : canvas_texture_allocate ( ) {
return canvas_texture_owner . allocate_rid ( ) ;
}
void TextureStorage : : canvas_texture_initialize ( RID p_rid ) {
canvas_texture_owner . initialize_rid ( p_rid ) ;
}
void TextureStorage : : canvas_texture_free ( RID p_rid ) {
canvas_texture_owner . free ( p_rid ) ;
}
void TextureStorage : : canvas_texture_set_channel ( RID p_canvas_texture , RS : : CanvasTextureChannel p_channel , RID p_texture ) {
CanvasTexture * ct = canvas_texture_owner . get_or_null ( p_canvas_texture ) ;
switch ( p_channel ) {
case RS : : CANVAS_TEXTURE_CHANNEL_DIFFUSE : {
ct - > diffuse = p_texture ;
} break ;
case RS : : CANVAS_TEXTURE_CHANNEL_NORMAL : {
ct - > normal_map = p_texture ;
} break ;
case RS : : CANVAS_TEXTURE_CHANNEL_SPECULAR : {
ct - > specular = p_texture ;
} break ;
}
}
void TextureStorage : : canvas_texture_set_shading_parameters ( RID p_canvas_texture , const Color & p_specular_color , float p_shininess ) {
CanvasTexture * ct = canvas_texture_owner . get_or_null ( p_canvas_texture ) ;
ct - > specular_color . r = p_specular_color . r ;
ct - > specular_color . g = p_specular_color . g ;
ct - > specular_color . b = p_specular_color . b ;
ct - > specular_color . a = p_shininess ;
}
void TextureStorage : : canvas_texture_set_texture_filter ( RID p_canvas_texture , RS : : CanvasItemTextureFilter p_filter ) {
CanvasTexture * ct = canvas_texture_owner . get_or_null ( p_canvas_texture ) ;
ct - > texture_filter = p_filter ;
}
void TextureStorage : : canvas_texture_set_texture_repeat ( RID p_canvas_texture , RS : : CanvasItemTextureRepeat p_repeat ) {
CanvasTexture * ct = canvas_texture_owner . get_or_null ( p_canvas_texture ) ;
ct - > texture_repeat = p_repeat ;
}
2022-06-21 00:08:33 +00:00
/* CANVAS SHADOW */
RID TextureStorage : : canvas_light_shadow_buffer_create ( int p_width ) {
Config * config = Config : : get_singleton ( ) ;
CanvasLightShadow * cls = memnew ( CanvasLightShadow ) ;
if ( p_width > config - > max_texture_size ) {
p_width = config - > max_texture_size ;
}
cls - > size = p_width ;
cls - > height = 16 ;
glActiveTexture ( GL_TEXTURE0 ) ;
glGenFramebuffers ( 1 , & cls - > fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , cls - > fbo ) ;
glGenRenderbuffers ( 1 , & cls - > depth ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , cls - > depth ) ;
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT16 , cls - > size , cls - > height ) ;
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , cls - > depth ) ;
glGenTextures ( 1 , & cls - > distance ) ;
glBindTexture ( GL_TEXTURE_2D , cls - > distance ) ;
if ( config - > use_rgba_2d_shadows ) {
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , cls - > size , cls - > height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , nullptr ) ;
} else {
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_R32F , cls - > size , cls - > height , 0 , GL_RED , GL_FLOAT , nullptr ) ;
}
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , cls - > distance , 0 ) ;
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
//printf("errnum: %x\n",status);
glBindFramebuffer ( GL_FRAMEBUFFER , GLES3 : : TextureStorage : : system_fbo ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
memdelete ( cls ) ;
ERR_FAIL_COND_V ( status ! = GL_FRAMEBUFFER_COMPLETE , RID ( ) ) ;
}
return canvas_light_shadow_owner . make_rid ( cls ) ;
}
2022-04-07 14:00:51 +00:00
/* Texture API */
2022-05-18 15:04:41 +00:00
Ref < Image > TextureStorage : : _get_gl_image_and_format ( const Ref < Image > & p_image , Image : : Format p_format , Image : : Format & r_real_format , GLenum & r_gl_format , GLenum & r_gl_internal_format , GLenum & r_gl_type , bool & r_compressed , bool p_force_decompress ) const {
2022-03-12 11:19:59 +00:00
Config * config = Config : : get_singleton ( ) ;
r_gl_format = 0 ;
Ref < Image > image = p_image ;
r_compressed = false ;
r_real_format = p_format ;
bool need_decompress = false ;
switch ( p_format ) {
case Image : : FORMAT_L8 : {
# ifdef GLES_OVER_GL
r_gl_internal_format = GL_R8 ;
r_gl_format = GL_RED ;
r_gl_type = GL_UNSIGNED_BYTE ;
# else
r_gl_internal_format = GL_LUMINANCE ;
r_gl_format = GL_LUMINANCE ;
r_gl_type = GL_UNSIGNED_BYTE ;
# endif
} break ;
case Image : : FORMAT_LA8 : {
# ifdef GLES_OVER_GL
r_gl_internal_format = GL_RG8 ;
r_gl_format = GL_RG ;
r_gl_type = GL_UNSIGNED_BYTE ;
# else
r_gl_internal_format = GL_LUMINANCE_ALPHA ;
r_gl_format = GL_LUMINANCE_ALPHA ;
r_gl_type = GL_UNSIGNED_BYTE ;
# endif
} break ;
case Image : : FORMAT_R8 : {
r_gl_internal_format = GL_R8 ;
r_gl_format = GL_RED ;
r_gl_type = GL_UNSIGNED_BYTE ;
} break ;
case Image : : FORMAT_RG8 : {
r_gl_internal_format = GL_RG8 ;
r_gl_format = GL_RG ;
r_gl_type = GL_UNSIGNED_BYTE ;
} break ;
case Image : : FORMAT_RGB8 : {
r_gl_internal_format = GL_RGB8 ;
r_gl_format = GL_RGB ;
r_gl_type = GL_UNSIGNED_BYTE ;
} break ;
case Image : : FORMAT_RGBA8 : {
r_gl_format = GL_RGBA ;
r_gl_internal_format = GL_RGBA8 ;
r_gl_type = GL_UNSIGNED_BYTE ;
} break ;
case Image : : FORMAT_RGBA4444 : {
r_gl_internal_format = GL_RGBA4 ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4 ;
} break ;
case Image : : FORMAT_RF : {
r_gl_internal_format = GL_R32F ;
r_gl_format = GL_RED ;
r_gl_type = GL_FLOAT ;
} break ;
case Image : : FORMAT_RGF : {
r_gl_internal_format = GL_RG32F ;
r_gl_format = GL_RG ;
r_gl_type = GL_FLOAT ;
} break ;
case Image : : FORMAT_RGBF : {
r_gl_internal_format = GL_RGB32F ;
r_gl_format = GL_RGB ;
r_gl_type = GL_FLOAT ;
} break ;
case Image : : FORMAT_RGBAF : {
r_gl_internal_format = GL_RGBA32F ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_FLOAT ;
} break ;
case Image : : FORMAT_RH : {
r_gl_internal_format = GL_R16F ;
r_gl_format = GL_RED ;
r_gl_type = GL_HALF_FLOAT ;
} break ;
case Image : : FORMAT_RGH : {
r_gl_internal_format = GL_RG16F ;
r_gl_format = GL_RG ;
r_gl_type = GL_HALF_FLOAT ;
} break ;
case Image : : FORMAT_RGBH : {
r_gl_internal_format = GL_RGB16F ;
r_gl_format = GL_RGB ;
r_gl_type = GL_HALF_FLOAT ;
} break ;
case Image : : FORMAT_RGBAH : {
r_gl_internal_format = GL_RGBA16F ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_HALF_FLOAT ;
} break ;
case Image : : FORMAT_RGBE9995 : {
r_gl_internal_format = GL_RGB9_E5 ;
r_gl_format = GL_RGB ;
r_gl_type = GL_UNSIGNED_INT_5_9_9_9_REV ;
} break ;
case Image : : FORMAT_DXT1 : {
if ( config - > s3tc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_DXT3 : {
if ( config - > s3tc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_DXT5 : {
if ( config - > s3tc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_RGTC_R : {
if ( config - > rgtc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RED_RGTC1_EXT ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_RGTC_RG : {
if ( config - > rgtc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_BPTC_RGBA : {
if ( config - > bptc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA_BPTC_UNORM ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_BPTC_RGBF : {
if ( config - > bptc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT ;
r_gl_format = GL_RGB ;
r_gl_type = GL_FLOAT ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_BPTC_RGBFU : {
if ( config - > bptc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT ;
r_gl_format = GL_RGB ;
r_gl_type = GL_FLOAT ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_R11 : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_R11_EAC ;
r_gl_format = GL_RED ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_R11S : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_SIGNED_R11_EAC ;
r_gl_format = GL_RED ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_RG11 : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RG11_EAC ;
r_gl_format = GL_RG ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_RG11S : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_SIGNED_RG11_EAC ;
r_gl_format = GL_RG ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
2022-05-18 15:04:41 +00:00
case Image : : FORMAT_ETC :
2022-03-12 11:19:59 +00:00
case Image : : FORMAT_ETC2_RGB8 : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGB8_ETC2 ;
r_gl_format = GL_RGB ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_RGBA8 : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA8_ETC2_EAC ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_RGB8A1 : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
default : {
2022-05-16 18:56:03 +00:00
ERR_FAIL_V_MSG ( Ref < Image > ( ) , " Image Format: " + itos ( p_format ) + " is not supported by the OpenGL3 Renderer " ) ;
2022-03-12 11:19:59 +00:00
}
}
if ( need_decompress | | p_force_decompress ) {
if ( ! image . is_null ( ) ) {
image = image - > duplicate ( ) ;
image - > decompress ( ) ;
ERR_FAIL_COND_V ( image - > is_compressed ( ) , image ) ;
switch ( image - > get_format ( ) ) {
case Image : : FORMAT_RGB8 : {
r_gl_format = GL_RGB ;
r_gl_internal_format = GL_RGB ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_real_format = Image : : FORMAT_RGB8 ;
r_compressed = false ;
} break ;
case Image : : FORMAT_RGBA8 : {
r_gl_format = GL_RGBA ;
r_gl_internal_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_real_format = Image : : FORMAT_RGBA8 ;
r_compressed = false ;
} break ;
default : {
image - > convert ( Image : : FORMAT_RGBA8 ) ;
r_gl_format = GL_RGBA ;
r_gl_internal_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_real_format = Image : : FORMAT_RGBA8 ;
r_compressed = false ;
} break ;
}
}
return image ;
}
return p_image ;
}
2022-02-20 00:08:53 +00:00
RID TextureStorage : : texture_allocate ( ) {
return texture_owner . allocate_rid ( ) ;
2022-03-12 11:19:59 +00:00
}
2022-02-20 00:08:53 +00:00
void TextureStorage : : texture_free ( RID p_texture ) {
Texture * t = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! t ) ;
ERR_FAIL_COND ( t - > is_render_target ) ;
2022-03-12 11:19:59 +00:00
2022-02-20 00:08:53 +00:00
if ( t - > canvas_texture ) {
memdelete ( t - > canvas_texture ) ;
2022-03-12 11:19:59 +00:00
}
2022-02-20 00:08:53 +00:00
if ( t - > tex_id ! = 0 ) {
glDeleteTextures ( 1 , & t - > tex_id ) ;
t - > tex_id = 0 ;
2022-03-12 11:19:59 +00:00
}
2022-02-20 00:08:53 +00:00
if ( t - > is_proxy & & t - > proxy_to . is_valid ( ) ) {
Texture * proxy_to = texture_owner . get_or_null ( t - > proxy_to ) ;
if ( proxy_to ) {
proxy_to - > proxies . erase ( p_texture ) ;
2022-03-12 11:19:59 +00:00
}
}
2022-10-13 00:55:01 +00:00
texture_atlas_remove_texture ( p_texture ) ;
2022-03-12 11:19:59 +00:00
2022-02-20 00:08:53 +00:00
for ( int i = 0 ; i < t - > proxies . size ( ) ; i + + ) {
Texture * p = texture_owner . get_or_null ( t - > proxies [ i ] ) ;
ERR_CONTINUE ( ! p ) ;
p - > proxy_to = RID ( ) ;
p - > tex_id = 0 ;
2022-03-12 11:19:59 +00:00
}
2022-02-20 00:08:53 +00:00
texture_owner . free ( p_texture ) ;
2022-03-12 11:19:59 +00:00
}
void TextureStorage : : texture_2d_initialize ( RID p_texture , const Ref < Image > & p_image ) {
2022-09-30 01:55:32 +00:00
ERR_FAIL_COND ( p_image . is_null ( ) ) ;
2022-02-20 00:08:53 +00:00
Texture texture ;
texture . width = p_image - > get_width ( ) ;
texture . height = p_image - > get_height ( ) ;
2022-05-10 17:02:44 +00:00
texture . alloc_width = texture . width ;
texture . alloc_height = texture . height ;
texture . mipmaps = p_image - > get_mipmap_count ( ) ;
2022-02-20 00:08:53 +00:00
texture . format = p_image - > get_format ( ) ;
texture . type = Texture : : TYPE_2D ;
texture . target = GL_TEXTURE_2D ;
2022-05-18 15:04:41 +00:00
_get_gl_image_and_format ( Ref < Image > ( ) , texture . format , texture . real_format , texture . gl_format_cache , texture . gl_internal_format_cache , texture . gl_type_cache , texture . compressed , false ) ;
2022-05-10 17:02:44 +00:00
//texture.total_data_size = p_image->get_image_data_size(); // verify that this returns size in bytes
2022-02-20 00:08:53 +00:00
texture . active = true ;
glGenTextures ( 1 , & texture . tex_id ) ;
texture_owner . initialize_rid ( p_texture , texture ) ;
2022-03-12 11:19:59 +00:00
texture_set_data ( p_texture , p_image ) ;
}
void TextureStorage : : texture_2d_layered_initialize ( RID p_texture , const Vector < Ref < Image > > & p_layers , RS : : TextureLayeredType p_layered_type ) {
2022-02-20 00:08:53 +00:00
texture_owner . initialize_rid ( p_texture , Texture ( ) ) ;
2022-03-12 11:19:59 +00:00
}
void TextureStorage : : texture_3d_initialize ( RID p_texture , Image : : Format , int p_width , int p_height , int p_depth , bool p_mipmaps , const Vector < Ref < Image > > & p_data ) {
2022-02-20 00:08:53 +00:00
texture_owner . initialize_rid ( p_texture , Texture ( ) ) ;
2022-03-12 11:19:59 +00:00
}
2022-02-20 00:08:53 +00:00
// Called internally when texture_proxy_create(p_base) is called.
// Note: p_base is the root and p_texture is the proxy.
2022-03-12 11:19:59 +00:00
void TextureStorage : : texture_proxy_initialize ( RID p_texture , RID p_base ) {
2022-02-20 00:08:53 +00:00
Texture * texture = texture_owner . get_or_null ( p_base ) ;
ERR_FAIL_COND ( ! texture ) ;
Texture proxy_tex ;
proxy_tex . copy_from ( * texture ) ;
proxy_tex . proxy_to = p_base ;
proxy_tex . is_render_target = false ;
proxy_tex . is_proxy = true ;
proxy_tex . proxies . clear ( ) ;
texture - > proxies . push_back ( p_texture ) ;
texture_owner . initialize_rid ( p_texture , proxy_tex ) ;
2022-03-12 11:19:59 +00:00
}
void TextureStorage : : texture_2d_update ( RID p_texture , const Ref < Image > & p_image , int p_layer ) {
2022-09-04 14:56:24 +00:00
texture_set_data ( p_texture , p_image , p_layer ) ;
2022-02-20 00:08:53 +00:00
# ifdef TOOLS_ENABLED
Texture * tex = texture_owner . get_or_null ( p_texture ) ;
tex - > image_cache_2d . unref ( ) ;
# endif
}
void TextureStorage : : texture_proxy_update ( RID p_texture , RID p_proxy_to ) {
2022-03-12 11:19:59 +00:00
}
void TextureStorage : : texture_2d_placeholder_initialize ( RID p_texture ) {
2022-02-20 00:08:53 +00:00
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
2022-07-22 18:06:19 +00:00
Ref < Image > image = Image : : create_empty ( 4 , 4 , false , Image : : FORMAT_RGBA8 ) ;
2022-02-20 00:08:53 +00:00
image - > fill ( Color ( 1 , 0 , 1 , 1 ) ) ;
texture_2d_initialize ( p_texture , image ) ;
2022-03-12 11:19:59 +00:00
}
void TextureStorage : : texture_2d_layered_placeholder_initialize ( RID p_texture , RenderingServer : : TextureLayeredType p_layered_type ) {
2022-02-20 00:08:53 +00:00
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
2022-07-22 18:06:19 +00:00
Ref < Image > image = Image : : create_empty ( 4 , 4 , false , Image : : FORMAT_RGBA8 ) ;
2022-02-20 00:08:53 +00:00
image - > fill ( Color ( 1 , 0 , 1 , 1 ) ) ;
Vector < Ref < Image > > images ;
if ( p_layered_type = = RS : : TEXTURE_LAYERED_2D_ARRAY ) {
images . push_back ( image ) ;
} else {
//cube
for ( int i = 0 ; i < 6 ; i + + ) {
images . push_back ( image ) ;
}
}
texture_2d_layered_initialize ( p_texture , images , p_layered_type ) ;
2022-03-12 11:19:59 +00:00
}
void TextureStorage : : texture_3d_placeholder_initialize ( RID p_texture ) {
2022-02-20 00:08:53 +00:00
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
2022-07-22 18:06:19 +00:00
Ref < Image > image = Image : : create_empty ( 4 , 4 , false , Image : : FORMAT_RGBA8 ) ;
2022-02-20 00:08:53 +00:00
image - > fill ( Color ( 1 , 0 , 1 , 1 ) ) ;
Vector < Ref < Image > > images ;
//cube
for ( int i = 0 ; i < 4 ; i + + ) {
images . push_back ( image ) ;
}
texture_3d_initialize ( p_texture , Image : : FORMAT_RGBA8 , 4 , 4 , 4 , false , images ) ;
2022-03-12 11:19:59 +00:00
}
Ref < Image > TextureStorage : : texture_2d_get ( RID p_texture ) const {
2022-05-10 17:02:44 +00:00
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , Ref < Image > ( ) ) ;
2022-03-12 11:19:59 +00:00
2022-02-20 00:08:53 +00:00
# ifdef TOOLS_ENABLED
2022-05-10 17:02:44 +00:00
if ( texture - > image_cache_2d . is_valid ( ) & & ! texture - > is_render_target ) {
return texture - > image_cache_2d ;
2022-02-20 00:08:53 +00:00
}
# endif
2022-05-10 17:02:44 +00:00
# ifdef GLES_OVER_GL
// OpenGL 3.3 supports glGetTexImage which is faster and simpler than glReadPixels.
Vector < uint8_t > data ;
int data_size = Image : : get_image_data_size ( texture - > alloc_width , texture - > alloc_height , texture - > real_format , texture - > mipmaps > 1 ) ;
data . resize ( data_size * 2 ) ; //add some memory at the end, just in case for buggy drivers
uint8_t * w = data . ptrw ( ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( texture - > target , texture - > tex_id ) ;
glBindBuffer ( GL_PIXEL_PACK_BUFFER , 0 ) ;
for ( int i = 0 ; i < texture - > mipmaps ; i + + ) {
int ofs = Image : : get_image_mipmap_offset ( texture - > alloc_width , texture - > alloc_height , texture - > real_format , i ) ;
if ( texture - > compressed ) {
glPixelStorei ( GL_PACK_ALIGNMENT , 4 ) ;
glGetCompressedTexImage ( texture - > target , i , & w [ ofs ] ) ;
} else {
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
glGetTexImage ( texture - > target , i , texture - > gl_format_cache , texture - > gl_type_cache , & w [ ofs ] ) ;
}
2022-03-12 11:19:59 +00:00
}
2022-05-10 17:02:44 +00:00
data . resize ( data_size ) ;
2022-03-12 11:19:59 +00:00
ERR_FAIL_COND_V ( data . size ( ) = = 0 , Ref < Image > ( ) ) ;
2022-07-22 18:06:19 +00:00
Ref < Image > image = Image : : create_from_data ( texture - > width , texture - > height , texture - > mipmaps > 1 , texture - > real_format , data ) ;
2022-05-10 17:02:44 +00:00
ERR_FAIL_COND_V ( image - > is_empty ( ) , Ref < Image > ( ) ) ;
if ( texture - > format ! = texture - > real_format ) {
image - > convert ( texture - > format ) ;
2022-03-12 11:19:59 +00:00
}
2022-05-10 17:02:44 +00:00
# else
// Support for Web and Mobile will come later.
Ref < Image > image ;
# endif
2022-03-12 11:19:59 +00:00
# ifdef TOOLS_ENABLED
2022-05-10 17:02:44 +00:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) & & ! texture - > is_render_target ) {
texture - > image_cache_2d = image ;
2022-03-12 11:19:59 +00:00
}
# endif
2022-05-10 17:02:44 +00:00
return image ;
2022-03-12 11:19:59 +00:00
}
void TextureStorage : : texture_replace ( RID p_texture , RID p_by_texture ) {
Texture * tex_to = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! tex_to ) ;
2022-02-20 00:08:53 +00:00
ERR_FAIL_COND ( tex_to - > is_proxy ) ; //can't replace proxy
2022-03-12 11:19:59 +00:00
Texture * tex_from = texture_owner . get_or_null ( p_by_texture ) ;
ERR_FAIL_COND ( ! tex_from ) ;
2022-02-20 00:08:53 +00:00
ERR_FAIL_COND ( tex_from - > is_proxy ) ; //can't replace proxy
if ( tex_to = = tex_from ) {
return ;
}
if ( tex_to - > canvas_texture ) {
memdelete ( tex_to - > canvas_texture ) ;
tex_to - > canvas_texture = nullptr ;
}
if ( tex_to - > tex_id ) {
glDeleteTextures ( 1 , & tex_to - > tex_id ) ;
tex_to - > tex_id = 0 ;
}
Vector < RID > proxies_to_update = tex_to - > proxies ;
Vector < RID > proxies_to_redirect = tex_from - > proxies ;
2022-03-12 11:19:59 +00:00
tex_to - > copy_from ( * tex_from ) ;
2022-02-20 00:08:53 +00:00
tex_to - > proxies = proxies_to_update ; //restore proxies, so they can be updated
2022-03-12 11:19:59 +00:00
2022-02-20 00:08:53 +00:00
if ( tex_to - > canvas_texture ) {
tex_to - > canvas_texture - > diffuse = p_texture ; //update
2022-03-12 11:19:59 +00:00
}
2022-02-20 00:08:53 +00:00
for ( int i = 0 ; i < proxies_to_update . size ( ) ; i + + ) {
texture_proxy_update ( proxies_to_update [ i ] , p_texture ) ;
}
for ( int i = 0 ; i < proxies_to_redirect . size ( ) ; i + + ) {
texture_proxy_update ( proxies_to_redirect [ i ] , p_texture ) ;
}
//delete last, so proxies can be updated
texture_owner . free ( p_by_texture ) ;
2022-10-13 00:55:01 +00:00
texture_atlas_mark_dirty_on_texture ( p_texture ) ;
2022-03-12 11:19:59 +00:00
}
void TextureStorage : : texture_set_size_override ( RID p_texture , int p_width , int p_height ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
2022-02-20 00:08:53 +00:00
ERR_FAIL_COND ( texture - > is_render_target ) ;
2022-03-12 11:19:59 +00:00
ERR_FAIL_COND ( p_width < = 0 | | p_width > 16384 ) ;
ERR_FAIL_COND ( p_height < = 0 | | p_height > 16384 ) ;
//real texture size is in alloc width and height
texture - > width = p_width ;
texture - > height = p_height ;
}
void TextureStorage : : texture_set_path ( RID p_texture , const String & p_path ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
texture - > path = p_path ;
}
String TextureStorage : : texture_get_path ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , " " ) ;
return texture - > path ;
}
void TextureStorage : : texture_set_detect_3d_callback ( RID p_texture , RS : : TextureDetectCallback p_callback , void * p_userdata ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
2022-02-20 00:08:53 +00:00
texture - > detect_3d_callback = p_callback ;
texture - > detect_3d_callback_ud = p_userdata ;
2022-03-12 11:19:59 +00:00
}
void TextureStorage : : texture_set_detect_srgb_callback ( RID p_texture , RS : : TextureDetectCallback p_callback , void * p_userdata ) {
}
void TextureStorage : : texture_set_detect_normal_callback ( RID p_texture , RS : : TextureDetectCallback p_callback , void * p_userdata ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
2022-02-20 00:08:53 +00:00
texture - > detect_normal_callback = p_callback ;
texture - > detect_normal_callback_ud = p_userdata ;
}
void TextureStorage : : texture_set_detect_roughness_callback ( RID p_texture , RS : : TextureDetectRoughnessCallback p_callback , void * p_userdata ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
texture - > detect_roughness_callback = p_callback ;
texture - > detect_roughness_callback_ud = p_userdata ;
2022-03-12 11:19:59 +00:00
}
void TextureStorage : : texture_debug_usage ( List < RS : : TextureInfo > * r_info ) {
List < RID > textures ;
texture_owner . get_owned_list ( & textures ) ;
for ( List < RID > : : Element * E = textures . front ( ) ; E ; E = E - > next ( ) ) {
Texture * t = texture_owner . get_or_null ( E - > get ( ) ) ;
if ( ! t ) {
continue ;
}
RS : : TextureInfo tinfo ;
tinfo . path = t - > path ;
tinfo . format = t - > format ;
tinfo . width = t - > alloc_width ;
tinfo . height = t - > alloc_height ;
tinfo . depth = 0 ;
tinfo . bytes = t - > total_data_size ;
r_info - > push_back ( tinfo ) ;
}
}
void TextureStorage : : texture_set_force_redraw_if_visible ( RID p_texture , bool p_enable ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
texture - > redraw_if_visible = p_enable ;
}
Size2 TextureStorage : : texture_size_with_proxy ( RID p_texture ) {
const Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , Size2 ( ) ) ;
2022-02-20 00:08:53 +00:00
if ( texture - > is_proxy ) {
const Texture * proxy = texture_owner . get_or_null ( texture - > proxy_to ) ;
return Size2 ( proxy - > width , proxy - > height ) ;
2022-03-12 11:19:59 +00:00
} else {
return Size2 ( texture - > width , texture - > height ) ;
}
}
void TextureStorage : : texture_set_data ( RID p_texture , const Ref < Image > & p_image , int p_layer ) {
Texture * texture = texture_owner . get_or_null ( 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
return ;
}
ERR_FAIL_COND ( ! texture - > active ) ;
2022-02-20 00:08:53 +00:00
ERR_FAIL_COND ( texture - > is_render_target ) ;
2022-03-12 11:19:59 +00:00
ERR_FAIL_COND ( p_image . is_null ( ) ) ;
ERR_FAIL_COND ( texture - > format ! = p_image - > get_format ( ) ) ;
ERR_FAIL_COND ( ! p_image - > get_width ( ) ) ;
ERR_FAIL_COND ( ! p_image - > get_height ( ) ) ;
// ERR_FAIL_COND(texture->type == RS::TEXTURE_TYPE_EXTERNAL);
GLenum type ;
GLenum format ;
GLenum internal_format ;
bool compressed = false ;
// print_line("texture_set_data width " + itos (p_image->get_width()) + " height " + itos(p_image->get_height()));
Image : : Format real_format ;
2022-05-18 15:04:41 +00:00
Ref < Image > img = _get_gl_image_and_format ( p_image , p_image - > get_format ( ) , real_format , format , internal_format , type , compressed , texture - > resize_to_po2 ) ;
2022-05-16 18:56:03 +00:00
ERR_FAIL_COND ( img . is_null ( ) ) ;
2022-03-12 11:19:59 +00:00
if ( texture - > resize_to_po2 ) {
if ( p_image - > is_compressed ( ) ) {
ERR_PRINT ( " Texture ' " + texture - > path + " ' is required to be a power of 2 because it uses either mipmaps or repeat, so it was decompressed. This will hurt performance and memory usage. " ) ;
}
if ( img = = p_image ) {
img = img - > duplicate ( ) ;
}
img - > resize_to_po2 ( false ) ;
}
2022-09-04 14:56:24 +00:00
GLenum blit_target = ( texture - > target = = GL_TEXTURE_CUBE_MAP ) ? _cube_side_enum [ p_layer ] : texture - > target ;
2022-03-12 11:19:59 +00:00
Vector < uint8_t > read = img - > get_data ( ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( texture - > target , texture - > tex_id ) ;
2022-02-20 00:08:53 +00:00
// set filtering and repeat state to default
texture - > gl_set_filter ( RS : : CANVAS_ITEM_TEXTURE_FILTER_NEAREST ) ;
texture - > gl_set_repeat ( RS : : CANVAS_ITEM_TEXTURE_REPEAT_ENABLED ) ;
2022-03-12 11:19:59 +00:00
//set swizle for older format compatibility
# ifdef GLES_OVER_GL
switch ( texture - > format ) {
case Image : : FORMAT_L8 : {
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_R , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_G , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_B , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_A , GL_ONE ) ;
} break ;
case Image : : FORMAT_LA8 : {
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_R , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_G , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_B , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_A , GL_GREEN ) ;
} break ;
default : {
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_R , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_G , GL_GREEN ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_B , GL_BLUE ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_A , GL_ALPHA ) ;
} break ;
}
# endif
2022-02-20 00:08:53 +00:00
int mipmaps = img - > has_mipmaps ( ) ? img - > get_mipmap_count ( ) + 1 : 1 ;
2022-03-12 11:19:59 +00:00
int w = img - > get_width ( ) ;
int h = img - > get_height ( ) ;
int tsize = 0 ;
for ( int i = 0 ; i < mipmaps ; i + + ) {
int size , ofs ;
img - > get_mipmap_offset_and_size ( i , ofs , size ) ;
if ( compressed ) {
glPixelStorei ( GL_UNPACK_ALIGNMENT , 4 ) ;
int bw = w ;
int bh = h ;
glCompressedTexImage2D ( blit_target , i , internal_format , bw , bh , 0 , size , & read [ ofs ] ) ;
} else {
glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
2022-09-04 14:56:24 +00:00
if ( texture - > target = = GL_TEXTURE_2D_ARRAY ) {
glTexSubImage3D ( GL_TEXTURE_2D_ARRAY , i , 0 , 0 , p_layer , w , h , 0 , format , type , & read [ ofs ] ) ;
} else {
glTexImage2D ( blit_target , i , internal_format , w , h , 0 , format , type , & read [ ofs ] ) ;
}
2022-03-12 11:19:59 +00:00
}
tsize + = size ;
w = MAX ( 1 , w > > 1 ) ;
h = MAX ( 1 , h > > 1 ) ;
}
// info.texture_mem -= texture->total_data_size; // TODO make this work again!!
texture - > total_data_size = tsize ;
// info.texture_mem += texture->total_data_size; // TODO make this work again!!
// printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem);
texture - > stored_cube_sides | = ( 1 < < p_layer ) ;
texture - > mipmaps = mipmaps ;
}
void TextureStorage : : texture_set_data_partial ( RID p_texture , const Ref < Image > & p_image , int src_x , int src_y , int src_w , int src_h , int dst_x , int dst_y , int p_dst_mip , int p_layer ) {
2022-02-20 00:08:53 +00:00
ERR_PRINT ( " Not implemented yet, sorry :( " ) ;
2022-03-12 11:19:59 +00:00
}
Image : : Format TextureStorage : : texture_get_format ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , Image : : FORMAT_L8 ) ;
return texture - > format ;
}
uint32_t TextureStorage : : texture_get_texid ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , 0 ) ;
return texture - > tex_id ;
}
uint32_t TextureStorage : : texture_get_width ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , 0 ) ;
return texture - > width ;
}
uint32_t TextureStorage : : texture_get_height ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , 0 ) ;
return texture - > height ;
}
uint32_t TextureStorage : : texture_get_depth ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , 0 ) ;
return texture - > depth ;
}
void TextureStorage : : texture_bind ( RID p_texture , uint32_t p_texture_no ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
glActiveTexture ( GL_TEXTURE0 + p_texture_no ) ;
glBindTexture ( texture - > target , texture - > tex_id ) ;
}
RID TextureStorage : : texture_create_radiance_cubemap ( RID p_source , int p_resolution ) const {
return RID ( ) ;
}
2022-10-13 00:55:01 +00:00
/* TEXTURE ATLAS API */
void TextureStorage : : texture_add_to_texture_atlas ( RID p_texture ) {
if ( ! texture_atlas . textures . has ( p_texture ) ) {
TextureAtlas : : Texture t ;
t . users = 1 ;
texture_atlas . textures [ p_texture ] = t ;
texture_atlas . dirty = true ;
} else {
TextureAtlas : : Texture * t = texture_atlas . textures . getptr ( p_texture ) ;
t - > users + + ;
}
}
void TextureStorage : : texture_remove_from_texture_atlas ( RID p_texture ) {
TextureAtlas : : Texture * t = texture_atlas . textures . getptr ( p_texture ) ;
ERR_FAIL_COND ( ! t ) ;
t - > users - - ;
if ( t - > users = = 0 ) {
texture_atlas . textures . erase ( p_texture ) ;
// Do not mark it dirty, there is no need to since it remains working.
}
}
void TextureStorage : : texture_atlas_mark_dirty_on_texture ( RID p_texture ) {
if ( texture_atlas . textures . has ( p_texture ) ) {
texture_atlas . dirty = true ; // Mark it dirty since it was most likely modified.
}
}
void TextureStorage : : texture_atlas_remove_texture ( RID p_texture ) {
if ( texture_atlas . textures . has ( p_texture ) ) {
texture_atlas . textures . erase ( p_texture ) ;
// There is not much a point of making it dirty, texture can be removed next time the atlas is updated.
}
}
GLuint TextureStorage : : texture_atlas_get_texture ( ) const {
return texture_atlas . texture ;
}
void TextureStorage : : update_texture_atlas ( ) {
CopyEffects * copy_effects = CopyEffects : : get_singleton ( ) ;
ERR_FAIL_NULL ( copy_effects ) ;
if ( ! texture_atlas . dirty ) {
return ; //nothing to do
}
texture_atlas . dirty = false ;
if ( texture_atlas . texture ! = 0 ) {
glDeleteTextures ( 1 , & texture_atlas . texture ) ;
texture_atlas . texture = 0 ;
glDeleteFramebuffers ( 1 , & texture_atlas . framebuffer ) ;
texture_atlas . framebuffer = 0 ;
}
const int border = 2 ;
if ( texture_atlas . textures . size ( ) ) {
//generate atlas
Vector < TextureAtlas : : SortItem > itemsv ;
itemsv . resize ( texture_atlas . textures . size ( ) ) ;
int base_size = 8 ;
int idx = 0 ;
for ( const KeyValue < RID , TextureAtlas : : Texture > & E : texture_atlas . textures ) {
TextureAtlas : : SortItem & si = itemsv . write [ idx ] ;
Texture * src_tex = get_texture ( E . key ) ;
si . size . width = ( src_tex - > width / border ) + 1 ;
si . size . height = ( src_tex - > height / border ) + 1 ;
si . pixel_size = Size2i ( src_tex - > width , src_tex - > height ) ;
if ( base_size < si . size . width ) {
base_size = nearest_power_of_2_templated ( si . size . width ) ;
}
si . texture = E . key ;
idx + + ;
}
//sort items by size
itemsv . sort ( ) ;
//attempt to create atlas
int item_count = itemsv . size ( ) ;
TextureAtlas : : SortItem * items = itemsv . ptrw ( ) ;
int atlas_height = 0 ;
while ( true ) {
Vector < int > v_offsetsv ;
v_offsetsv . resize ( base_size ) ;
int * v_offsets = v_offsetsv . ptrw ( ) ;
memset ( v_offsets , 0 , sizeof ( int ) * base_size ) ;
int max_height = 0 ;
for ( int i = 0 ; i < item_count ; i + + ) {
//best fit
TextureAtlas : : SortItem & si = items [ i ] ;
int best_idx = - 1 ;
int best_height = 0x7FFFFFFF ;
for ( int j = 0 ; j < = base_size - si . size . width ; j + + ) {
int height = 0 ;
for ( int k = 0 ; k < si . size . width ; k + + ) {
int h = v_offsets [ k + j ] ;
if ( h > height ) {
height = h ;
if ( height > best_height ) {
break ; //already bad
}
}
}
if ( height < best_height ) {
best_height = height ;
best_idx = j ;
}
}
//update
for ( int k = 0 ; k < si . size . width ; k + + ) {
v_offsets [ k + best_idx ] = best_height + si . size . height ;
}
si . pos . x = best_idx ;
si . pos . y = best_height ;
if ( si . pos . y + si . size . height > max_height ) {
max_height = si . pos . y + si . size . height ;
}
}
if ( max_height < = base_size * 2 ) {
atlas_height = max_height ;
break ; //good ratio, break;
}
base_size * = 2 ;
}
texture_atlas . size . width = base_size * border ;
texture_atlas . size . height = nearest_power_of_2_templated ( atlas_height * border ) ;
for ( int i = 0 ; i < item_count ; i + + ) {
TextureAtlas : : Texture * t = texture_atlas . textures . getptr ( items [ i ] . texture ) ;
t - > uv_rect . position = items [ i ] . pos * border + Vector2i ( border / 2 , border / 2 ) ;
t - > uv_rect . size = items [ i ] . pixel_size ;
t - > uv_rect . position / = Size2 ( texture_atlas . size ) ;
t - > uv_rect . size / = Size2 ( texture_atlas . size ) ;
}
} else {
texture_atlas . size . width = 4 ;
texture_atlas . size . height = 4 ;
}
{ // Atlas Texture initialize.
// TODO validate texture atlas size with maximum texture size
glGenTextures ( 1 , & texture_atlas . texture ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , texture_atlas . texture ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , texture_atlas . size . width , texture_atlas . size . height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , nullptr ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_BASE_LEVEL , 0 ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , 1 ) ;
glGenFramebuffers ( 1 , & texture_atlas . framebuffer ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , texture_atlas . framebuffer ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , texture_atlas . texture , 0 ) ;
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
glDeleteFramebuffers ( 1 , & texture_atlas . framebuffer ) ;
texture_atlas . framebuffer = 0 ;
glDeleteTextures ( 1 , & texture_atlas . texture ) ;
texture_atlas . texture = 0 ;
WARN_PRINT ( " Could not create texture atlas, status: " + get_framebuffer_error ( status ) ) ;
return ;
}
glViewport ( 0 , 0 , texture_atlas . size . width , texture_atlas . size . height ) ;
glClearColor ( 0.0 , 0.0 , 0.0 , 0.0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
}
glDisable ( GL_BLEND ) ;
if ( texture_atlas . textures . size ( ) ) {
for ( const KeyValue < RID , TextureAtlas : : Texture > & E : texture_atlas . textures ) {
TextureAtlas : : Texture * t = texture_atlas . textures . getptr ( E . key ) ;
Texture * src_tex = get_texture ( E . key ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , src_tex - > tex_id ) ;
copy_effects - > copy_to_rect ( t - > uv_rect ) ;
}
}
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
}
2022-04-07 14:00:51 +00:00
/* DECAL API */
RID TextureStorage : : decal_allocate ( ) {
return RID ( ) ;
}
void TextureStorage : : decal_initialize ( RID p_rid ) {
}
void TextureStorage : : decal_set_extents ( RID p_decal , const Vector3 & p_extents ) {
}
void TextureStorage : : decal_set_texture ( RID p_decal , RS : : DecalTexture p_type , RID p_texture ) {
}
void TextureStorage : : decal_set_emission_energy ( RID p_decal , float p_energy ) {
}
void TextureStorage : : decal_set_albedo_mix ( RID p_decal , float p_mix ) {
}
void TextureStorage : : decal_set_modulate ( RID p_decal , const Color & p_modulate ) {
}
void TextureStorage : : decal_set_cull_mask ( RID p_decal , uint32_t p_layers ) {
}
void TextureStorage : : decal_set_distance_fade ( RID p_decal , bool p_enabled , float p_begin , float p_length ) {
}
void TextureStorage : : decal_set_fade ( RID p_decal , float p_above , float p_below ) {
}
void TextureStorage : : decal_set_normal_fade ( RID p_decal , float p_fade ) {
}
AABB TextureStorage : : decal_get_aabb ( RID p_decal ) const {
return AABB ( ) ;
}
2022-09-12 09:44:48 +00:00
/* DECAL INSTANCE API */
RID TextureStorage : : decal_instance_create ( RID p_decal ) {
return RID ( ) ;
}
void TextureStorage : : decal_instance_free ( RID p_decal_instance ) {
}
void TextureStorage : : decal_instance_set_transform ( RID p_decal , const Transform3D & p_transform ) {
}
2022-04-07 14:00:51 +00:00
/* RENDER TARGET API */
GLuint TextureStorage : : system_fbo = 0 ;
2022-02-20 00:08:53 +00:00
void TextureStorage : : _update_render_target ( RenderTarget * rt ) {
2022-04-07 14:00:51 +00:00
// do not allocate a render target with no size
2022-02-20 00:08:53 +00:00
if ( rt - > size . x < = 0 | | rt - > size . y < = 0 ) {
2022-04-07 14:00:51 +00:00
return ;
}
// do not allocate a render target that is attached to the screen
2022-05-18 15:04:41 +00:00
if ( rt - > direct_to_screen ) {
2022-04-07 14:00:51 +00:00
rt - > fbo = system_fbo ;
return ;
}
2022-09-04 14:56:24 +00:00
Config * config = Config : : get_singleton ( ) ;
2022-05-18 15:04:41 +00:00
rt - > color_internal_format = rt - > is_transparent ? GL_RGBA8 : GL_RGB10_A2 ;
2022-02-20 00:08:53 +00:00
rt - > color_format = GL_RGBA ;
2022-09-12 15:19:03 +00:00
rt - > color_type = rt - > is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV ;
2022-02-20 00:08:53 +00:00
rt - > image_format = Image : : FORMAT_RGBA8 ;
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
glDisable ( GL_SCISSOR_TEST ) ;
glColorMask ( 1 , 1 , 1 , 1 ) ;
glDepthMask ( GL_FALSE ) ;
2022-04-07 14:00:51 +00:00
{
/* Front FBO */
Texture * texture = get_texture ( rt - > texture ) ;
ERR_FAIL_COND ( ! texture ) ;
// framebuffer
glGenFramebuffers ( 1 , & rt - > fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > fbo ) ;
// color
glGenTextures ( 1 , & rt - > color ) ;
2022-09-04 14:56:24 +00:00
if ( rt - > view_count > 1 & & config - > multiview_supported ) {
glBindTexture ( GL_TEXTURE_2D_ARRAY , rt - > color ) ;
glTexImage3D ( GL_TEXTURE_2D_ARRAY , 0 , rt - > color_internal_format , rt - > size . x , rt - > size . y , rt - > view_count , 0 , rt - > color_format , rt - > color_type , nullptr ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D_ARRAY , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
} else {
glBindTexture ( GL_TEXTURE_2D , rt - > color ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , rt - > color_internal_format , rt - > size . x , rt - > size . y , 0 , rt - > color_format , rt - > color_type , nullptr ) ;
2022-04-07 14:00:51 +00:00
2022-09-04 14:56:24 +00:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
}
2022-04-07 14:00:51 +00:00
2022-09-04 14:56:24 +00:00
if ( rt - > view_count > 1 & & config - > multiview_supported ) {
glFramebufferTextureMultiviewOVR ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , rt - > color , 0 , 0 , rt - > view_count ) ;
} else {
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , rt - > color , 0 ) ;
}
2022-04-07 14:00:51 +00:00
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
glDeleteFramebuffers ( 1 , & rt - > fbo ) ;
glDeleteTextures ( 1 , & rt - > color ) ;
rt - > fbo = 0 ;
2022-02-20 00:08:53 +00:00
rt - > size . x = 0 ;
rt - > size . y = 0 ;
2022-04-07 14:00:51 +00:00
rt - > color = 0 ;
texture - > tex_id = 0 ;
texture - > active = false ;
2022-02-20 00:08:53 +00:00
WARN_PRINT ( " Could not create render target, status: " + get_framebuffer_error ( status ) ) ;
2022-04-07 14:00:51 +00:00
return ;
}
2022-02-20 00:08:53 +00:00
texture - > format = rt - > image_format ;
2022-05-10 17:02:44 +00:00
texture - > real_format = rt - > image_format ;
2022-09-04 14:56:24 +00:00
if ( rt - > view_count > 1 & & config - > multiview_supported ) {
texture - > type = Texture : : TYPE_LAYERED ;
texture - > target = GL_TEXTURE_2D_ARRAY ;
texture - > layers = rt - > view_count ;
} else {
texture - > type = Texture : : TYPE_2D ;
texture - > target = GL_TEXTURE_2D ;
texture - > layers = 1 ;
}
2022-02-20 00:08:53 +00:00
texture - > gl_format_cache = rt - > color_format ;
2022-04-07 14:00:51 +00:00
texture - > gl_type_cache = GL_UNSIGNED_BYTE ;
2022-02-20 00:08:53 +00:00
texture - > gl_internal_format_cache = rt - > color_internal_format ;
2022-04-07 14:00:51 +00:00
texture - > tex_id = rt - > color ;
2022-02-20 00:08:53 +00:00
texture - > width = rt - > size . x ;
texture - > alloc_width = rt - > size . x ;
texture - > height = rt - > size . y ;
texture - > alloc_height = rt - > size . y ;
2022-04-07 14:00:51 +00:00
texture - > active = true ;
}
glClearColor ( 0 , 0 , 0 , 0 ) ;
2022-02-20 00:08:53 +00:00
glClear ( GL_COLOR_BUFFER_BIT ) ;
2022-05-18 15:04:41 +00:00
glBindFramebuffer ( GL_FRAMEBUFFER , system_fbo ) ;
}
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
void TextureStorage : : _create_render_target_backbuffer ( RenderTarget * rt ) {
ERR_FAIL_COND_MSG ( rt - > backbuffer_fbo ! = 0 , " Cannot allocate RenderTarget backbuffer: already initialized. " ) ;
ERR_FAIL_COND ( rt - > direct_to_screen ) ;
2022-02-20 00:08:53 +00:00
// Allocate mipmap chains for full screen blur
2022-05-18 15:04:41 +00:00
// Limit mipmaps so smallest is 32x32 to avoid unnecessary framebuffer switches
int count = MAX ( 1 , Image : : get_image_required_mipmaps ( rt - > size . x , rt - > size . y , Image : : FORMAT_RGBA8 ) - 4 ) ;
if ( rt - > size . x > 40 & & rt - > size . y > 40 ) {
GLsizei width = rt - > size . x ;
GLsizei height = rt - > size . y ;
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
rt - > mipmap_count = count ;
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
glGenTextures ( 1 , & rt - > backbuffer ) ;
glBindTexture ( GL_TEXTURE_2D , rt - > backbuffer ) ;
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
for ( int l = 0 ; l < count ; l + + ) {
glTexImage2D ( GL_TEXTURE_2D , l , rt - > color_internal_format , width , height , 0 , rt - > color_format , rt - > color_type , nullptr ) ;
width = MAX ( 1 , ( width / 2 ) ) ;
height = MAX ( 1 , ( height / 2 ) ) ;
}
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_BASE_LEVEL , 0 ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , count - 1 ) ;
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
glGenFramebuffers ( 1 , & rt - > backbuffer_fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > backbuffer_fbo ) ;
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , rt - > backbuffer , 0 ) ;
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
WARN_PRINT_ONCE ( " Cannot allocate mipmaps for canvas screen blur. Status: " + get_framebuffer_error ( status ) ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , system_fbo ) ;
return ;
}
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
// Initialize all levels to opaque Magenta.
for ( int j = 0 ; j < count ; j + + ) {
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , rt - > backbuffer , j ) ;
glClearColor ( 1.0 , 0.0 , 1.0 , 1.0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
}
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , rt - > backbuffer , 0 ) ;
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
2022-04-07 14:00:51 +00:00
}
}
2022-02-20 00:08:53 +00:00
void TextureStorage : : _clear_render_target ( RenderTarget * rt ) {
2022-04-07 14:00:51 +00:00
// there is nothing to clear when DIRECT_TO_SCREEN is used
2022-05-18 15:04:41 +00:00
if ( rt - > direct_to_screen ) {
2022-04-07 14:00:51 +00:00
return ;
}
if ( rt - > fbo ) {
glDeleteFramebuffers ( 1 , & rt - > fbo ) ;
glDeleteTextures ( 1 , & rt - > color ) ;
rt - > fbo = 0 ;
2022-02-20 00:08:53 +00:00
rt - > color = 0 ;
2022-04-07 14:00:51 +00:00
}
Texture * tex = get_texture ( rt - > texture ) ;
tex - > alloc_height = 0 ;
tex - > alloc_width = 0 ;
tex - > width = 0 ;
tex - > height = 0 ;
tex - > active = false ;
2022-05-18 15:04:41 +00:00
if ( rt - > backbuffer_fbo ! = 0 ) {
glDeleteFramebuffers ( 1 , & rt - > backbuffer_fbo ) ;
glDeleteTextures ( 1 , & rt - > backbuffer ) ;
rt - > backbuffer = 0 ;
rt - > backbuffer_fbo = 0 ;
2022-04-07 14:00:51 +00:00
}
2022-02-20 00:08:53 +00:00
}
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
RID TextureStorage : : render_target_create ( ) {
RenderTarget render_target ;
//render_target.was_used = false;
render_target . clear_requested = false ;
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
Texture t ;
t . active = true ;
t . render_target = & render_target ;
t . is_render_target = true ;
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
render_target . texture = texture_owner . make_rid ( t ) ;
_update_render_target ( & render_target ) ;
return render_target_owner . make_rid ( render_target ) ;
2022-04-07 14:00:51 +00:00
}
void TextureStorage : : render_target_free ( RID p_rid ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_rid ) ;
2022-02-20 00:08:53 +00:00
_clear_render_target ( rt ) ;
2022-04-07 14:00:51 +00:00
Texture * t = get_texture ( rt - > texture ) ;
if ( t ) {
2022-02-20 00:08:53 +00:00
t - > is_render_target = false ;
2022-04-07 14:00:51 +00:00
texture_free ( rt - > texture ) ;
2022-02-20 00:08:53 +00:00
//memdelete(t);
2022-04-07 14:00:51 +00:00
}
render_target_owner . free ( p_rid ) ;
}
void TextureStorage : : render_target_set_position ( RID p_render_target , int p_x , int p_y ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
2022-02-20 00:08:53 +00:00
rt - > position = Point2i ( p_x , p_y ) ;
2022-04-07 14:00:51 +00:00
}
2022-09-01 08:10:53 +00:00
Point2i TextureStorage : : render_target_get_position ( RID p_render_target ) const {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , Point2i ( ) ) ;
return rt - > position ;
} ;
2022-04-07 14:00:51 +00:00
void TextureStorage : : render_target_set_size ( RID p_render_target , int p_width , int p_height , uint32_t p_view_count ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
2022-09-04 14:56:24 +00:00
if ( p_width = = rt - > size . x & & p_height = = rt - > size . y & & p_view_count = = rt - > view_count ) {
2022-04-07 14:00:51 +00:00
return ;
}
2022-02-20 00:08:53 +00:00
_clear_render_target ( rt ) ;
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
rt - > size = Size2i ( p_width , p_height ) ;
2022-09-04 14:56:24 +00:00
rt - > view_count = p_view_count ;
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
_update_render_target ( rt ) ;
2022-04-07 14:00:51 +00:00
}
// TODO: convert to Size2i internally
2022-09-01 08:10:53 +00:00
Size2i TextureStorage : : render_target_get_size ( RID p_render_target ) const {
2022-04-07 14:00:51 +00:00
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
2022-09-01 08:10:53 +00:00
ERR_FAIL_COND_V ( ! rt , Size2i ( ) ) ;
2022-04-07 14:00:51 +00:00
2022-02-20 00:08:53 +00:00
return rt - > size ;
2022-04-07 14:00:51 +00:00
}
RID TextureStorage : : render_target_get_texture ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , RID ( ) ) ;
2022-09-01 08:10:53 +00:00
return rt - > texture ;
2022-04-07 14:00:51 +00:00
}
2022-05-18 15:04:41 +00:00
void TextureStorage : : render_target_set_transparent ( RID p_render_target , bool p_transparent ) {
2022-04-07 14:00:51 +00:00
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
2022-05-18 15:04:41 +00:00
rt - > is_transparent = p_transparent ;
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
_clear_render_target ( rt ) ;
_update_render_target ( rt ) ;
}
2022-04-07 14:00:51 +00:00
2022-09-01 08:10:53 +00:00
bool TextureStorage : : render_target_get_transparent ( RID p_render_target ) const {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , false ) ;
return rt - > is_transparent ;
}
2022-05-18 15:04:41 +00:00
void TextureStorage : : render_target_set_direct_to_screen ( RID p_render_target , bool p_direct_to_screen ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
if ( p_direct_to_screen = = rt - > direct_to_screen ) {
return ;
2022-04-07 14:00:51 +00:00
}
2022-05-18 15:04:41 +00:00
// When setting DIRECT_TO_SCREEN, you need to clear before the value is set, but allocate after as
// those functions change how they operate depending on the value of DIRECT_TO_SCREEN
_clear_render_target ( rt ) ;
rt - > direct_to_screen = p_direct_to_screen ;
_update_render_target ( rt ) ;
2022-04-07 14:00:51 +00:00
}
2022-09-01 08:10:53 +00:00
bool TextureStorage : : render_target_get_direct_to_screen ( RID p_render_target ) const {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , false ) ;
return rt - > direct_to_screen ;
}
bool TextureStorage : : render_target_was_used ( RID p_render_target ) const {
2022-04-07 14:00:51 +00:00
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , false ) ;
return rt - > used_in_frame ;
}
void TextureStorage : : render_target_clear_used ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
rt - > used_in_frame = false ;
}
2022-08-12 23:02:32 +00:00
void TextureStorage : : render_target_set_msaa ( RID p_render_target , RS : : ViewportMSAA p_msaa ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
if ( p_msaa = = rt - > msaa ) {
return ;
}
WARN_PRINT ( " 2D MSAA is not yet supported for GLES3. " ) ;
_clear_render_target ( rt ) ;
rt - > msaa = p_msaa ;
_update_render_target ( rt ) ;
}
2022-09-01 08:10:53 +00:00
RS : : ViewportMSAA TextureStorage : : render_target_get_msaa ( RID p_render_target ) const {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , RS : : VIEWPORT_MSAA_DISABLED ) ;
return rt - > msaa ;
}
2022-04-07 14:00:51 +00:00
void TextureStorage : : render_target_request_clear ( RID p_render_target , const Color & p_clear_color ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
rt - > clear_requested = true ;
rt - > clear_color = p_clear_color ;
}
bool TextureStorage : : render_target_is_clear_requested ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , false ) ;
return rt - > clear_requested ;
}
Color TextureStorage : : render_target_get_clear_request_color ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , Color ( ) ) ;
return rt - > clear_color ;
}
void TextureStorage : : render_target_disable_clear_request ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
rt - > clear_requested = false ;
}
void TextureStorage : : render_target_do_clear_request ( RID p_render_target ) {
2022-02-20 00:08:53 +00:00
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
if ( ! rt - > clear_requested ) {
return ;
}
2022-06-21 04:56:26 +00:00
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > fbo ) ;
2022-02-20 00:08:53 +00:00
glClearBufferfv ( GL_COLOR , 0 , rt - > clear_color . components ) ;
rt - > clear_requested = false ;
2022-06-21 04:56:26 +00:00
glBindFramebuffer ( GL_FRAMEBUFFER , system_fbo ) ;
2022-04-07 14:00:51 +00:00
}
void TextureStorage : : render_target_set_sdf_size_and_scale ( RID p_render_target , RS : : ViewportSDFOversize p_size , RS : : ViewportSDFScale p_scale ) {
}
Rect2i TextureStorage : : render_target_get_sdf_rect ( RID p_render_target ) const {
return Rect2i ( ) ;
}
void TextureStorage : : render_target_mark_sdf_enabled ( RID p_render_target , bool p_enabled ) {
}
2022-05-18 15:04:41 +00:00
void TextureStorage : : render_target_copy_to_back_buffer ( RID p_render_target , const Rect2i & p_region , bool p_gen_mipmaps ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
ERR_FAIL_COND ( rt - > direct_to_screen ) ;
if ( rt - > backbuffer_fbo = = 0 ) {
_create_render_target_backbuffer ( rt ) ;
}
Rect2i region ;
if ( p_region = = Rect2i ( ) ) {
region . size = rt - > size ;
} else {
region = Rect2i ( Size2i ( ) , rt - > size ) . intersection ( p_region ) ;
if ( region . size = = Size2i ( ) ) {
return ; //nothing to do
}
}
glDisable ( GL_BLEND ) ;
//single texture copy for backbuffer
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > backbuffer_fbo ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , rt - > color ) ;
GLES3 : : CopyEffects : : get_singleton ( ) - > copy_screen ( ) ;
if ( p_gen_mipmaps ) {
GLES3 : : CopyEffects : : get_singleton ( ) - > bilinear_blur ( rt - > backbuffer , rt - > mipmap_count , region ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > backbuffer_fbo ) ;
}
glEnable ( GL_BLEND ) ; // 2D almost always uses blend.
}
void TextureStorage : : render_target_clear_back_buffer ( RID p_render_target , const Rect2i & p_region , const Color & p_color ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
ERR_FAIL_COND ( rt - > direct_to_screen ) ;
if ( rt - > backbuffer_fbo = = 0 ) {
_create_render_target_backbuffer ( rt ) ;
}
Rect2i region ;
if ( p_region = = Rect2i ( ) ) {
// Just do a full screen clear;
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > backbuffer_fbo ) ;
glClearColor ( p_color . r , p_color . g , p_color . b , p_color . a ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
} else {
region = Rect2i ( Size2i ( ) , rt - > size ) . intersection ( p_region ) ;
if ( region . size = = Size2i ( ) ) {
return ; //nothing to do
}
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > backbuffer_fbo ) ;
GLES3 : : CopyEffects : : get_singleton ( ) - > set_color ( p_color , region ) ;
}
}
void TextureStorage : : render_target_gen_back_buffer_mipmaps ( RID p_render_target , const Rect2i & p_region ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
if ( rt - > backbuffer_fbo = = 0 ) {
_create_render_target_backbuffer ( rt ) ;
}
Rect2i region ;
if ( p_region = = Rect2i ( ) ) {
region . size = rt - > size ;
} else {
region = Rect2i ( Size2i ( ) , rt - > size ) . intersection ( p_region ) ;
if ( region . size = = Size2i ( ) ) {
return ; //nothing to do
}
}
GLES3 : : CopyEffects : : get_singleton ( ) - > bilinear_blur ( rt - > backbuffer , rt - > mipmap_count , region ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > backbuffer_fbo ) ;
}
2022-03-12 11:19:59 +00:00
# endif // GLES3_ENABLED