2023-12-17 15:39:29 +01:00
2023-12-14 21:54:22 +01:00
/* rasterizer_canvas_base_gles2.cpp */
2023-12-17 15:39:29 +01:00
2023-12-14 21:54:22 +01:00
# include "rasterizer_canvas_base_gles2.h"
# include "core/os/os.h"
# include "core/config/project_settings.h"
# include "drivers/gles_common/rasterizer_asserts.h"
# include "servers/rendering/rendering_server_raster.h"
# ifndef GLES_OVER_GL
# define glClearDepth glClearDepthf
# endif
void RasterizerCanvasBaseGLES2 : : canvas_begin ( ) {
state . using_transparent_rt = false ;
state . using_modulate = false ;
state . canvas_shader . set_conditional ( CanvasShaderGLES2 : : USE_ATTRIB_MODULATE , false ) ;
state . canvas_shader . bind ( ) ;
int viewport_x , viewport_y , viewport_width , viewport_height ;
if ( storage - > frame . current_rt ) {
glBindFramebuffer ( GL_FRAMEBUFFER , storage - > frame . current_rt - > fbo ) ;
state . using_transparent_rt = storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_TRANSPARENT ] ;
if ( storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_DIRECT_TO_SCREEN ] ) {
// set Viewport and Scissor when rendering directly to screen
viewport_width = storage - > frame . current_rt - > width ;
viewport_height = storage - > frame . current_rt - > height ;
viewport_x = storage - > frame . current_rt - > x ;
viewport_y = OS : : get_singleton ( ) - > get_window_size ( ) . height - viewport_height - storage - > frame . current_rt - > y ;
glScissor ( viewport_x , viewport_y , viewport_width , viewport_height ) ;
glViewport ( viewport_x , viewport_y , viewport_width , viewport_height ) ;
glEnable ( GL_SCISSOR_TEST ) ;
}
}
if ( storage - > frame . clear_request ) {
glClearColor ( storage - > frame . clear_request_color . r ,
storage - > frame . clear_request_color . g ,
storage - > frame . clear_request_color . b ,
state . using_transparent_rt ? storage - > frame . clear_request_color . a : 1.0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
storage - > frame . clear_request = false ;
}
/*
if ( storage - > frame . current_rt ) {
glBindFramebuffer ( GL_FRAMEBUFFER , storage - > frame . current_rt - > fbo ) ;
glColorMask ( 1 , 1 , 1 , 1 ) ;
}
*/
reset_canvas ( ) ;
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > resources . white_tex ) ;
glVertexAttrib4f ( RS : : ARRAY_COLOR , 1 , 1 , 1 , 1 ) ;
glDisableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
// set up default uniforms
Transform canvas_transform ;
if ( storage - > frame . current_rt ) {
float csy = 1.0 ;
if ( storage - > frame . current_rt & & storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_VFLIP ] ) {
csy = - 1.0 ;
}
canvas_transform . translate_local ( - ( storage - > frame . current_rt - > width / 2.0f ) , - ( storage - > frame . current_rt - > height / 2.0f ) , 0.0f ) ;
canvas_transform . scale ( Vector3 ( 2.0f / storage - > frame . current_rt - > width , csy * - 2.0f / storage - > frame . current_rt - > height , 1.0f ) ) ;
} else {
Vector2 ssize = OS : : get_singleton ( ) - > get_window_size ( ) ;
canvas_transform . translate_local ( - ( ssize . width / 2.0f ) , - ( ssize . height / 2.0f ) , 0.0f ) ;
canvas_transform . scale ( Vector3 ( 2.0f / ssize . width , - 2.0f / ssize . height , 1.0f ) ) ;
}
state . uniforms . projection_matrix = canvas_transform ;
state . uniforms . final_modulate = Color ( 1 , 1 , 1 , 1 ) ;
state . uniforms . modelview_matrix = Transform2D ( ) ;
state . uniforms . extra_matrix = Transform2D ( ) ;
_set_uniforms ( ) ;
_bind_quad_buffer ( ) ;
}
void RasterizerCanvasBaseGLES2 : : canvas_end ( ) {
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
for ( int i = 0 ; i < RS : : ARRAY_MAX ; i + + ) {
glDisableVertexAttribArray ( i ) ;
}
if ( storage - > frame . current_rt & & storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_DIRECT_TO_SCREEN ] ) {
//reset viewport to full window size
int viewport_width = OS : : get_singleton ( ) - > get_window_size ( ) . width ;
int viewport_height = OS : : get_singleton ( ) - > get_window_size ( ) . height ;
glViewport ( 0 , 0 , viewport_width , viewport_height ) ;
glScissor ( 0 , 0 , viewport_width , viewport_height ) ;
}
state . using_texture_rect = false ;
state . using_ninepatch = false ;
state . using_transparent_rt = false ;
}
void RasterizerCanvasBaseGLES2 : : draw_generic_textured_rect ( const Rect2 & p_rect , const Rect2 & p_src ) {
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : DST_RECT , Color ( p_rect . position . x , p_rect . position . y , p_rect . size . x , p_rect . size . y ) ) ;
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : SRC_RECT , Color ( p_src . position . x , p_src . position . y , p_src . size . x , p_src . size . y ) ) ;
glDrawArrays ( GL_TRIANGLE_FAN , 0 , 4 ) ;
}
void RasterizerCanvasBaseGLES2 : : _set_texture_rect_mode ( bool p_texture_rect , bool p_light_angle , bool p_modulate , bool p_large_vertex ) {
// always set this directly (this could be state checked)
state . canvas_shader . set_conditional ( CanvasShaderGLES2 : : USE_TEXTURE_RECT , p_texture_rect ) ;
if ( state . using_modulate ! = p_modulate ) {
state . using_modulate = p_modulate ;
state . canvas_shader . set_conditional ( CanvasShaderGLES2 : : USE_ATTRIB_MODULATE , p_modulate ) ;
}
}
RasterizerStorageGLES2 : : Texture * RasterizerCanvasBaseGLES2 : : _bind_canvas_texture ( const RID & p_texture , const RID & p_normal_map ) {
RasterizerStorageGLES2 : : Texture * tex_return = nullptr ;
if ( p_texture . is_valid ( ) ) {
RasterizerStorageGLES2 : : Texture * texture = storage - > texture_owner . getornull ( p_texture ) ;
if ( ! texture ) {
state . current_tex = RID ( ) ;
state . current_tex_ptr = nullptr ;
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 + storage - > config . max_texture_image_units - 1 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > resources . white_tex ) ;
} else {
if ( texture - > redraw_if_visible ) {
RenderingServerRaster : : redraw_request ( false ) ;
}
texture = texture - > get_ptr ( ) ;
if ( texture - > render_target ) {
texture - > render_target - > used_in_frame = true ;
}
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 + storage - > config . max_texture_image_units - 1 ) ;
glBindTexture ( GL_TEXTURE_2D , texture - > tex_id ) ;
state . current_tex = p_texture ;
state . current_tex_ptr = texture ;
tex_return = texture ;
}
} else {
state . current_tex = RID ( ) ;
state . current_tex_ptr = nullptr ;
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 + storage - > config . max_texture_image_units - 1 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > resources . white_tex ) ;
}
if ( p_normal_map = = state . current_normal ) {
//do none
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : USE_DEFAULT_NORMAL , state . current_normal . is_valid ( ) ) ;
} else if ( p_normal_map . is_valid ( ) ) {
RasterizerStorageGLES2 : : Texture * normal_map = storage - > texture_owner . getornull ( p_normal_map ) ;
if ( ! normal_map ) {
state . current_normal = RID ( ) ;
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 + storage - > config . max_texture_image_units - 2 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > resources . normal_tex ) ;
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : USE_DEFAULT_NORMAL , false ) ;
} else {
if ( normal_map - > redraw_if_visible ) { //check before proxy, because this is usually used with proxies
RenderingServerRaster : : redraw_request ( false ) ;
}
normal_map = normal_map - > get_ptr ( ) ;
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 + storage - > config . max_texture_image_units - 2 ) ;
glBindTexture ( GL_TEXTURE_2D , normal_map - > tex_id ) ;
state . current_normal = p_normal_map ;
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : USE_DEFAULT_NORMAL , true ) ;
}
} else {
state . current_normal = RID ( ) ;
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 + storage - > config . max_texture_image_units - 2 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > resources . normal_tex ) ;
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : USE_DEFAULT_NORMAL , false ) ;
}
return tex_return ;
}
void RasterizerCanvasBaseGLES2 : : draw_window_margins ( int * black_margin , RID * black_image ) {
Vector2 window_size = OS : : get_singleton ( ) - > get_window_size ( ) ;
int window_h = window_size . height ;
int window_w = window_size . width ;
glBindFramebuffer ( GL_FRAMEBUFFER , storage - > system_fbo ) ;
glViewport ( 0 , 0 , window_size . width , window_size . height ) ;
canvas_begin ( ) ;
if ( black_image [ MARGIN_LEFT ] . is_valid ( ) ) {
_bind_canvas_texture ( black_image [ MARGIN_LEFT ] , RID ( ) ) ;
Size2 sz ( storage - > texture_get_width ( black_image [ MARGIN_LEFT ] ) , storage - > texture_get_height ( black_image [ MARGIN_LEFT ] ) ) ;
draw_generic_textured_rect ( Rect2 ( 0 , 0 , black_margin [ MARGIN_LEFT ] , window_h ) ,
Rect2 ( 0 , 0 , ( float ) black_margin [ MARGIN_LEFT ] / sz . x , ( float ) ( window_h ) / sz . y ) ) ;
} else if ( black_margin [ MARGIN_LEFT ] ) {
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > resources . black_tex ) ;
draw_generic_textured_rect ( Rect2 ( 0 , 0 , black_margin [ MARGIN_LEFT ] , window_h ) , Rect2 ( 0 , 0 , 1 , 1 ) ) ;
}
if ( black_image [ MARGIN_RIGHT ] . is_valid ( ) ) {
_bind_canvas_texture ( black_image [ MARGIN_RIGHT ] , RID ( ) ) ;
Size2 sz ( storage - > texture_get_width ( black_image [ MARGIN_RIGHT ] ) , storage - > texture_get_height ( black_image [ MARGIN_RIGHT ] ) ) ;
draw_generic_textured_rect ( Rect2 ( window_w - black_margin [ MARGIN_RIGHT ] , 0 , black_margin [ MARGIN_RIGHT ] , window_h ) ,
Rect2 ( 0 , 0 , ( float ) black_margin [ MARGIN_RIGHT ] / sz . x , ( float ) window_h / sz . y ) ) ;
} else if ( black_margin [ MARGIN_RIGHT ] ) {
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > resources . black_tex ) ;
draw_generic_textured_rect ( Rect2 ( window_w - black_margin [ MARGIN_RIGHT ] , 0 , black_margin [ MARGIN_RIGHT ] , window_h ) , Rect2 ( 0 , 0 , 1 , 1 ) ) ;
}
if ( black_image [ MARGIN_TOP ] . is_valid ( ) ) {
_bind_canvas_texture ( black_image [ MARGIN_TOP ] , RID ( ) ) ;
Size2 sz ( storage - > texture_get_width ( black_image [ MARGIN_TOP ] ) , storage - > texture_get_height ( black_image [ MARGIN_TOP ] ) ) ;
draw_generic_textured_rect ( Rect2 ( 0 , 0 , window_w , black_margin [ MARGIN_TOP ] ) ,
Rect2 ( 0 , 0 , ( float ) window_w / sz . x , ( float ) black_margin [ MARGIN_TOP ] / sz . y ) ) ;
} else if ( black_margin [ MARGIN_TOP ] ) {
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > resources . black_tex ) ;
draw_generic_textured_rect ( Rect2 ( 0 , 0 , window_w , black_margin [ MARGIN_TOP ] ) , Rect2 ( 0 , 0 , 1 , 1 ) ) ;
}
if ( black_image [ MARGIN_BOTTOM ] . is_valid ( ) ) {
_bind_canvas_texture ( black_image [ MARGIN_BOTTOM ] , RID ( ) ) ;
Size2 sz ( storage - > texture_get_width ( black_image [ MARGIN_BOTTOM ] ) , storage - > texture_get_height ( black_image [ MARGIN_BOTTOM ] ) ) ;
draw_generic_textured_rect ( Rect2 ( 0 , window_h - black_margin [ MARGIN_BOTTOM ] , window_w , black_margin [ MARGIN_BOTTOM ] ) ,
Rect2 ( 0 , 0 , ( float ) window_w / sz . x , ( float ) black_margin [ MARGIN_BOTTOM ] / sz . y ) ) ;
} else if ( black_margin [ MARGIN_BOTTOM ] ) {
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > resources . black_tex ) ;
draw_generic_textured_rect ( Rect2 ( 0 , window_h - black_margin [ MARGIN_BOTTOM ] , window_w , black_margin [ MARGIN_BOTTOM ] ) , Rect2 ( 0 , 0 , 1 , 1 ) ) ;
}
canvas_end ( ) ;
}
void RasterizerCanvasBaseGLES2 : : _bind_quad_buffer ( ) {
glBindBuffer ( GL_ARRAY_BUFFER , data . canvas_quad_vertices ) ;
glEnableVertexAttribArray ( RS : : ARRAY_VERTEX ) ;
glVertexAttribPointer ( RS : : ARRAY_VERTEX , 2 , GL_FLOAT , GL_FALSE , 0 , nullptr ) ;
}
void RasterizerCanvasBaseGLES2 : : _set_uniforms ( ) {
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : PROJECTION_MATRIX , state . uniforms . projection_matrix ) ;
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : MODELVIEW_MATRIX , state . uniforms . modelview_matrix ) ;
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : EXTRA_MATRIX , state . uniforms . extra_matrix ) ;
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : FINAL_MODULATE , state . uniforms . final_modulate ) ;
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : TIME , storage - > frame . time [ 0 ] ) ;
if ( storage - > frame . current_rt ) {
Vector2 screen_pixel_size ;
screen_pixel_size . x = 1.0 / storage - > frame . current_rt - > width ;
screen_pixel_size . y = 1.0 / storage - > frame . current_rt - > height ;
state . canvas_shader . set_uniform ( CanvasShaderGLES2 : : SCREEN_PIXEL_SIZE , screen_pixel_size ) ;
}
}
void RasterizerCanvasBaseGLES2 : : reset_canvas ( ) {
glDisable ( GL_CULL_FACE ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_SCISSOR_TEST ) ;
glDisable ( GL_DITHER ) ;
glEnable ( GL_BLEND ) ;
if ( storage - > frame . current_rt & & storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_TRANSPARENT ] ) {
glBlendFuncSeparate ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA , GL_ONE , GL_ONE_MINUS_SRC_ALPHA ) ;
} else {
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
}
// bind the back buffer to a texture so shaders can use it.
// It should probably use texture unit -3 (as GLES2 does as well) but currently that's buggy.
// keeping this for now as there's nothing else that uses texture unit 2
// TODO ^
if ( storage - > frame . current_rt ) {
// WRAPPED_GL_ACTIVE_TEXTURE(GL_TEXTURE0 + 2);
// glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color);
}
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
void RasterizerCanvasBaseGLES2 : : _copy_texscreen ( const Rect2 & p_rect ) {
state . canvas_texscreen_used = true ;
_copy_screen ( p_rect ) ;
// back to canvas, force rebind
state . using_texture_rect = false ;
state . canvas_shader . bind ( ) ;
_bind_canvas_texture ( state . current_tex , state . current_normal ) ;
_set_uniforms ( ) ;
}
void RasterizerCanvasBaseGLES2 : : _draw_polygon ( const int * p_indices , int p_index_count , int p_vertex_count , const Vector2 * p_vertices , const Vector2 * p_uvs , const Color * p_colors , bool p_singlecolor , const float * p_weights , const int * p_bones ) {
glBindBuffer ( GL_ARRAY_BUFFER , data . polygon_buffer ) ;
uint32_t buffer_ofs = 0 ;
uint32_t buffer_ofs_after = buffer_ofs + ( sizeof ( Vector2 ) * p_vertex_count ) ;
# ifdef DEBUG_ENABLED
ERR_FAIL_COND ( buffer_ofs_after > data . polygon_buffer_size ) ;
# endif
storage - > buffer_orphan_and_upload ( data . polygon_buffer_size , 0 , sizeof ( Vector2 ) * p_vertex_count , p_vertices , GL_ARRAY_BUFFER , _buffer_upload_usage_flag , true ) ;
glEnableVertexAttribArray ( RS : : ARRAY_VERTEX ) ;
glVertexAttribPointer ( RS : : ARRAY_VERTEX , 2 , GL_FLOAT , GL_FALSE , sizeof ( Vector2 ) , nullptr ) ;
buffer_ofs = buffer_ofs_after ;
if ( p_singlecolor ) {
glDisableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
Color m = * p_colors ;
glVertexAttrib4f ( RS : : ARRAY_COLOR , m . r , m . g , m . b , m . a ) ;
} else if ( ! p_colors ) {
glDisableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
glVertexAttrib4f ( RS : : ARRAY_COLOR , 1 , 1 , 1 , 1 ) ;
} else {
RAST_FAIL_COND ( ! storage - > safe_buffer_sub_data ( data . polygon_buffer_size , GL_ARRAY_BUFFER , buffer_ofs , sizeof ( Color ) * p_vertex_count , p_colors , buffer_ofs_after ) ) ;
glEnableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
glVertexAttribPointer ( RS : : ARRAY_COLOR , 4 , GL_FLOAT , GL_FALSE , sizeof ( Color ) , CAST_INT_TO_UCHAR_PTR ( buffer_ofs ) ) ;
buffer_ofs = buffer_ofs_after ;
}
if ( p_uvs ) {
RAST_FAIL_COND ( ! storage - > safe_buffer_sub_data ( data . polygon_buffer_size , GL_ARRAY_BUFFER , buffer_ofs , sizeof ( Vector2 ) * p_vertex_count , p_uvs , buffer_ofs_after ) ) ;
glEnableVertexAttribArray ( RS : : ARRAY_TEX_UV ) ;
glVertexAttribPointer ( RS : : ARRAY_TEX_UV , 2 , GL_FLOAT , GL_FALSE , sizeof ( Vector2 ) , CAST_INT_TO_UCHAR_PTR ( buffer_ofs ) ) ;
buffer_ofs = buffer_ofs_after ;
} else {
glDisableVertexAttribArray ( RS : : ARRAY_TEX_UV ) ;
}
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , data . polygon_index_buffer ) ;
if ( storage - > config . support_32_bits_indices ) { //should check for
# ifdef DEBUG_ENABLED
ERR_FAIL_COND ( ( sizeof ( int ) * p_index_count ) > data . polygon_index_buffer_size ) ;
# endif
storage - > buffer_orphan_and_upload ( data . polygon_index_buffer_size , 0 , sizeof ( int ) * p_index_count , p_indices , GL_ELEMENT_ARRAY_BUFFER , _buffer_upload_usage_flag , true ) ;
glDrawElements ( GL_TRIANGLES , p_index_count , GL_UNSIGNED_INT , nullptr ) ;
storage - > info . render . _2d_draw_call_count + + ;
} else {
# ifdef DEBUG_ENABLED
ERR_FAIL_COND ( ( sizeof ( uint16_t ) * p_index_count ) > data . polygon_index_buffer_size ) ;
# endif
uint16_t * index16 = ( uint16_t * ) alloca ( sizeof ( uint16_t ) * p_index_count ) ;
for ( int i = 0 ; i < p_index_count ; i + + ) {
index16 [ i ] = uint16_t ( p_indices [ i ] ) ;
}
storage - > buffer_orphan_and_upload ( data . polygon_index_buffer_size , 0 , sizeof ( uint16_t ) * p_index_count , index16 , GL_ELEMENT_ARRAY_BUFFER , _buffer_upload_usage_flag , true ) ;
glDrawElements ( GL_TRIANGLES , p_index_count , GL_UNSIGNED_SHORT , nullptr ) ;
storage - > info . render . _2d_draw_call_count + + ;
}
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
void RasterizerCanvasBaseGLES2 : : _draw_generic ( GLuint p_primitive , int p_vertex_count , const Vector2 * p_vertices , const Vector2 * p_uvs , const Color * p_colors , bool p_singlecolor ) {
glBindBuffer ( GL_ARRAY_BUFFER , data . polygon_buffer ) ;
uint32_t buffer_ofs = 0 ;
uint32_t buffer_ofs_after = buffer_ofs + ( sizeof ( Vector2 ) * p_vertex_count ) ;
# ifdef DEBUG_ENABLED
ERR_FAIL_COND ( buffer_ofs_after > data . polygon_buffer_size ) ;
# endif
storage - > buffer_orphan_and_upload ( data . polygon_buffer_size , 0 , sizeof ( Vector2 ) * p_vertex_count , p_vertices , GL_ARRAY_BUFFER , _buffer_upload_usage_flag , true ) ;
glEnableVertexAttribArray ( RS : : ARRAY_VERTEX ) ;
glVertexAttribPointer ( RS : : ARRAY_VERTEX , 2 , GL_FLOAT , GL_FALSE , sizeof ( Vector2 ) , nullptr ) ;
buffer_ofs = buffer_ofs_after ;
if ( p_singlecolor ) {
glDisableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
Color m = * p_colors ;
glVertexAttrib4f ( RS : : ARRAY_COLOR , m . r , m . g , m . b , m . a ) ;
} else if ( ! p_colors ) {
glDisableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
glVertexAttrib4f ( RS : : ARRAY_COLOR , 1 , 1 , 1 , 1 ) ;
} else {
RAST_FAIL_COND ( ! storage - > safe_buffer_sub_data ( data . polygon_buffer_size , GL_ARRAY_BUFFER , buffer_ofs , sizeof ( Color ) * p_vertex_count , p_colors , buffer_ofs_after ) ) ;
glEnableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
glVertexAttribPointer ( RS : : ARRAY_COLOR , 4 , GL_FLOAT , GL_FALSE , sizeof ( Color ) , CAST_INT_TO_UCHAR_PTR ( buffer_ofs ) ) ;
buffer_ofs = buffer_ofs_after ;
}
if ( p_uvs ) {
RAST_FAIL_COND ( ! storage - > safe_buffer_sub_data ( data . polygon_buffer_size , GL_ARRAY_BUFFER , buffer_ofs , sizeof ( Vector2 ) * p_vertex_count , p_uvs , buffer_ofs_after ) ) ;
glEnableVertexAttribArray ( RS : : ARRAY_TEX_UV ) ;
glVertexAttribPointer ( RS : : ARRAY_TEX_UV , 2 , GL_FLOAT , GL_FALSE , sizeof ( Vector2 ) , CAST_INT_TO_UCHAR_PTR ( buffer_ofs ) ) ;
buffer_ofs = buffer_ofs_after ;
} else {
glDisableVertexAttribArray ( RS : : ARRAY_TEX_UV ) ;
}
glDrawArrays ( p_primitive , 0 , p_vertex_count ) ;
storage - > info . render . _2d_draw_call_count + + ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
}
void RasterizerCanvasBaseGLES2 : : _draw_generic_indices ( GLuint p_primitive , const int * p_indices , int p_index_count , int p_vertex_count , const Vector2 * p_vertices , const Vector2 * p_uvs , const Color * p_colors , bool p_singlecolor ) {
glBindBuffer ( GL_ARRAY_BUFFER , data . polygon_buffer ) ;
uint32_t buffer_ofs = 0 ;
uint32_t buffer_ofs_after = buffer_ofs + ( sizeof ( Vector2 ) * p_vertex_count ) ;
# ifdef DEBUG_ENABLED
ERR_FAIL_COND ( buffer_ofs_after > data . polygon_buffer_size ) ;
# endif
storage - > buffer_orphan_and_upload ( data . polygon_buffer_size , 0 , sizeof ( Vector2 ) * p_vertex_count , p_vertices , GL_ARRAY_BUFFER , _buffer_upload_usage_flag , true ) ;
glEnableVertexAttribArray ( RS : : ARRAY_VERTEX ) ;
glVertexAttribPointer ( RS : : ARRAY_VERTEX , 2 , GL_FLOAT , GL_FALSE , sizeof ( Vector2 ) , nullptr ) ;
buffer_ofs = buffer_ofs_after ;
if ( p_singlecolor ) {
glDisableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
Color m = * p_colors ;
glVertexAttrib4f ( RS : : ARRAY_COLOR , m . r , m . g , m . b , m . a ) ;
} else if ( ! p_colors ) {
glDisableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
glVertexAttrib4f ( RS : : ARRAY_COLOR , 1 , 1 , 1 , 1 ) ;
} else {
RAST_FAIL_COND ( ! storage - > safe_buffer_sub_data ( data . polygon_buffer_size , GL_ARRAY_BUFFER , buffer_ofs , sizeof ( Color ) * p_vertex_count , p_colors , buffer_ofs_after ) ) ;
glEnableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
glVertexAttribPointer ( RS : : ARRAY_COLOR , 4 , GL_FLOAT , GL_FALSE , sizeof ( Color ) , CAST_INT_TO_UCHAR_PTR ( buffer_ofs ) ) ;
buffer_ofs = buffer_ofs_after ;
}
if ( p_uvs ) {
RAST_FAIL_COND ( ! storage - > safe_buffer_sub_data ( data . polygon_buffer_size , GL_ARRAY_BUFFER , buffer_ofs , sizeof ( Vector2 ) * p_vertex_count , p_uvs , buffer_ofs_after ) ) ;
glEnableVertexAttribArray ( RS : : ARRAY_TEX_UV ) ;
glVertexAttribPointer ( RS : : ARRAY_TEX_UV , 2 , GL_FLOAT , GL_FALSE , sizeof ( Vector2 ) , CAST_INT_TO_UCHAR_PTR ( buffer_ofs ) ) ;
buffer_ofs = buffer_ofs_after ;
} else {
glDisableVertexAttribArray ( RS : : ARRAY_TEX_UV ) ;
}
# ifdef RASTERIZER_EXTRA_CHECKS
// very slow, do not enable in normal use
for ( int n = 0 ; n < p_index_count ; n + + ) {
RAST_DEV_DEBUG_ASSERT ( p_indices [ n ] < p_vertex_count ) ;
}
# endif
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , data . polygon_index_buffer ) ;
if ( storage - > config . support_32_bits_indices ) { //should check for
# ifdef DEBUG_ENABLED
ERR_FAIL_COND ( ( sizeof ( int ) * p_index_count ) > data . polygon_index_buffer_size ) ;
# endif
storage - > buffer_orphan_and_upload ( data . polygon_index_buffer_size , 0 , sizeof ( int ) * p_index_count , p_indices , GL_ELEMENT_ARRAY_BUFFER , _buffer_upload_usage_flag , true ) ;
glDrawElements ( p_primitive , p_index_count , GL_UNSIGNED_INT , nullptr ) ;
storage - > info . render . _2d_draw_call_count + + ;
} else {
# ifdef DEBUG_ENABLED
ERR_FAIL_COND ( ( sizeof ( uint16_t ) * p_index_count ) > data . polygon_index_buffer_size ) ;
# endif
uint16_t * index16 = ( uint16_t * ) alloca ( sizeof ( uint16_t ) * p_index_count ) ;
for ( int i = 0 ; i < p_index_count ; i + + ) {
index16 [ i ] = uint16_t ( p_indices [ i ] ) ;
}
storage - > buffer_orphan_and_upload ( data . polygon_index_buffer_size , 0 , sizeof ( uint16_t ) * p_index_count , index16 , GL_ELEMENT_ARRAY_BUFFER , _buffer_upload_usage_flag , true ) ;
glDrawElements ( p_primitive , p_index_count , GL_UNSIGNED_SHORT , nullptr ) ;
storage - > info . render . _2d_draw_call_count + + ;
}
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
void RasterizerCanvasBaseGLES2 : : _draw_gui_primitive ( int p_points , const Vector2 * p_vertices , const Color * p_colors , const Vector2 * p_uvs , const float * p_light_angles ) {
static const GLenum prim [ 5 ] = { GL_POINTS , GL_POINTS , GL_LINES , GL_TRIANGLES , GL_TRIANGLE_FAN } ;
int color_offset = 0 ;
int uv_offset = 0 ;
int light_angle_offset = 0 ;
int stride = 2 ;
if ( p_colors ) {
color_offset = stride ;
stride + = 4 ;
}
if ( p_uvs ) {
uv_offset = stride ;
stride + = 2 ;
}
if ( p_light_angles ) { //light_angles
light_angle_offset = stride ;
stride + = 1 ;
}
DEV_ASSERT ( p_points < = 4 ) ;
float buffer_data [ ( 2 + 2 + 4 + 1 ) * 4 ] ;
for ( int i = 0 ; i < p_points ; i + + ) {
buffer_data [ stride * i + 0 ] = p_vertices [ i ] . x ;
buffer_data [ stride * i + 1 ] = p_vertices [ i ] . y ;
}
if ( p_colors ) {
for ( int i = 0 ; i < p_points ; i + + ) {
buffer_data [ stride * i + color_offset + 0 ] = p_colors [ i ] . r ;
buffer_data [ stride * i + color_offset + 1 ] = p_colors [ i ] . g ;
buffer_data [ stride * i + color_offset + 2 ] = p_colors [ i ] . b ;
buffer_data [ stride * i + color_offset + 3 ] = p_colors [ i ] . a ;
}
}
if ( p_uvs ) {
for ( int i = 0 ; i < p_points ; i + + ) {
buffer_data [ stride * i + uv_offset + 0 ] = p_uvs [ i ] . x ;
buffer_data [ stride * i + uv_offset + 1 ] = p_uvs [ i ] . y ;
}
}
if ( p_light_angles ) {
for ( int i = 0 ; i < p_points ; i + + ) {
buffer_data [ stride * i + light_angle_offset + 0 ] = p_light_angles [ i ] ;
}
}
glBindBuffer ( GL_ARRAY_BUFFER , data . polygon_buffer ) ;
storage - > buffer_orphan_and_upload ( data . polygon_buffer_size , 0 , p_points * stride * sizeof ( float ) , buffer_data , GL_ARRAY_BUFFER , _buffer_upload_usage_flag , true ) ;
glVertexAttribPointer ( RS : : ARRAY_VERTEX , 2 , GL_FLOAT , GL_FALSE , stride * sizeof ( float ) , nullptr ) ;
if ( p_colors ) {
glVertexAttribPointer ( RS : : ARRAY_COLOR , 4 , GL_FLOAT , GL_FALSE , stride * sizeof ( float ) , CAST_INT_TO_UCHAR_PTR ( color_offset * sizeof ( float ) ) ) ;
glEnableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
}
if ( p_uvs ) {
glVertexAttribPointer ( RS : : ARRAY_TEX_UV , 2 , GL_FLOAT , GL_FALSE , stride * sizeof ( float ) , CAST_INT_TO_UCHAR_PTR ( uv_offset * sizeof ( float ) ) ) ;
glEnableVertexAttribArray ( RS : : ARRAY_TEX_UV ) ;
}
if ( p_light_angles ) {
glVertexAttribPointer ( RS : : ARRAY_TANGENT , 1 , GL_FLOAT , GL_FALSE , stride * sizeof ( float ) , CAST_INT_TO_UCHAR_PTR ( light_angle_offset * sizeof ( float ) ) ) ;
glEnableVertexAttribArray ( RS : : ARRAY_TANGENT ) ;
}
glDrawArrays ( prim [ p_points ] , 0 , p_points ) ;
storage - > info . render . _2d_draw_call_count + + ;
if ( p_light_angles ) {
// may not be needed
glDisableVertexAttribArray ( RS : : ARRAY_TANGENT ) ;
}
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
}
void RasterizerCanvasBaseGLES2 : : _copy_screen ( const Rect2 & p_rect ) {
if ( storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_DIRECT_TO_SCREEN ] ) {
ERR_PRINT_ONCE ( " Cannot use screen texture copying in render target set to render direct to screen. " ) ;
return ;
}
ERR_FAIL_COND_MSG ( storage - > frame . current_rt - > copy_screen_effect . color = = 0 , " Can't use screen texture copying in a render target configured without copy buffers. To resolve this, change the viewport's Usage property to \" 2D \" or \" 3D \" instead of \" 2D Without Sampling \" or \" 3D Without Effects \" respectively. " ) ;
glDisable ( GL_BLEND ) ;
Vector2 wh ( storage - > frame . current_rt - > width , storage - > frame . current_rt - > height ) ;
Color copy_section ( p_rect . position . x / wh . x , p_rect . position . y / wh . y , p_rect . size . x / wh . x , p_rect . size . y / wh . y ) ;
if ( p_rect ! = Rect2 ( ) ) {
storage - > shaders . copy . set_conditional ( CopyShaderGLES2 : : USE_COPY_SECTION , true ) ;
}
storage - > shaders . copy . set_conditional ( CopyShaderGLES2 : : USE_NO_ALPHA , ! state . using_transparent_rt ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , storage - > frame . current_rt - > copy_screen_effect . fbo ) ;
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > frame . current_rt - > color ) ;
storage - > shaders . copy . bind ( ) ;
storage - > shaders . copy . set_uniform ( CopyShaderGLES2 : : COPY_SECTION , copy_section ) ;
const Vector2 vertpos [ 4 ] = {
Vector2 ( - 1 , - 1 ) ,
Vector2 ( - 1 , 1 ) ,
Vector2 ( 1 , 1 ) ,
Vector2 ( 1 , - 1 ) ,
} ;
const Vector2 uvpos [ 4 ] = {
Vector2 ( 0 , 0 ) ,
Vector2 ( 0 , 1 ) ,
Vector2 ( 1 , 1 ) ,
Vector2 ( 1 , 0 )
} ;
const int indexpos [ 6 ] = {
0 , 1 , 2 ,
2 , 3 , 0
} ;
_draw_polygon ( indexpos , 6 , 4 , vertpos , uvpos , nullptr , false ) ;
storage - > shaders . copy . set_conditional ( CopyShaderGLES2 : : USE_COPY_SECTION , false ) ;
storage - > shaders . copy . set_conditional ( CopyShaderGLES2 : : USE_NO_ALPHA , false ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , storage - > frame . current_rt - > fbo ) ; //back to front
glEnable ( GL_BLEND ) ;
}
void RasterizerCanvasBaseGLES2 : : draw_lens_distortion_rect ( const Rect2 & p_rect , float p_k1 , float p_k2 , const Vector2 & p_eye_center , float p_oversample ) {
Vector2 half_size ;
if ( storage - > frame . current_rt ) {
half_size = Vector2 ( storage - > frame . current_rt - > width , storage - > frame . current_rt - > height ) ;
} else {
half_size = OS : : get_singleton ( ) - > get_window_size ( ) ;
}
half_size * = 0.5 ;
Vector2 offset ( ( p_rect . position . x - half_size . x ) / half_size . x , ( p_rect . position . y - half_size . y ) / half_size . y ) ;
Vector2 scale ( p_rect . size . x / half_size . x , p_rect . size . y / half_size . y ) ;
float aspect_ratio = p_rect . size . x / p_rect . size . y ;
// setup our lens shader
state . lens_shader . bind ( ) ;
state . lens_shader . set_uniform ( LensDistortedShaderGLES2 : : OFFSET , offset ) ;
state . lens_shader . set_uniform ( LensDistortedShaderGLES2 : : SCALE , scale ) ;
state . lens_shader . set_uniform ( LensDistortedShaderGLES2 : : K1 , p_k1 ) ;
state . lens_shader . set_uniform ( LensDistortedShaderGLES2 : : K2 , p_k2 ) ;
state . lens_shader . set_uniform ( LensDistortedShaderGLES2 : : EYE_CENTER , p_eye_center ) ;
state . lens_shader . set_uniform ( LensDistortedShaderGLES2 : : UPSCALE , p_oversample ) ;
state . lens_shader . set_uniform ( LensDistortedShaderGLES2 : : ASPECT_RATIO , aspect_ratio ) ;
// bind our quad buffer
_bind_quad_buffer ( ) ;
// and draw
glDrawArrays ( GL_TRIANGLE_FAN , 0 , 4 ) ;
// and cleanup
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
for ( int i = 0 ; i < RS : : ARRAY_MAX ; i + + ) {
glDisableVertexAttribArray ( i ) ;
}
}
void RasterizerCanvasBaseGLES2 : : initialize ( ) {
int flag_stream_mode = GLOBAL_GET ( " rendering/2d/opengl/legacy_stream " ) ;
switch ( flag_stream_mode ) {
default : {
_buffer_upload_usage_flag = GL_STREAM_DRAW ;
} break ;
case 1 : {
_buffer_upload_usage_flag = GL_DYNAMIC_DRAW ;
} break ;
case 2 : {
_buffer_upload_usage_flag = GL_STREAM_DRAW ;
} break ;
}
// quad buffer
{
glGenBuffers ( 1 , & data . canvas_quad_vertices ) ;
glBindBuffer ( GL_ARRAY_BUFFER , data . canvas_quad_vertices ) ;
const float qv [ 8 ] = {
0 , 0 ,
0 , 1 ,
1 , 1 ,
1 , 0
} ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 8 , qv , GL_STATIC_DRAW ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
}
// polygon buffer
{
uint32_t poly_size = GLOBAL_DEF ( " rendering/limits/buffers/canvas_polygon_buffer_size_kb " , 128 ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " rendering/limits/buffers/canvas_polygon_buffer_size_kb " , PropertyInfo ( Variant : : INT , " rendering/limits/buffers/canvas_polygon_buffer_size_kb " , PROPERTY_HINT_RANGE , " 0,256,1,or_greater " ) ) ;
poly_size = MAX ( poly_size , 2 ) ; // minimum 2k, may still see anomalies in editor
poly_size * = 1024 ;
glGenBuffers ( 1 , & data . polygon_buffer ) ;
glBindBuffer ( GL_ARRAY_BUFFER , data . polygon_buffer ) ;
glBufferData ( GL_ARRAY_BUFFER , poly_size , nullptr , GL_DYNAMIC_DRAW ) ;
data . polygon_buffer_size = poly_size ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
uint32_t index_size = GLOBAL_DEF ( " rendering/limits/buffers/canvas_polygon_index_buffer_size_kb " , 128 ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " rendering/limits/buffers/canvas_polygon_index_buffer_size_kb " , PropertyInfo ( Variant : : INT , " rendering/limits/buffers/canvas_polygon_index_buffer_size_kb " , PROPERTY_HINT_RANGE , " 0,256,1,or_greater " ) ) ;
index_size = MAX ( index_size , 2 ) ;
index_size * = 1024 ; // kb
glGenBuffers ( 1 , & data . polygon_index_buffer ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , data . polygon_index_buffer ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , index_size , nullptr , GL_DYNAMIC_DRAW ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
data . polygon_index_buffer_size = index_size ;
}
// ninepatch buffers
{
// array buffer
glGenBuffers ( 1 , & data . ninepatch_vertices ) ;
glBindBuffer ( GL_ARRAY_BUFFER , data . ninepatch_vertices ) ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * ( 16 + 16 ) * 2 , nullptr , GL_DYNAMIC_DRAW ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
// element buffer
glGenBuffers ( 1 , & data . ninepatch_elements ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , data . ninepatch_elements ) ;
# define _EIDX(y, x) (y * 4 + x)
uint8_t elems [ 3 * 2 * 9 ] = {
// first row
_EIDX ( 0 , 0 ) , _EIDX ( 0 , 1 ) , _EIDX ( 1 , 1 ) ,
_EIDX ( 1 , 1 ) , _EIDX ( 1 , 0 ) , _EIDX ( 0 , 0 ) ,
_EIDX ( 0 , 1 ) , _EIDX ( 0 , 2 ) , _EIDX ( 1 , 2 ) ,
_EIDX ( 1 , 2 ) , _EIDX ( 1 , 1 ) , _EIDX ( 0 , 1 ) ,
_EIDX ( 0 , 2 ) , _EIDX ( 0 , 3 ) , _EIDX ( 1 , 3 ) ,
_EIDX ( 1 , 3 ) , _EIDX ( 1 , 2 ) , _EIDX ( 0 , 2 ) ,
// second row
_EIDX ( 1 , 0 ) , _EIDX ( 1 , 1 ) , _EIDX ( 2 , 1 ) ,
_EIDX ( 2 , 1 ) , _EIDX ( 2 , 0 ) , _EIDX ( 1 , 0 ) ,
// the center one would be here, but we'll put it at the end
// so it's easier to disable the center and be able to use
// one draw call for both
_EIDX ( 1 , 2 ) , _EIDX ( 1 , 3 ) , _EIDX ( 2 , 3 ) ,
_EIDX ( 2 , 3 ) , _EIDX ( 2 , 2 ) , _EIDX ( 1 , 2 ) ,
// third row
_EIDX ( 2 , 0 ) , _EIDX ( 2 , 1 ) , _EIDX ( 3 , 1 ) ,
_EIDX ( 3 , 1 ) , _EIDX ( 3 , 0 ) , _EIDX ( 2 , 0 ) ,
_EIDX ( 2 , 1 ) , _EIDX ( 2 , 2 ) , _EIDX ( 3 , 2 ) ,
_EIDX ( 3 , 2 ) , _EIDX ( 3 , 1 ) , _EIDX ( 2 , 1 ) ,
_EIDX ( 2 , 2 ) , _EIDX ( 2 , 3 ) , _EIDX ( 3 , 3 ) ,
_EIDX ( 3 , 3 ) , _EIDX ( 3 , 2 ) , _EIDX ( 2 , 2 ) ,
// center field
_EIDX ( 1 , 1 ) , _EIDX ( 1 , 2 ) , _EIDX ( 2 , 2 ) ,
_EIDX ( 2 , 2 ) , _EIDX ( 2 , 1 ) , _EIDX ( 1 , 1 )
} ;
# undef _EIDX
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( elems ) , elems , GL_STATIC_DRAW ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
state . canvas_shader . init ( ) ;
state . using_modulate = false ;
_set_texture_rect_mode ( true ) ;
state . canvas_shader . bind ( ) ;
state . lens_shader . init ( ) ;
state . canvas_shader . set_conditional ( CanvasShaderGLES2 : : USE_PIXEL_SNAP , GLOBAL_DEF ( " rendering/2d/snapping/use_gpu_pixel_snap " , false ) ) ;
state . using_transparent_rt = false ;
}
void RasterizerCanvasBaseGLES2 : : finalize ( ) {
}
RasterizerCanvasBaseGLES2 : : RasterizerCanvasBaseGLES2 ( ) {
}