2019-06-12 02:43:37 +08:00
# include "rasterizer_canvas_rd.h"
2019-06-25 03:13:06 +08:00
# include "core/math/math_funcs.h"
2019-06-16 10:45:24 +08:00
void RasterizerCanvasRD : : _update_transform_2d_to_mat4 ( const Transform2D & p_transform , float * p_mat4 ) {
p_mat4 [ 0 ] = p_transform . elements [ 0 ] [ 0 ] ;
p_mat4 [ 1 ] = p_transform . elements [ 0 ] [ 1 ] ;
p_mat4 [ 2 ] = 0 ;
p_mat4 [ 3 ] = 0 ;
p_mat4 [ 4 ] = p_transform . elements [ 1 ] [ 0 ] ;
p_mat4 [ 5 ] = p_transform . elements [ 1 ] [ 1 ] ;
p_mat4 [ 6 ] = 0 ;
p_mat4 [ 7 ] = 0 ;
p_mat4 [ 8 ] = 0 ;
p_mat4 [ 9 ] = 0 ;
p_mat4 [ 10 ] = 1 ;
p_mat4 [ 11 ] = 0 ;
p_mat4 [ 12 ] = p_transform . elements [ 2 ] [ 0 ] ;
p_mat4 [ 13 ] = p_transform . elements [ 2 ] [ 1 ] ;
p_mat4 [ 14 ] = 0 ;
p_mat4 [ 15 ] = 1 ;
}
void RasterizerCanvasRD : : _update_transform_2d_to_mat2x4 ( const Transform2D & p_transform , float * p_mat2x4 ) {
p_mat2x4 [ 0 ] = p_transform . elements [ 0 ] [ 0 ] ;
p_mat2x4 [ 1 ] = p_transform . elements [ 1 ] [ 0 ] ;
p_mat2x4 [ 2 ] = 0 ;
p_mat2x4 [ 3 ] = p_transform . elements [ 2 ] [ 0 ] ;
p_mat2x4 [ 4 ] = p_transform . elements [ 0 ] [ 1 ] ;
p_mat2x4 [ 5 ] = p_transform . elements [ 1 ] [ 1 ] ;
p_mat2x4 [ 6 ] = 0 ;
p_mat2x4 [ 7 ] = p_transform . elements [ 2 ] [ 1 ] ;
}
2019-06-25 03:13:06 +08:00
void RasterizerCanvasRD : : _update_transform_2d_to_mat2x3 ( const Transform2D & p_transform , float * p_mat2x3 ) {
p_mat2x3 [ 0 ] = p_transform . elements [ 0 ] [ 0 ] ;
p_mat2x3 [ 1 ] = p_transform . elements [ 0 ] [ 1 ] ;
p_mat2x3 [ 2 ] = p_transform . elements [ 1 ] [ 0 ] ;
p_mat2x3 [ 3 ] = p_transform . elements [ 1 ] [ 1 ] ;
p_mat2x3 [ 4 ] = p_transform . elements [ 2 ] [ 0 ] ;
p_mat2x3 [ 5 ] = p_transform . elements [ 2 ] [ 1 ] ;
}
2019-06-16 10:45:24 +08:00
void RasterizerCanvasRD : : _update_transform_to_mat4 ( const Transform & p_transform , float * p_mat4 ) {
p_mat4 [ 0 ] = p_transform . basis . elements [ 0 ] [ 0 ] ;
p_mat4 [ 1 ] = p_transform . basis . elements [ 1 ] [ 0 ] ;
p_mat4 [ 2 ] = p_transform . basis . elements [ 2 ] [ 0 ] ;
p_mat4 [ 3 ] = 0 ;
p_mat4 [ 4 ] = p_transform . basis . elements [ 0 ] [ 1 ] ;
p_mat4 [ 5 ] = p_transform . basis . elements [ 1 ] [ 1 ] ;
p_mat4 [ 6 ] = p_transform . basis . elements [ 2 ] [ 1 ] ;
p_mat4 [ 7 ] = 0 ;
p_mat4 [ 8 ] = p_transform . basis . elements [ 0 ] [ 2 ] ;
p_mat4 [ 9 ] = p_transform . basis . elements [ 1 ] [ 2 ] ;
p_mat4 [ 10 ] = p_transform . basis . elements [ 2 ] [ 2 ] ;
p_mat4 [ 11 ] = 0 ;
p_mat4 [ 12 ] = p_transform . origin . x ;
p_mat4 [ 13 ] = p_transform . origin . y ;
p_mat4 [ 14 ] = p_transform . origin . z ;
p_mat4 [ 15 ] = 1 ;
}
2019-07-05 09:54:32 +08:00
void RasterizerCanvasRD : : _update_specular_shininess ( const Color & p_transform , uint32_t * r_ss ) {
* r_ss = uint32_t ( CLAMP ( p_transform . a * 255.0 , 0 , 255 ) ) < < 24 ;
* r_ss | = uint32_t ( CLAMP ( p_transform . b * 255.0 , 0 , 255 ) ) < < 16 ;
* r_ss | = uint32_t ( CLAMP ( p_transform . g * 255.0 , 0 , 255 ) ) < < 8 ;
* r_ss | = uint32_t ( CLAMP ( p_transform . r * 255.0 , 0 , 255 ) ) ;
}
2019-06-25 03:13:06 +08:00
RID RasterizerCanvasRD : : _create_texture_binding ( RID p_texture , RID p_normalmap , RID p_specular , VisualServer : : CanvasItemTextureFilter p_filter , VisualServer : : CanvasItemTextureRepeat p_repeat , RID p_multimesh ) {
Vector < RD : : Uniform > uniform_set ;
{ // COLOR TEXTURE
RD : : Uniform u ;
u . type = RD : : UNIFORM_TYPE_TEXTURE ;
u . binding = 1 ;
RID texture = storage - > texture_get_rd_texture ( p_texture ) ;
if ( ! texture . is_valid ( ) ) {
//use default white texture
texture = default_textures . white_texture ;
}
u . ids . push_back ( texture ) ;
uniform_set . push_back ( u ) ;
}
{ // NORMAL TEXTURE
RD : : Uniform u ;
u . type = RD : : UNIFORM_TYPE_TEXTURE ;
u . binding = 2 ;
RID texture = storage - > texture_get_rd_texture ( p_normalmap ) ;
if ( ! texture . is_valid ( ) ) {
//use default normal texture
texture = default_textures . normal_texture ;
}
u . ids . push_back ( texture ) ;
uniform_set . push_back ( u ) ;
}
{ // SPECULAR TEXTURE
RD : : Uniform u ;
u . type = RD : : UNIFORM_TYPE_TEXTURE ;
u . binding = 3 ;
RID texture = storage - > texture_get_rd_texture ( p_specular ) ;
if ( ! texture . is_valid ( ) ) {
//use default white texture
texture = default_textures . white_texture ;
}
u . ids . push_back ( texture ) ;
uniform_set . push_back ( u ) ;
}
{ // SAMPLER
RD : : Uniform u ;
u . type = RD : : UNIFORM_TYPE_SAMPLER ;
u . binding = 4 ;
RID sampler = default_samplers . samplers [ p_filter ] [ p_repeat ] ;
ERR_FAIL_COND_V ( sampler . is_null ( ) , RID ( ) ) ;
u . ids . push_back ( sampler ) ;
uniform_set . push_back ( u ) ;
}
{ // MULTIMESH TEXTURE BUFFER
RD : : Uniform u ;
u . type = RD : : UNIFORM_TYPE_TEXTURE_BUFFER ;
u . binding = 5 ;
u . ids . push_back ( default_textures . default_multimesh_tb ) ;
uniform_set . push_back ( u ) ;
}
return RD : : get_singleton ( ) - > uniform_set_create ( uniform_set , shader . default_version_rd_shader , 0 ) ;
}
2019-06-16 10:45:24 +08:00
RasterizerCanvas : : TextureBindingID RasterizerCanvasRD : : request_texture_binding ( RID p_texture , RID p_normalmap , RID p_specular , VisualServer : : CanvasItemTextureFilter p_filter , VisualServer : : CanvasItemTextureRepeat p_repeat , RID p_multimesh ) {
if ( p_filter = = VS : : CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ) {
p_filter = default_samplers . default_filter ;
}
if ( p_repeat = = VS : : CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ) {
p_repeat = default_samplers . default_repeat ;
}
TextureBindingKey key ;
key . texture = p_texture ;
key . normalmap = p_normalmap ;
key . specular = p_specular ;
key . multimesh = p_multimesh ;
key . texture_filter = p_filter ;
key . texture_repeat = p_repeat ;
TextureBinding * binding ;
TextureBindingID id ;
{
TextureBindingID * idptr = bindings . texture_key_bindings . getptr ( key ) ;
if ( ! idptr ) {
id = bindings . id_generator + + ;
bindings . texture_key_bindings [ key ] = id ;
binding = memnew ( TextureBinding ) ;
binding - > key = key ;
binding - > id = id ;
bindings . texture_bindings [ id ] = binding ;
} else {
id = * idptr ;
binding = bindings . texture_bindings [ id ] ;
}
}
binding - > reference_count + + ;
if ( binding - > to_dispose . in_list ( ) ) {
//was queued for disposal previously, but ended up reused.
bindings . to_dispose_list . remove ( & binding - > to_dispose ) ;
}
if ( binding - > uniform_set . is_null ( ) | | ! RD : : get_singleton ( ) - > uniform_set_is_valid ( binding - > uniform_set ) ) {
2019-06-25 03:13:06 +08:00
binding - > uniform_set = _create_texture_binding ( p_texture , p_normalmap , p_specular , p_filter , p_repeat , p_multimesh ) ;
2019-06-16 10:45:24 +08:00
}
return id ;
}
void RasterizerCanvasRD : : free_texture_binding ( TextureBindingID p_binding ) {
TextureBinding * * binding_ptr = bindings . texture_bindings . getptr ( p_binding ) ;
ERR_FAIL_COND ( ! binding_ptr ) ;
TextureBinding * binding = * binding_ptr ;
ERR_FAIL_COND ( binding - > reference_count = = 0 ) ;
binding - > reference_count - - ;
if ( binding - > reference_count = = 0 ) {
bindings . to_dispose_list . add ( & binding - > to_dispose ) ;
}
}
void RasterizerCanvasRD : : _dispose_bindings ( ) {
while ( bindings . to_dispose_list . first ( ) ) {
TextureBinding * binding = bindings . to_dispose_list . first ( ) - > self ( ) ;
2019-06-25 03:13:06 +08:00
if ( binding - > uniform_set . is_valid ( ) & & RD : : get_singleton ( ) - > uniform_set_is_valid ( binding - > uniform_set ) ) {
2019-06-16 10:45:24 +08:00
RD : : get_singleton ( ) - > free ( binding - > uniform_set ) ;
}
bindings . texture_key_bindings . erase ( binding - > key ) ;
bindings . texture_bindings . erase ( binding - > id ) ;
bindings . to_dispose_list . remove ( & binding - > to_dispose ) ;
memdelete ( binding ) ;
}
}
2019-06-25 03:13:06 +08:00
RasterizerCanvas : : PolygonID RasterizerCanvasRD : : request_polygon ( const Vector < int > & p_indices , const Vector < Point2 > & p_points , const Vector < Color > & p_colors , const Vector < Point2 > & p_uvs , const Vector < int > & p_bones , const Vector < float > & p_weights ) {
// Care must be taken to generate array formats
// in ways where they could be reused, so we will
// put single-occuring elements first, and repeated
// elements later. This way the generated formats are
// the same no matter the length of the arrays.
// This dramatically reduces the amount of pipeline objects
// that need to be created for these formats.
uint32_t vertex_count = p_points . size ( ) ;
uint32_t base_offset = 0 ;
uint32_t stride = 2 ; //vertices always repeat
if ( ( uint32_t ) p_colors . size ( ) = = vertex_count ) {
stride + = 4 ;
} else {
base_offset + = 4 ;
}
if ( ( uint32_t ) p_uvs . size ( ) = = vertex_count ) {
stride + = 2 ;
} else {
base_offset + = 2 ;
}
if ( ( uint32_t ) p_bones . size ( ) = = vertex_count * 4 ) {
stride + = 4 ;
} else {
base_offset + = 4 ;
}
if ( ( uint32_t ) p_weights . size ( ) = = vertex_count * 4 ) {
stride + = 4 ;
} else {
base_offset + = 4 ;
}
uint32_t buffer_size = base_offset + stride * p_points . size ( ) ;
PoolVector < uint8_t > polygon_buffer ;
polygon_buffer . resize ( buffer_size * sizeof ( float ) ) ;
Vector < RD : : VertexDescription > descriptions ;
descriptions . resize ( 5 ) ;
{
PoolVector < uint8_t > : : Read r = polygon_buffer . read ( ) ;
float * fptr = ( float * ) r . ptr ( ) ;
uint32_t * uptr = ( uint32_t * ) r . ptr ( ) ;
uint32_t single_offset = 0 ;
{ //vertices
RD : : VertexDescription vd ;
vd . format = RD : : DATA_FORMAT_R32G32_SFLOAT ;
vd . offset = base_offset * sizeof ( float ) ;
vd . location = VS : : ARRAY_VERTEX ;
vd . stride = stride * sizeof ( float ) ;
descriptions . write [ 0 ] = vd ;
const Vector2 * points_ptr = p_points . ptr ( ) ;
for ( uint32_t i = 0 ; i < vertex_count ; i + + ) {
fptr [ base_offset + i * stride + 0 ] = points_ptr [ i ] . x ;
fptr [ base_offset + i * stride + 1 ] = points_ptr [ i ] . y ;
}
base_offset + = 2 ;
}
//colors
if ( ( uint32_t ) p_colors . size ( ) = = vertex_count ) {
RD : : VertexDescription vd ;
vd . format = RD : : DATA_FORMAT_R32G32B32A32_SFLOAT ;
vd . offset = base_offset * sizeof ( float ) ;
vd . location = VS : : ARRAY_COLOR ;
vd . stride = stride * sizeof ( float ) ;
descriptions . write [ 1 ] = vd ;
const Color * color_ptr = p_colors . ptr ( ) ;
for ( uint32_t i = 0 ; i < vertex_count ; i + + ) {
fptr [ base_offset + i * stride + 0 ] = color_ptr [ i ] . r ;
fptr [ base_offset + i * stride + 1 ] = color_ptr [ i ] . g ;
fptr [ base_offset + i * stride + 2 ] = color_ptr [ i ] . b ;
fptr [ base_offset + i * stride + 3 ] = color_ptr [ i ] . a ;
}
base_offset + = 4 ;
} else {
RD : : VertexDescription vd ;
vd . format = RD : : DATA_FORMAT_R32G32B32A32_SFLOAT ;
vd . offset = single_offset * sizeof ( float ) ;
vd . location = VS : : ARRAY_COLOR ;
vd . stride = 0 ;
descriptions . write [ 1 ] = vd ;
Color color = p_colors . size ( ) ? p_colors [ 0 ] : Color ( 1 , 1 , 1 , 1 ) ;
fptr [ single_offset + 0 ] = color . r ;
fptr [ single_offset + 1 ] = color . g ;
fptr [ single_offset + 2 ] = color . b ;
fptr [ single_offset + 3 ] = color . a ;
single_offset + = 4 ;
}
//uvs
if ( ( uint32_t ) p_uvs . size ( ) = = vertex_count ) {
RD : : VertexDescription vd ;
vd . format = RD : : DATA_FORMAT_R32G32_SFLOAT ;
vd . offset = base_offset * sizeof ( float ) ;
vd . location = VS : : ARRAY_TEX_UV ;
vd . stride = stride * sizeof ( float ) ;
descriptions . write [ 2 ] = vd ;
const Vector2 * uv_ptr = p_uvs . ptr ( ) ;
for ( uint32_t i = 0 ; i < vertex_count ; i + + ) {
fptr [ base_offset + i * stride + 0 ] = uv_ptr [ i ] . x ;
fptr [ base_offset + i * stride + 1 ] = uv_ptr [ i ] . y ;
}
base_offset + = 2 ;
} else {
RD : : VertexDescription vd ;
vd . format = RD : : DATA_FORMAT_R32G32_SFLOAT ;
vd . offset = single_offset * sizeof ( float ) ;
vd . location = VS : : ARRAY_TEX_UV ;
vd . stride = 0 ;
descriptions . write [ 2 ] = vd ;
Vector2 uv ;
fptr [ single_offset + 0 ] = uv . x ;
fptr [ single_offset + 1 ] = uv . y ;
single_offset + = 2 ;
}
//bones
if ( ( uint32_t ) p_indices . size ( ) = = vertex_count * 4 ) {
RD : : VertexDescription vd ;
vd . format = RD : : DATA_FORMAT_R32G32B32A32_UINT ;
vd . offset = base_offset * sizeof ( float ) ;
vd . location = VS : : ARRAY_BONES ;
vd . stride = stride * sizeof ( float ) ;
descriptions . write [ 3 ] = vd ;
const int * bone_ptr = p_bones . ptr ( ) ;
for ( uint32_t i = 0 ; i < vertex_count ; i + + ) {
uptr [ base_offset + i * stride + 0 ] = bone_ptr [ i * 4 + 0 ] ;
uptr [ base_offset + i * stride + 1 ] = bone_ptr [ i * 4 + 1 ] ;
uptr [ base_offset + i * stride + 2 ] = bone_ptr [ i * 4 + 2 ] ;
uptr [ base_offset + i * stride + 3 ] = bone_ptr [ i * 4 + 3 ] ;
}
base_offset + = 4 ;
} else {
RD : : VertexDescription vd ;
vd . format = RD : : DATA_FORMAT_R32G32B32A32_UINT ;
vd . offset = single_offset * sizeof ( float ) ;
vd . location = VS : : ARRAY_BONES ;
vd . stride = 0 ;
descriptions . write [ 3 ] = vd ;
uptr [ single_offset + 0 ] = 0 ;
uptr [ single_offset + 1 ] = 0 ;
uptr [ single_offset + 2 ] = 0 ;
uptr [ single_offset + 3 ] = 0 ;
single_offset + = 4 ;
}
//bones
if ( ( uint32_t ) p_weights . size ( ) = = vertex_count * 4 ) {
RD : : VertexDescription vd ;
vd . format = RD : : DATA_FORMAT_R32G32B32A32_SFLOAT ;
vd . offset = base_offset * sizeof ( float ) ;
vd . location = VS : : ARRAY_WEIGHTS ;
vd . stride = stride * sizeof ( float ) ;
descriptions . write [ 4 ] = vd ;
const float * weight_ptr = p_weights . ptr ( ) ;
for ( uint32_t i = 0 ; i < vertex_count ; i + + ) {
fptr [ base_offset + i * stride + 0 ] = weight_ptr [ i * 4 + 0 ] ;
fptr [ base_offset + i * stride + 1 ] = weight_ptr [ i * 4 + 1 ] ;
fptr [ base_offset + i * stride + 2 ] = weight_ptr [ i * 4 + 2 ] ;
fptr [ base_offset + i * stride + 3 ] = weight_ptr [ i * 4 + 3 ] ;
}
base_offset + = 4 ;
} else {
RD : : VertexDescription vd ;
vd . format = RD : : DATA_FORMAT_R32G32B32A32_SFLOAT ;
vd . offset = single_offset * sizeof ( float ) ;
vd . location = VS : : ARRAY_WEIGHTS ;
vd . stride = 0 ;
descriptions . write [ 4 ] = vd ;
fptr [ single_offset + 0 ] = 0.0 ;
fptr [ single_offset + 1 ] = 0.0 ;
fptr [ single_offset + 2 ] = 0.0 ;
fptr [ single_offset + 3 ] = 0.0 ;
single_offset + = 4 ;
}
//check that everything is as it should be
ERR_FAIL_COND_V ( single_offset ! = ( base_offset - stride ) , 0 ) ;
ERR_FAIL_COND_V ( ( ( base_offset - stride ) + stride * vertex_count ) ! = buffer_size , 0 ) ;
}
RD : : VertexFormatID vertex_id = RD : : get_singleton ( ) - > vertex_format_create ( descriptions ) ;
ERR_FAIL_COND_V ( vertex_id = = RD : : INVALID_ID , 0 ) ;
PolygonBuffers pb ;
pb . vertex_buffer = RD : : get_singleton ( ) - > vertex_buffer_create ( polygon_buffer . size ( ) , polygon_buffer ) ;
Vector < RID > buffers ;
buffers . resize ( descriptions . size ( ) ) ;
for ( int i = 0 ; i < descriptions . size ( ) ; i + + ) {
buffers . write [ i ] = pb . vertex_buffer ;
}
pb . vertex_array = RD : : get_singleton ( ) - > vertex_array_create ( p_points . size ( ) , vertex_id , buffers ) ;
if ( p_indices . size ( ) ) {
//create indices, as indices were requested
PoolVector < uint8_t > index_buffer ;
index_buffer . resize ( p_indices . size ( ) * sizeof ( int32_t ) ) ;
{
PoolVector < uint8_t > : : Write w = index_buffer . write ( ) ;
copymem ( w . ptr ( ) , p_indices . ptr ( ) , sizeof ( int32_t ) * p_indices . size ( ) ) ;
}
pb . index_buffer = RD : : get_singleton ( ) - > index_buffer_create ( p_indices . size ( ) , RD : : INDEX_BUFFER_FORMAT_UINT32 , index_buffer ) ;
pb . indices = RD : : get_singleton ( ) - > index_array_create ( pb . index_buffer , 0 , p_indices . size ( ) ) ;
}
pb . vertex_format_id = vertex_id ;
PolygonID id = polygon_buffers . last_id + + ;
polygon_buffers . polygons [ id ] = pb ;
return id ;
}
void RasterizerCanvasRD : : free_polygon ( PolygonID p_polygon ) {
PolygonBuffers * pb_ptr = polygon_buffers . polygons . getptr ( p_polygon ) ;
ERR_FAIL_COND ( ! pb_ptr ) ;
PolygonBuffers & pb = * pb_ptr ;
if ( pb . indices . is_valid ( ) ) {
RD : : get_singleton ( ) - > free ( pb . indices ) ;
}
if ( pb . index_buffer . is_valid ( ) ) {
RD : : get_singleton ( ) - > free ( pb . index_buffer ) ;
}
RD : : get_singleton ( ) - > free ( pb . vertex_array ) ;
RD : : get_singleton ( ) - > free ( pb . vertex_buffer ) ;
polygon_buffers . polygons . erase ( p_polygon ) ;
}
2019-07-05 09:54:32 +08:00
Size2i RasterizerCanvasRD : : _bind_texture_binding ( TextureBindingID p_binding , RD : : DrawListID p_draw_list , uint32_t & flags ) {
2019-06-25 03:13:06 +08:00
TextureBinding * * texture_binding_ptr = bindings . texture_bindings . getptr ( p_binding ) ;
ERR_FAIL_COND_V ( ! texture_binding_ptr , Size2i ( ) ) ;
TextureBinding * texture_binding = * texture_binding_ptr ;
2019-07-05 09:54:32 +08:00
if ( texture_binding - > key . normalmap . is_valid ( ) ) {
flags | = FLAGS_DEFAULT_NORMAL_MAP_USED ;
}
if ( texture_binding - > key . specular . is_valid ( ) ) {
flags | = FLAGS_DEFAULT_SPECULAR_MAP_USED ;
}
2019-06-25 03:13:06 +08:00
if ( ! RD : : get_singleton ( ) - > uniform_set_is_valid ( texture_binding - > uniform_set ) ) {
//texture may have changed (erased or replaced, see if we can fix)
texture_binding - > uniform_set = _create_texture_binding ( texture_binding - > key . texture , texture_binding - > key . normalmap , texture_binding - > key . specular , texture_binding - > key . texture_filter , texture_binding - > key . texture_repeat , texture_binding - > key . multimesh ) ;
ERR_FAIL_COND_V ( ! texture_binding - > uniform_set . is_valid ( ) , Size2i ( 1 , 1 ) ) ;
}
RD : : get_singleton ( ) - > draw_list_bind_uniform_set ( p_draw_list , texture_binding - > uniform_set , 0 ) ;
if ( texture_binding - > key . texture . is_valid ( ) ) {
return storage - > texture_2d_get_size ( texture_binding - > key . texture ) ;
} else {
return Size2i ( 1 , 1 ) ;
}
}
////////////////////
2019-07-05 09:54:32 +08:00
void RasterizerCanvasRD : : _render_item ( RD : : DrawListID p_draw_list , const Item * p_item , RenderTargetFormat p_render_target_format , RD : : TextureSamples p_samples , const Transform2D & p_canvas_transform_inverse , Item * & current_clip , Light * p_lights ) {
2019-06-16 10:45:24 +08:00
//create an empty push constant
PushConstant push_constant ;
2019-06-25 03:13:06 +08:00
Transform2D base_transform = p_canvas_transform_inverse * p_item - > final_transform ;
_update_transform_2d_to_mat2x3 ( base_transform , push_constant . world ) ;
2019-07-05 09:54:32 +08:00
Color base_color = p_item - > final_modulate ;
2019-06-16 10:45:24 +08:00
for ( int i = 0 ; i < 4 ; i + + ) {
push_constant . modulation [ i ] = 0 ;
push_constant . ninepatch_margins [ i ] = 0 ;
push_constant . src_rect [ i ] = 0 ;
push_constant . dst_rect [ i ] = 0 ;
}
push_constant . flags = 0 ;
push_constant . color_texture_pixel_size [ 0 ] = 0 ;
push_constant . color_texture_pixel_size [ 1 ] = 0 ;
2019-06-27 02:11:52 +08:00
2019-06-16 10:45:24 +08:00
push_constant . pad [ 1 ] = 0 ;
push_constant . pad [ 2 ] = 0 ;
2019-06-27 02:11:52 +08:00
push_constant . pad [ 3 ] = 0 ;
2019-06-16 10:45:24 +08:00
2019-07-05 09:54:32 +08:00
push_constant . lights [ 0 ] = 0 ;
push_constant . lights [ 1 ] = 0 ;
push_constant . lights [ 2 ] = 0 ;
push_constant . lights [ 3 ] = 0 ;
uint32_t base_flags = 0 ;
{
Light * light = p_lights ;
uint16_t light_count = 0 ;
while ( light ) {
if ( light - > render_index_cache > = 0 & & p_item - > light_mask & light - > item_mask & & p_item - > z_final > = light - > z_min & & p_item - > z_final < = light - > z_max & & p_item - > global_rect_cache . intersects_transformed ( light - > xform_cache , light - > rect_cache ) ) {
uint32_t light_index = light - > render_index_cache ;
push_constant . lights [ light_count > > 2 ] | = light_index < < ( ( light_count & 3 ) * 8 ) ;
light_count + + ;
if ( light - > mode = = VS : : CANVAS_LIGHT_MODE_MASK ) {
base_flags | = FLAGS_USING_LIGHT_MASK ;
}
if ( light_count = = MAX_LIGHTS_PER_ITEM ) {
break ;
}
}
light = light - > next_ptr ;
}
base_flags | = light_count < < FLAGS_LIGHT_COUNT_SHIFT ;
}
2019-06-16 10:45:24 +08:00
PipelineVariants * pipeline_variants = & shader . pipeline_variants ;
2019-06-25 03:13:06 +08:00
bool reclip = false ;
2019-06-27 06:48:05 +08:00
const Item : : Command * c = p_item - > commands ;
while ( c ) {
2019-06-16 10:45:24 +08:00
2019-07-05 09:54:32 +08:00
push_constant . flags = base_flags ; //reset on each command for sanity
push_constant . specular_shininess = 0xFFFFFFFF ;
2019-06-16 10:45:24 +08:00
switch ( c - > type ) {
case Item : : Command : : TYPE_RECT : {
const Item : : CommandRect * rect = static_cast < const Item : : CommandRect * > ( c ) ;
//bind pipeline
{
2019-06-20 04:03:19 +08:00
RID pipeline = pipeline_variants - > variants [ p_render_target_format ] [ PIPELINE_VARIANT_QUAD ] . get_render_pipeline ( RD : : INVALID_ID , p_samples ) ;
2019-06-16 10:45:24 +08:00
RD : : get_singleton ( ) - > draw_list_bind_render_pipeline ( p_draw_list , pipeline ) ;
}
//bind textures
Size2 texpixel_size ;
{
2019-07-05 09:54:32 +08:00
texpixel_size = _bind_texture_binding ( rect - > texture_binding . binding_id , p_draw_list , push_constant . flags ) ;
2019-06-25 03:13:06 +08:00
texpixel_size . x = 1.0 / texpixel_size . x ;
texpixel_size . y = 1.0 / texpixel_size . y ;
2019-06-16 10:45:24 +08:00
}
2019-07-05 09:54:32 +08:00
if ( rect - > specular_shininess . a < 0.999 ) {
push_constant . flags | = FLAGS_DEFAULT_SPECULAR_MAP_USED ;
}
_update_specular_shininess ( rect - > specular_shininess , & push_constant . specular_shininess ) ;
2019-06-16 10:45:24 +08:00
Rect2 src_rect ;
Rect2 dst_rect ;
if ( texpixel_size ! = Vector2 ( ) ) {
push_constant . color_texture_pixel_size [ 0 ] = texpixel_size . x ;
push_constant . color_texture_pixel_size [ 1 ] = texpixel_size . y ;
src_rect = ( rect - > flags & CANVAS_RECT_REGION ) ? Rect2 ( rect - > source . position * texpixel_size , rect - > source . size * texpixel_size ) : Rect2 ( 0 , 0 , 1 , 1 ) ;
dst_rect = Rect2 ( rect - > rect . position , rect - > rect . size ) ;
if ( dst_rect . size . width < 0 ) {
dst_rect . position . x + = dst_rect . size . width ;
dst_rect . size . width * = - 1 ;
}
if ( dst_rect . size . height < 0 ) {
dst_rect . position . y + = dst_rect . size . height ;
dst_rect . size . height * = - 1 ;
}
if ( rect - > flags & CANVAS_RECT_FLIP_H ) {
src_rect . size . x * = - 1 ;
}
if ( rect - > flags & CANVAS_RECT_FLIP_V ) {
src_rect . size . y * = - 1 ;
}
if ( rect - > flags & CANVAS_RECT_TRANSPOSE ) {
dst_rect . size . x * = - 1 ; // Encoding in the dst_rect.z uniform
}
if ( rect - > flags & CANVAS_RECT_CLIP_UV ) {
push_constant . flags | = FLAGS_CLIP_RECT_UV ;
}
} else {
dst_rect = Rect2 ( rect - > rect . position , rect - > rect . size ) ;
if ( dst_rect . size . width < 0 ) {
dst_rect . position . x + = dst_rect . size . width ;
dst_rect . size . width * = - 1 ;
}
if ( dst_rect . size . height < 0 ) {
dst_rect . position . y + = dst_rect . size . height ;
dst_rect . size . height * = - 1 ;
}
src_rect = Rect2 ( 0 , 0 , 1 , 1 ) ;
texpixel_size = Vector2 ( 1 , 1 ) ;
}
2019-07-05 09:54:32 +08:00
push_constant . modulation [ 0 ] = rect - > modulate . r * base_color . r ;
push_constant . modulation [ 1 ] = rect - > modulate . g * base_color . g ;
push_constant . modulation [ 2 ] = rect - > modulate . b * base_color . b ;
push_constant . modulation [ 3 ] = rect - > modulate . a * base_color . a ;
2019-06-16 10:45:24 +08:00
push_constant . src_rect [ 0 ] = src_rect . position . x ;
push_constant . src_rect [ 1 ] = src_rect . position . y ;
push_constant . src_rect [ 2 ] = src_rect . size . width ;
push_constant . src_rect [ 3 ] = src_rect . size . height ;
push_constant . dst_rect [ 0 ] = dst_rect . position . x ;
push_constant . dst_rect [ 1 ] = dst_rect . position . y ;
push_constant . dst_rect [ 2 ] = dst_rect . size . width ;
push_constant . dst_rect [ 3 ] = dst_rect . size . height ;
push_constant . color_texture_pixel_size [ 0 ] = texpixel_size . x ;
push_constant . color_texture_pixel_size [ 1 ] = texpixel_size . y ;
RD : : get_singleton ( ) - > draw_list_set_push_constant ( p_draw_list , & push_constant , sizeof ( PushConstant ) ) ;
RD : : get_singleton ( ) - > draw_list_bind_index_array ( p_draw_list , shader . quad_index_array ) ;
RD : : get_singleton ( ) - > draw_list_draw ( p_draw_list , true ) ;
} break ;
case Item : : Command : : TYPE_NINEPATCH : {
const Item : : CommandNinePatch * np = static_cast < const Item : : CommandNinePatch * > ( c ) ;
//bind pipeline
{
2019-06-20 04:03:19 +08:00
RID pipeline = pipeline_variants - > variants [ p_render_target_format ] [ PIPELINE_VARIANT_NINEPATCH ] . get_render_pipeline ( RD : : INVALID_ID , p_samples ) ;
2019-06-16 10:45:24 +08:00
RD : : get_singleton ( ) - > draw_list_bind_render_pipeline ( p_draw_list , pipeline ) ;
}
//bind textures
Size2 texpixel_size ;
{
2019-07-05 09:54:32 +08:00
texpixel_size = _bind_texture_binding ( np - > texture_binding . binding_id , p_draw_list , push_constant . flags ) ;
2019-06-25 03:13:06 +08:00
texpixel_size . x = 1.0 / texpixel_size . x ;
texpixel_size . y = 1.0 / texpixel_size . y ;
2019-06-16 10:45:24 +08:00
}
2019-07-05 09:54:32 +08:00
if ( np - > specular_shininess . a < 0.999 ) {
push_constant . flags | = FLAGS_DEFAULT_SPECULAR_MAP_USED ;
}
_update_specular_shininess ( np - > specular_shininess , & push_constant . specular_shininess ) ;
2019-06-16 10:45:24 +08:00
Rect2 src_rect ;
Rect2 dst_rect ( np - > rect . position . x , np - > rect . position . y , np - > rect . size . x , np - > rect . size . y ) ;
if ( texpixel_size = = Size2 ( ) ) {
texpixel_size = Size2 ( 1 , 1 ) ;
src_rect = Rect2 ( 0 , 0 , 1 , 1 ) ;
} else {
if ( np - > source ! = Rect2 ( ) ) {
src_rect = Rect2 ( np - > source . position . x * texpixel_size . width , np - > source . position . y * texpixel_size . height , np - > source . size . x * texpixel_size . width , np - > source . size . y * texpixel_size . height ) ;
texpixel_size = Size2 ( 1.0 / np - > source . size . width , 1.0 / np - > source . size . height ) ;
} else {
src_rect = Rect2 ( 0 , 0 , 1 , 1 ) ;
}
}
2019-07-05 09:54:32 +08:00
push_constant . modulation [ 0 ] = np - > color . r * base_color . r ;
push_constant . modulation [ 1 ] = np - > color . g * base_color . g ;
push_constant . modulation [ 2 ] = np - > color . b * base_color . b ;
push_constant . modulation [ 3 ] = np - > color . a * base_color . a ;
2019-06-16 10:45:24 +08:00
push_constant . src_rect [ 0 ] = src_rect . position . x ;
push_constant . src_rect [ 1 ] = src_rect . position . y ;
push_constant . src_rect [ 2 ] = src_rect . size . width ;
push_constant . src_rect [ 3 ] = src_rect . size . height ;
push_constant . dst_rect [ 0 ] = dst_rect . position . x ;
push_constant . dst_rect [ 1 ] = dst_rect . position . y ;
push_constant . dst_rect [ 2 ] = dst_rect . size . width ;
push_constant . dst_rect [ 3 ] = dst_rect . size . height ;
push_constant . color_texture_pixel_size [ 0 ] = texpixel_size . x ;
push_constant . color_texture_pixel_size [ 1 ] = texpixel_size . y ;
2019-06-20 04:03:19 +08:00
push_constant . flags | = int ( np - > axis_x ) < < FLAGS_NINEPATCH_H_MODE_SHIFT ;
push_constant . flags | = int ( np - > axis_y ) < < FLAGS_NINEPATCH_V_MODE_SHIFT ;
2019-06-16 10:45:24 +08:00
if ( np - > draw_center ) {
push_constant . flags | = FLAGS_NINEPACH_DRAW_CENTER ;
}
push_constant . ninepatch_margins [ 0 ] = np - > margin [ MARGIN_LEFT ] ;
push_constant . ninepatch_margins [ 1 ] = np - > margin [ MARGIN_TOP ] ;
push_constant . ninepatch_margins [ 2 ] = np - > margin [ MARGIN_RIGHT ] ;
push_constant . ninepatch_margins [ 3 ] = np - > margin [ MARGIN_BOTTOM ] ;
RD : : get_singleton ( ) - > draw_list_set_push_constant ( p_draw_list , & push_constant , sizeof ( PushConstant ) ) ;
RD : : get_singleton ( ) - > draw_list_bind_index_array ( p_draw_list , shader . quad_index_array ) ;
RD : : get_singleton ( ) - > draw_list_draw ( p_draw_list , true ) ;
} break ;
2019-06-25 03:13:06 +08:00
case Item : : Command : : TYPE_POLYGON : {
2019-06-16 10:45:24 +08:00
2019-06-25 03:13:06 +08:00
const Item : : CommandPolygon * polygon = static_cast < const Item : : CommandPolygon * > ( c ) ;
PolygonBuffers * pb = polygon_buffers . polygons . getptr ( polygon - > polygon . polygon_id ) ;
ERR_CONTINUE ( ! pb ) ;
//bind pipeline
{
static const PipelineVariant variant [ VS : : PRIMITIVE_MAX ] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS , PIPELINE_VARIANT_ATTRIBUTE_LINES , PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES } ;
ERR_CONTINUE ( polygon - > primitive < 0 | | polygon - > primitive > = VS : : PRIMITIVE_MAX ) ;
RID pipeline = pipeline_variants - > variants [ p_render_target_format ] [ variant [ polygon - > primitive ] ] . get_render_pipeline ( pb - > vertex_format_id , p_samples ) ;
RD : : get_singleton ( ) - > draw_list_bind_render_pipeline ( p_draw_list , pipeline ) ;
}
2019-06-16 10:45:24 +08:00
2019-06-25 03:13:06 +08:00
if ( polygon - > primitive = = VS : : PRIMITIVE_LINES ) {
//not supported in most hardware, so pointless
//RD::get_singleton()->draw_list_set_line_width(p_draw_list, polygon->line_width);
}
2019-06-16 10:45:24 +08:00
2019-06-25 03:13:06 +08:00
//bind textures
2019-06-16 10:45:24 +08:00
2019-06-25 03:13:06 +08:00
Size2 texpixel_size ;
{
2019-07-05 09:54:32 +08:00
texpixel_size = _bind_texture_binding ( polygon - > texture_binding . binding_id , p_draw_list , push_constant . flags ) ;
2019-06-25 03:13:06 +08:00
texpixel_size . x = 1.0 / texpixel_size . x ;
texpixel_size . y = 1.0 / texpixel_size . y ;
2019-06-16 10:45:24 +08:00
}
2019-07-05 09:54:32 +08:00
if ( polygon - > specular_shininess . a < 0.999 ) {
push_constant . flags | = FLAGS_DEFAULT_SPECULAR_MAP_USED ;
}
_update_specular_shininess ( polygon - > specular_shininess , & push_constant . specular_shininess ) ;
push_constant . modulation [ 0 ] = base_color . r ;
push_constant . modulation [ 1 ] = base_color . g ;
push_constant . modulation [ 2 ] = base_color . b ;
push_constant . modulation [ 3 ] = base_color . a ;
2019-06-16 10:45:24 +08:00
2019-06-25 03:13:06 +08:00
for ( int j = 0 ; j < 4 ; j + + ) {
push_constant . src_rect [ j ] = 0 ;
push_constant . dst_rect [ j ] = 0 ;
push_constant . ninepatch_margins [ j ] = 0 ;
2019-06-16 10:45:24 +08:00
}
2019-06-25 03:13:06 +08:00
push_constant . color_texture_pixel_size [ 0 ] = texpixel_size . x ;
push_constant . color_texture_pixel_size [ 1 ] = texpixel_size . y ;
RD : : get_singleton ( ) - > draw_list_set_push_constant ( p_draw_list , & push_constant , sizeof ( PushConstant ) ) ;
RD : : get_singleton ( ) - > draw_list_bind_vertex_array ( p_draw_list , pb - > vertex_array ) ;
if ( pb - > indices . is_valid ( ) ) {
RD : : get_singleton ( ) - > draw_list_bind_index_array ( p_draw_list , pb - > indices ) ;
}
RD : : get_singleton ( ) - > draw_list_draw ( p_draw_list , pb - > indices . is_valid ( ) ) ;
2019-06-16 10:45:24 +08:00
} break ;
2019-06-25 03:13:06 +08:00
case Item : : Command : : TYPE_PRIMITIVE : {
2019-06-16 10:45:24 +08:00
2019-06-25 03:13:06 +08:00
const Item : : CommandPrimitive * primitive = static_cast < const Item : : CommandPrimitive * > ( c ) ;
2019-06-16 10:45:24 +08:00
2019-06-25 03:13:06 +08:00
//bind pipeline
{
static const PipelineVariant variant [ 4 ] = { PIPELINE_VARIANT_PRIMITIVE_POINTS , PIPELINE_VARIANT_PRIMITIVE_LINES , PIPELINE_VARIANT_PRIMITIVE_TRIANGLES , PIPELINE_VARIANT_PRIMITIVE_TRIANGLES } ;
ERR_CONTINUE ( primitive - > point_count = = 0 | | primitive - > point_count > 4 ) ;
RID pipeline = pipeline_variants - > variants [ p_render_target_format ] [ variant [ primitive - > point_count - 1 ] ] . get_render_pipeline ( RD : : INVALID_ID , p_samples ) ;
RD : : get_singleton ( ) - > draw_list_bind_render_pipeline ( p_draw_list , pipeline ) ;
}
2019-06-16 10:45:24 +08:00
2019-06-25 03:13:06 +08:00
//bind textures
{
2019-07-05 09:54:32 +08:00
_bind_texture_binding ( primitive - > texture_binding . binding_id , p_draw_list , push_constant . flags ) ;
2019-06-16 10:45:24 +08:00
}
2019-07-05 09:54:32 +08:00
if ( primitive - > specular_shininess . a < 0.999 ) {
push_constant . flags | = FLAGS_DEFAULT_SPECULAR_MAP_USED ;
}
_update_specular_shininess ( primitive - > specular_shininess , & push_constant . specular_shininess ) ;
2019-06-27 02:11:52 +08:00
RD : : get_singleton ( ) - > draw_list_bind_index_array ( p_draw_list , primitive_arrays . index_array [ MIN ( 3 , primitive - > point_count ) - 1 ] ) ;
for ( uint32_t j = 0 ; j < MIN ( 3 , primitive - > point_count ) ; j + + ) {
2019-06-25 03:13:06 +08:00
push_constant . points [ j * 2 + 0 ] = primitive - > points [ j ] . x ;
push_constant . points [ j * 2 + 1 ] = primitive - > points [ j ] . y ;
push_constant . uvs [ j * 2 + 0 ] = primitive - > uvs [ j ] . x ;
push_constant . uvs [ j * 2 + 1 ] = primitive - > uvs [ j ] . y ;
2019-07-05 09:54:32 +08:00
Color col = primitive - > colors [ j ] * base_color ;
2019-06-25 03:13:06 +08:00
push_constant . colors [ j * 2 + 0 ] = ( uint32_t ( Math : : make_half_float ( col . g ) ) < < 16 ) | Math : : make_half_float ( col . r ) ;
push_constant . colors [ j * 2 + 1 ] = ( uint32_t ( Math : : make_half_float ( col . a ) ) < < 16 ) | Math : : make_half_float ( col . b ) ;
2019-06-16 10:45:24 +08:00
}
2019-06-25 03:13:06 +08:00
RD : : get_singleton ( ) - > draw_list_set_push_constant ( p_draw_list , & push_constant , sizeof ( PushConstant ) ) ;
2019-06-27 02:11:52 +08:00
RD : : get_singleton ( ) - > draw_list_draw ( p_draw_list , true ) ;
2019-06-25 03:13:06 +08:00
2019-06-27 02:11:52 +08:00
if ( primitive - > point_count = = 4 ) {
for ( uint32_t j = 1 ; j < 3 ; j + + ) {
//second half of triangle
push_constant . points [ j * 2 + 0 ] = primitive - > points [ j + 1 ] . x ;
push_constant . points [ j * 2 + 1 ] = primitive - > points [ j + 1 ] . y ;
push_constant . uvs [ j * 2 + 0 ] = primitive - > uvs [ j + 1 ] . x ;
push_constant . uvs [ j * 2 + 1 ] = primitive - > uvs [ j + 1 ] . y ;
2019-07-05 09:54:32 +08:00
Color col = primitive - > colors [ j + 1 ] * base_color ;
2019-06-27 02:11:52 +08:00
push_constant . colors [ j * 2 + 0 ] = ( uint32_t ( Math : : make_half_float ( col . g ) ) < < 16 ) | Math : : make_half_float ( col . r ) ;
push_constant . colors [ j * 2 + 1 ] = ( uint32_t ( Math : : make_half_float ( col . a ) ) < < 16 ) | Math : : make_half_float ( col . b ) ;
}
2019-06-25 03:13:06 +08:00
2019-06-27 02:11:52 +08:00
RD : : get_singleton ( ) - > draw_list_set_push_constant ( p_draw_list , & push_constant , sizeof ( PushConstant ) ) ;
RD : : get_singleton ( ) - > draw_list_draw ( p_draw_list , true ) ;
}
2019-06-16 10:45:24 +08:00
} break ;
2019-06-25 03:13:06 +08:00
#if 0
2019-06-16 10:45:24 +08:00
case Item : : Command : : TYPE_MESH : {
Item : : CommandMesh * mesh = static_cast < Item : : CommandMesh * > ( c ) ;
_set_texture_rect_mode ( false ) ;
RasterizerStorageGLES3 : : Texture * texture = _bind_canvas_texture ( mesh - > texture , mesh - > normal_map ) ;
if ( texture ) {
Size2 texpixel_size ( 1.0 / texture - > width , 1.0 / texture - > height ) ;
state . canvas_shader . set_uniform ( CanvasShaderGLES3 : : COLOR_TEXPIXEL_SIZE , texpixel_size ) ;
}
state . canvas_shader . set_uniform ( CanvasShaderGLES3 : : MODELVIEW_MATRIX , state . final_transform * mesh - > transform ) ;
RasterizerStorageGLES3 : : Mesh * mesh_data = storage - > mesh_owner . getornull ( mesh - > mesh ) ;
if ( mesh_data ) {
for ( int j = 0 ; j < mesh_data - > surfaces . size ( ) ; j + + ) {
RasterizerStorageGLES3 : : Surface * s = mesh_data - > surfaces [ j ] ;
// materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing
glBindVertexArray ( s - > array_id ) ;
glVertexAttrib4f ( VS : : ARRAY_COLOR , mesh - > modulate . r , mesh - > modulate . g , mesh - > modulate . b , mesh - > modulate . a ) ;
if ( s - > index_array_len ) {
glDrawElements ( gl_primitive [ s - > primitive ] , s - > index_array_len , ( s - > array_len > = ( 1 < < 16 ) ) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT , 0 ) ;
} else {
glDrawArrays ( gl_primitive [ s - > primitive ] , 0 , s - > array_len ) ;
}
glBindVertexArray ( 0 ) ;
}
}
state . canvas_shader . set_uniform ( CanvasShaderGLES3 : : MODELVIEW_MATRIX , state . final_transform ) ;
} break ;
case Item : : Command : : TYPE_MULTIMESH : {
Item : : CommandMultiMesh * mmesh = static_cast < Item : : CommandMultiMesh * > ( c ) ;
RasterizerStorageGLES3 : : MultiMesh * multi_mesh = storage - > multimesh_owner . getornull ( mmesh - > multimesh ) ;
if ( ! multi_mesh )
break ;
RasterizerStorageGLES3 : : Mesh * mesh_data = storage - > mesh_owner . getornull ( multi_mesh - > mesh ) ;
if ( ! mesh_data )
break ;
RasterizerStorageGLES3 : : Texture * texture = _bind_canvas_texture ( mmesh - > texture , mmesh - > normal_map ) ;
state . canvas_shader . set_conditional ( CanvasShaderGLES3 : : USE_INSTANCE_CUSTOM , multi_mesh - > custom_data_format ! = VS : : MULTIMESH_CUSTOM_DATA_NONE ) ;
state . canvas_shader . set_conditional ( CanvasShaderGLES3 : : USE_INSTANCING , true ) ;
//reset shader and force rebind
state . using_texture_rect = true ;
_set_texture_rect_mode ( false ) ;
if ( texture ) {
Size2 texpixel_size ( 1.0 / texture - > width , 1.0 / texture - > height ) ;
state . canvas_shader . set_uniform ( CanvasShaderGLES3 : : COLOR_TEXPIXEL_SIZE , texpixel_size ) ;
}
int amount = MIN ( multi_mesh - > size , multi_mesh - > visible_instances ) ;
if ( amount = = - 1 ) {
amount = multi_mesh - > size ;
}
for ( int j = 0 ; j < mesh_data - > surfaces . size ( ) ; j + + ) {
RasterizerStorageGLES3 : : Surface * s = mesh_data - > surfaces [ j ] ;
// materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing
glBindVertexArray ( s - > instancing_array_id ) ;
glBindBuffer ( GL_ARRAY_BUFFER , multi_mesh - > buffer ) ; //modify the buffer
int stride = ( multi_mesh - > xform_floats + multi_mesh - > color_floats + multi_mesh - > custom_data_floats ) * 4 ;
glEnableVertexAttribArray ( 8 ) ;
glVertexAttribPointer ( 8 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( 0 ) ) ;
glVertexAttribDivisor ( 8 , 1 ) ;
glEnableVertexAttribArray ( 9 ) ;
glVertexAttribPointer ( 9 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( 4 * 4 ) ) ;
glVertexAttribDivisor ( 9 , 1 ) ;
int color_ofs ;
if ( multi_mesh - > transform_format = = VS : : MULTIMESH_TRANSFORM_3D ) {
glEnableVertexAttribArray ( 10 ) ;
glVertexAttribPointer ( 10 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( 8 * 4 ) ) ;
glVertexAttribDivisor ( 10 , 1 ) ;
color_ofs = 12 * 4 ;
} else {
glDisableVertexAttribArray ( 10 ) ;
glVertexAttrib4f ( 10 , 0 , 0 , 1 , 0 ) ;
color_ofs = 8 * 4 ;
}
int custom_data_ofs = color_ofs ;
switch ( multi_mesh - > color_format ) {
case VS : : MULTIMESH_COLOR_NONE : {
glDisableVertexAttribArray ( 11 ) ;
glVertexAttrib4f ( 11 , 1 , 1 , 1 , 1 ) ;
} break ;
case VS : : MULTIMESH_COLOR_8BIT : {
glEnableVertexAttribArray ( 11 ) ;
glVertexAttribPointer ( 11 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , stride , CAST_INT_TO_UCHAR_PTR ( color_ofs ) ) ;
glVertexAttribDivisor ( 11 , 1 ) ;
custom_data_ofs + = 4 ;
} break ;
case VS : : MULTIMESH_COLOR_FLOAT : {
glEnableVertexAttribArray ( 11 ) ;
glVertexAttribPointer ( 11 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( color_ofs ) ) ;
glVertexAttribDivisor ( 11 , 1 ) ;
custom_data_ofs + = 4 * 4 ;
} break ;
}
switch ( multi_mesh - > custom_data_format ) {
case VS : : MULTIMESH_CUSTOM_DATA_NONE : {
glDisableVertexAttribArray ( 12 ) ;
glVertexAttrib4f ( 12 , 1 , 1 , 1 , 1 ) ;
} break ;
case VS : : MULTIMESH_CUSTOM_DATA_8BIT : {
glEnableVertexAttribArray ( 12 ) ;
glVertexAttribPointer ( 12 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , stride , CAST_INT_TO_UCHAR_PTR ( custom_data_ofs ) ) ;
glVertexAttribDivisor ( 12 , 1 ) ;
} break ;
case VS : : MULTIMESH_CUSTOM_DATA_FLOAT : {
glEnableVertexAttribArray ( 12 ) ;
glVertexAttribPointer ( 12 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( custom_data_ofs ) ) ;
glVertexAttribDivisor ( 12 , 1 ) ;
} break ;
}
if ( s - > index_array_len ) {
glDrawElementsInstanced ( gl_primitive [ s - > primitive ] , s - > index_array_len , ( s - > array_len > = ( 1 < < 16 ) ) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT , 0 , amount ) ;
} else {
glDrawArraysInstanced ( gl_primitive [ s - > primitive ] , 0 , s - > array_len , amount ) ;
}
glBindVertexArray ( 0 ) ;
}
state . canvas_shader . set_conditional ( CanvasShaderGLES3 : : USE_INSTANCE_CUSTOM , false ) ;
state . canvas_shader . set_conditional ( CanvasShaderGLES3 : : USE_INSTANCING , false ) ;
state . using_texture_rect = true ;
_set_texture_rect_mode ( false ) ;
} break ;
case Item : : Command : : TYPE_PARTICLES : {
Item : : CommandParticles * particles_cmd = static_cast < Item : : CommandParticles * > ( c ) ;
RasterizerStorageGLES3 : : Particles * particles = storage - > particles_owner . getornull ( particles_cmd - > particles ) ;
if ( ! particles )
break ;
if ( particles - > inactive & & ! particles - > emitting )
break ;
glVertexAttrib4f ( VS : : ARRAY_COLOR , 1 , 1 , 1 , 1 ) ; //not used, so keep white
VisualServerRaster : : redraw_request ( ) ;
storage - > particles_request_process ( particles_cmd - > particles ) ;
//enable instancing
state . canvas_shader . set_conditional ( CanvasShaderGLES3 : : USE_INSTANCE_CUSTOM , true ) ;
state . canvas_shader . set_conditional ( CanvasShaderGLES3 : : USE_PARTICLES , true ) ;
state . canvas_shader . set_conditional ( CanvasShaderGLES3 : : USE_INSTANCING , true ) ;
//reset shader and force rebind
state . using_texture_rect = true ;
_set_texture_rect_mode ( false ) ;
RasterizerStorageGLES3 : : Texture * texture = _bind_canvas_texture ( particles_cmd - > texture , particles_cmd - > normal_map ) ;
if ( texture ) {
Size2 texpixel_size ( 1.0 / texture - > width , 1.0 / texture - > height ) ;
state . canvas_shader . set_uniform ( CanvasShaderGLES3 : : COLOR_TEXPIXEL_SIZE , texpixel_size ) ;
} else {
state . canvas_shader . set_uniform ( CanvasShaderGLES3 : : COLOR_TEXPIXEL_SIZE , Vector2 ( 1.0 , 1.0 ) ) ;
}
if ( ! particles - > use_local_coords ) {
Transform2D inv_xf ;
inv_xf . set_axis ( 0 , Vector2 ( particles - > emission_transform . basis . get_axis ( 0 ) . x , particles - > emission_transform . basis . get_axis ( 0 ) . y ) ) ;
inv_xf . set_axis ( 1 , Vector2 ( particles - > emission_transform . basis . get_axis ( 1 ) . x , particles - > emission_transform . basis . get_axis ( 1 ) . y ) ) ;
inv_xf . set_origin ( Vector2 ( particles - > emission_transform . get_origin ( ) . x , particles - > emission_transform . get_origin ( ) . y ) ) ;
inv_xf . affine_invert ( ) ;
state . canvas_shader . set_uniform ( CanvasShaderGLES3 : : MODELVIEW_MATRIX , state . final_transform * inv_xf ) ;
}
glBindVertexArray ( data . particle_quad_array ) ; //use particle quad array
glBindBuffer ( GL_ARRAY_BUFFER , particles - > particle_buffers [ 0 ] ) ; //bind particle buffer
int stride = sizeof ( float ) * 4 * 6 ;
int amount = particles - > amount ;
if ( particles - > draw_order ! = VS : : PARTICLES_DRAW_ORDER_LIFETIME ) {
glEnableVertexAttribArray ( 8 ) ; //xform x
glVertexAttribPointer ( 8 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( sizeof ( float ) * 4 * 3 ) ) ;
glVertexAttribDivisor ( 8 , 1 ) ;
glEnableVertexAttribArray ( 9 ) ; //xform y
glVertexAttribPointer ( 9 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( sizeof ( float ) * 4 * 4 ) ) ;
glVertexAttribDivisor ( 9 , 1 ) ;
glEnableVertexAttribArray ( 10 ) ; //xform z
glVertexAttribPointer ( 10 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( sizeof ( float ) * 4 * 5 ) ) ;
glVertexAttribDivisor ( 10 , 1 ) ;
glEnableVertexAttribArray ( 11 ) ; //color
glVertexAttribPointer ( 11 , 4 , GL_FLOAT , GL_FALSE , stride , NULL ) ;
glVertexAttribDivisor ( 11 , 1 ) ;
glEnableVertexAttribArray ( 12 ) ; //custom
glVertexAttribPointer ( 12 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( sizeof ( float ) * 4 * 2 ) ) ;
glVertexAttribDivisor ( 12 , 1 ) ;
glDrawArraysInstanced ( GL_TRIANGLE_FAN , 0 , 4 , amount ) ;
} else {
//split
int split = int ( Math : : ceil ( particles - > phase * particles - > amount ) ) ;
if ( amount - split > 0 ) {
glEnableVertexAttribArray ( 8 ) ; //xform x
glVertexAttribPointer ( 8 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( stride * split + sizeof ( float ) * 4 * 3 ) ) ;
glVertexAttribDivisor ( 8 , 1 ) ;
glEnableVertexAttribArray ( 9 ) ; //xform y
glVertexAttribPointer ( 9 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( stride * split + sizeof ( float ) * 4 * 4 ) ) ;
glVertexAttribDivisor ( 9 , 1 ) ;
glEnableVertexAttribArray ( 10 ) ; //xform z
glVertexAttribPointer ( 10 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( stride * split + sizeof ( float ) * 4 * 5 ) ) ;
glVertexAttribDivisor ( 10 , 1 ) ;
glEnableVertexAttribArray ( 11 ) ; //color
glVertexAttribPointer ( 11 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( stride * split + 0 ) ) ;
glVertexAttribDivisor ( 11 , 1 ) ;
glEnableVertexAttribArray ( 12 ) ; //custom
glVertexAttribPointer ( 12 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( stride * split + sizeof ( float ) * 4 * 2 ) ) ;
glVertexAttribDivisor ( 12 , 1 ) ;
glDrawArraysInstanced ( GL_TRIANGLE_FAN , 0 , 4 , amount - split ) ;
}
if ( split > 0 ) {
glEnableVertexAttribArray ( 8 ) ; //xform x
glVertexAttribPointer ( 8 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( sizeof ( float ) * 4 * 3 ) ) ;
glVertexAttribDivisor ( 8 , 1 ) ;
glEnableVertexAttribArray ( 9 ) ; //xform y
glVertexAttribPointer ( 9 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( sizeof ( float ) * 4 * 4 ) ) ;
glVertexAttribDivisor ( 9 , 1 ) ;
glEnableVertexAttribArray ( 10 ) ; //xform z
glVertexAttribPointer ( 10 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( sizeof ( float ) * 4 * 5 ) ) ;
glVertexAttribDivisor ( 10 , 1 ) ;
glEnableVertexAttribArray ( 11 ) ; //color
glVertexAttribPointer ( 11 , 4 , GL_FLOAT , GL_FALSE , stride , NULL ) ;
glVertexAttribDivisor ( 11 , 1 ) ;
glEnableVertexAttribArray ( 12 ) ; //custom
glVertexAttribPointer ( 12 , 4 , GL_FLOAT , GL_FALSE , stride , CAST_INT_TO_UCHAR_PTR ( sizeof ( float ) * 4 * 2 ) ) ;
glVertexAttribDivisor ( 12 , 1 ) ;
glDrawArraysInstanced ( GL_TRIANGLE_FAN , 0 , 4 , split ) ;
}
}
glBindVertexArray ( 0 ) ;
state . canvas_shader . set_conditional ( CanvasShaderGLES3 : : USE_INSTANCE_CUSTOM , false ) ;
state . canvas_shader . set_conditional ( CanvasShaderGLES3 : : USE_PARTICLES , false ) ;
state . canvas_shader . set_conditional ( CanvasShaderGLES3 : : USE_INSTANCING , false ) ;
state . using_texture_rect = true ;
_set_texture_rect_mode ( false ) ;
} break ;
2019-06-25 03:13:06 +08:00
# endif
2019-06-16 10:45:24 +08:00
case Item : : Command : : TYPE_TRANSFORM : {
2019-06-25 03:13:06 +08:00
const Item : : CommandTransform * transform = static_cast < const Item : : CommandTransform * > ( c ) ;
2019-06-25 09:24:07 +08:00
_update_transform_2d_to_mat2x3 ( base_transform * transform - > xform , push_constant . world ) ;
2019-06-16 10:45:24 +08:00
} break ;
case Item : : Command : : TYPE_CLIP_IGNORE : {
2019-06-25 03:13:06 +08:00
const Item : : CommandClipIgnore * ci = static_cast < const Item : : CommandClipIgnore * > ( c ) ;
2019-06-16 10:45:24 +08:00
if ( current_clip ) {
if ( ci - > ignore ! = reclip ) {
2019-06-25 03:13:06 +08:00
if ( ci - > ignore ) {
RD : : get_singleton ( ) - > draw_list_disable_scissor ( p_draw_list ) ;
2019-06-16 10:45:24 +08:00
reclip = true ;
} else {
2019-06-25 03:13:06 +08:00
RD : : get_singleton ( ) - > draw_list_enable_scissor ( p_draw_list , current_clip - > final_clip_rect ) ;
2019-06-16 10:45:24 +08:00
reclip = false ;
}
}
}
} break ;
}
2019-06-27 06:48:05 +08:00
c = c - > next ;
2019-06-16 10:45:24 +08:00
}
2019-06-25 03:13:06 +08:00
if ( current_clip & & reclip ) {
//will make it re-enable clipping if needed afterwards
current_clip = NULL ;
}
2019-06-16 10:45:24 +08:00
}
2019-07-05 09:54:32 +08:00
void RasterizerCanvasRD : : _render_items ( RID p_to_render_target , int p_item_count , const Transform2D & p_canvas_transform_inverse , Light * p_lights ) {
2019-06-16 10:45:24 +08:00
Item * current_clip = NULL ;
RenderTargetFormat render_target_format = RENDER_TARGET_FORMAT_8_BIT_INT ;
2019-07-05 09:54:32 +08:00
Transform2D canvas_transform_inverse = p_canvas_transform_inverse ;
2019-06-16 10:45:24 +08:00
RID framebuffer = storage - > render_target_get_rd_framebuffer ( p_to_render_target ) ;
Vector < Color > clear_colors ;
2019-06-25 03:13:06 +08:00
bool clear = false ;
if ( storage - > render_target_is_clear_requested ( p_to_render_target ) ) {
clear = true ;
clear_colors . push_back ( storage - > render_target_get_clear_request_color ( p_to_render_target ) ) ;
storage - > render_target_disable_clear_request ( p_to_render_target ) ;
2019-06-16 10:45:24 +08:00
}
2019-06-20 04:03:19 +08:00
# warning TODO obtain from framebuffer format eventually when this is implemented
RD : : TextureSamples texture_samples = RD : : TEXTURE_SAMPLES_1 ;
2019-06-25 03:13:06 +08:00
RD : : DrawListID draw_list = RD : : get_singleton ( ) - > draw_list_begin ( framebuffer , clear ? RD : : INITIAL_ACTION_CLEAR : RD : : INITIAL_ACTION_KEEP_COLOR , RD : : FINAL_ACTION_READ_COLOR_DISCARD_DEPTH , clear_colors ) ;
2019-06-16 10:45:24 +08:00
RD : : get_singleton ( ) - > draw_list_bind_uniform_set ( draw_list , state . canvas_state_uniform_set , 3 ) ;
for ( int i = 0 ; i < p_item_count ; i + + ) {
Item * ci = items [ i ] ;
if ( current_clip ! = ci - > final_clip_owner ) {
current_clip = ci - > final_clip_owner ;
//setup clip
if ( current_clip ) {
RD : : get_singleton ( ) - > draw_list_enable_scissor ( draw_list , current_clip - > final_clip_rect ) ;
} else {
RD : : get_singleton ( ) - > draw_list_disable_scissor ( draw_list ) ;
}
}
2019-06-20 04:03:19 +08:00
if ( false ) { //not skeleton
2019-06-16 10:45:24 +08:00
2019-06-25 03:13:06 +08:00
RD : : get_singleton ( ) - > draw_list_bind_uniform_set ( draw_list , shader . default_skeleton_uniform_set , 1 ) ;
2019-06-16 10:45:24 +08:00
}
2019-07-05 09:54:32 +08:00
_render_item ( draw_list , ci , render_target_format , texture_samples , canvas_transform_inverse , current_clip , p_lights ) ;
2019-06-16 10:45:24 +08:00
}
RD : : get_singleton ( ) - > draw_list_end ( ) ;
}
void RasterizerCanvasRD : : _update_canvas_state_uniform_set ( ) {
if ( state . canvas_state_uniform_set . is_valid ( ) & & RD : : get_singleton ( ) - > uniform_set_is_valid ( state . canvas_state_uniform_set ) ) {
return ; //nothing to update
}
Vector < RD : : Uniform > uniforms ;
2019-07-05 09:54:32 +08:00
{
RD : : Uniform u ;
u . type = RD : : UNIFORM_TYPE_UNIFORM_BUFFER ;
u . binding = 0 ;
u . ids . push_back ( state . canvas_state_buffer ) ;
uniforms . push_back ( u ) ;
}
{
RD : : Uniform u ;
u . type = RD : : UNIFORM_TYPE_UNIFORM_BUFFER ;
u . binding = 1 ;
u . ids . push_back ( state . lights_uniform_buffer ) ;
uniforms . push_back ( u ) ;
}
{
RD : : Uniform u_lights ;
u_lights . type = RD : : UNIFORM_TYPE_TEXTURE ;
u_lights . binding = 2 ;
RD : : Uniform u_shadows ;
u_shadows . type = RD : : UNIFORM_TYPE_TEXTURE ;
u_shadows . binding = 3 ;
//lights
for ( uint32_t i = 0 ; i < MAX_LIGHT_TEXTURES ; i + + ) {
if ( i < canvas_light_owner . get_rid_count ( ) ) {
CanvasLight * cl = canvas_light_owner . get_rid_by_index ( i ) ;
cl - > texture_index = i ;
RID rd_texture ;
if ( cl - > texture . is_valid ( ) ) {
rd_texture = storage - > texture_get_rd_texture ( cl - > texture ) ;
}
if ( rd_texture . is_valid ( ) ) {
u_lights . ids . push_back ( rd_texture ) ;
} else {
u_lights . ids . push_back ( default_textures . white_texture ) ;
}
if ( cl - > shadow . texture . is_valid ( ) ) {
u_shadows . ids . push_back ( cl - > shadow . texture ) ;
} else {
u_shadows . ids . push_back ( default_textures . black_texture ) ;
}
} else {
u_lights . ids . push_back ( default_textures . white_texture ) ;
u_shadows . ids . push_back ( default_textures . black_texture ) ;
}
}
//in case there are more
for ( uint32_t i = MAX_LIGHT_TEXTURES ; i < canvas_light_owner . get_rid_count ( ) ; i + + ) {
CanvasLight * cl = canvas_light_owner . get_rid_by_index ( i ) ;
cl - > texture_index = - 1 ; //make invalid (no texture)
}
uniforms . push_back ( u_lights ) ;
uniforms . push_back ( u_shadows ) ;
}
2019-06-16 10:45:24 +08:00
state . canvas_state_uniform_set = RD : : get_singleton ( ) - > uniform_set_create ( uniforms , shader . default_version_rd_shader , 3 ) ; // uses index 3
}
2019-06-25 03:13:06 +08:00
void RasterizerCanvasRD : : canvas_render_items ( RID p_to_render_target , Item * p_item_list , const Color & p_modulate , Light * p_light_list , const Transform2D & p_canvas_transform ) {
2019-06-16 10:45:24 +08:00
int item_count = 0 ;
//setup canvas state uniforms if needed
_update_canvas_state_uniform_set ( ) ;
2019-07-05 09:54:32 +08:00
Transform2D canvas_transform_inverse = p_canvas_transform . affine_inverse ( ) ;
2019-06-16 10:45:24 +08:00
{
//update canvas state uniform buffer
State : : Buffer state_buffer ;
Size2i ssize = storage - > render_target_get_size ( p_to_render_target ) ;
Transform screen_transform ;
screen_transform . translate ( - ( ssize . width / 2.0f ) , - ( ssize . height / 2.0f ) , 0.0f ) ;
screen_transform . scale ( Vector3 ( 2.0f / ssize . width , 2.0f / ssize . height , 1.0f ) ) ;
_update_transform_to_mat4 ( screen_transform , state_buffer . screen_transform ) ;
_update_transform_2d_to_mat4 ( p_canvas_transform , state_buffer . canvas_transform ) ;
2019-07-05 09:54:32 +08:00
Transform2D normal_transform = p_canvas_transform ;
normal_transform . elements [ 0 ] . normalize ( ) ;
normal_transform . elements [ 1 ] . normalize ( ) ;
normal_transform . elements [ 2 ] = Vector2 ( ) ;
_update_transform_2d_to_mat4 ( normal_transform , state_buffer . canvas_normal_transform ) ;
state_buffer . canvas_modulate [ 0 ] = p_modulate . r ;
state_buffer . canvas_modulate [ 1 ] = p_modulate . g ;
state_buffer . canvas_modulate [ 2 ] = p_modulate . b ;
state_buffer . canvas_modulate [ 3 ] = p_modulate . a ;
2019-06-16 10:45:24 +08:00
RD : : get_singleton ( ) - > buffer_update ( state . canvas_state_buffer , 0 , sizeof ( State : : Buffer ) , & state_buffer , true ) ;
}
2019-07-05 09:54:32 +08:00
//setup lights if exist
{
Light * l = p_light_list ;
uint32_t index = 0 ;
while ( l ) {
if ( index = = MAX_RENDER_LIGHTS ) {
l - > render_index_cache = - 1 ;
l = l - > next_ptr ;
continue ;
}
CanvasLight * clight = canvas_light_owner . getornull ( l - > light_internal ) ;
if ( ! clight | | clight - > texture_index < 0 ) { //unused or invalid texture
l - > render_index_cache = - 1 ;
l = l - > next_ptr ;
ERR_CONTINUE ( ! clight ) ;
}
Transform2D to_light_xform = ( p_canvas_transform * l - > light_shader_xform ) . affine_inverse ( ) ;
Vector2 canvas_light_pos = p_canvas_transform . xform ( l - > xform . get_origin ( ) ) ; //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss
state . light_uniforms [ index ] . position [ 0 ] = canvas_light_pos . x ;
state . light_uniforms [ index ] . position [ 1 ] = canvas_light_pos . y ;
_update_transform_2d_to_mat2x4 ( to_light_xform , state . light_uniforms [ index ] . matrix ) ;
state . light_uniforms [ index ] . height = l - > height * ( p_canvas_transform . elements [ 0 ] . length ( ) + p_canvas_transform . elements [ 1 ] . length ( ) ) * 0.5 ; //approximate height conversion to the canvas size, since all calculations are done in canvas coords to avoid precision loss
for ( int i = 0 ; i < 4 ; i + + ) {
state . light_uniforms [ index ] . shadow_color [ i ] = l - > shadow_color [ i ] ;
state . light_uniforms [ index ] . color [ i ] = l - > color [ i ] ;
}
state . light_uniforms [ index ] . color [ 3 ] = l - > energy ; //use alpha for energy, so base color can go separate
if ( clight - > shadow . texture . is_valid ( ) ) {
state . light_uniforms [ index ] . shadow_pixel_size = 1.0 / clight - > shadow . size ;
} else {
state . light_uniforms [ index ] . shadow_pixel_size = 1.0 ;
}
state . light_uniforms [ index ] . flags = clight - > texture_index ;
state . light_uniforms [ index ] . flags | = l - > mode < < LIGHT_FLAGS_BLEND_SHIFT ;
l - > render_index_cache = index ;
index + + ;
l = l - > next_ptr ;
}
if ( index > 0 ) {
RD : : get_singleton ( ) - > buffer_update ( state . lights_uniform_buffer , 0 , sizeof ( LightUniform ) * index , & state . light_uniforms [ 0 ] , true ) ;
}
}
2019-06-16 10:45:24 +08:00
//fill the list until rendering is possible.
Item * ci = p_item_list ;
while ( ci ) {
items [ item_count + + ] = ci ;
bool backbuffer_copy = ci - > copy_back_buffer ; // || shader uses SCREEN_TEXTURE
if ( ! ci - > next | | backbuffer_copy | | item_count = = MAX_RENDER_ITEMS - 1 ) {
2019-07-05 09:54:32 +08:00
_render_items ( p_to_render_target , item_count , canvas_transform_inverse , p_light_list ) ;
2019-06-16 10:45:24 +08:00
//then reset
item_count = 0 ;
}
if ( ci - > copy_back_buffer ) {
if ( ci - > copy_back_buffer - > full ) {
//_copy_texscreen(Rect2());
} else {
//_copy_texscreen(ci->copy_back_buffer->rect);
}
}
ci = ci - > next ;
}
}
2019-07-05 09:54:32 +08:00
RID RasterizerCanvasRD : : light_create ( ) {
CanvasLight canvas_light ;
canvas_light . shadow . size = 0 ;
canvas_light . texture_index = - 1 ;
return canvas_light_owner . make_rid ( canvas_light ) ;
}
void RasterizerCanvasRD : : light_set_texture ( RID p_rid , RID p_texture ) {
CanvasLight * cl = canvas_light_owner . getornull ( p_rid ) ;
ERR_FAIL_COND ( ! cl ) ;
if ( cl - > texture = = p_texture ) {
return ;
}
cl - > texture = p_texture ;
//canvas state uniform set needs updating
if ( state . canvas_state_uniform_set . is_valid ( ) & & RD : : get_singleton ( ) - > uniform_set_is_valid ( state . canvas_state_uniform_set ) ) {
RD : : get_singleton ( ) - > free ( state . canvas_state_uniform_set ) ;
}
}
void RasterizerCanvasRD : : light_set_use_shadow ( RID p_rid , bool p_enable , int p_resolution ) {
CanvasLight * cl = canvas_light_owner . getornull ( p_rid ) ;
ERR_FAIL_COND ( ! cl ) ;
ERR_FAIL_COND ( p_resolution < 64 ) ;
if ( cl - > shadow . texture . is_valid ( ) = = p_enable & & p_resolution = = cl - > shadow . size ) {
return ;
}
if ( cl - > shadow . texture . is_valid ( ) ) {
RD : : get_singleton ( ) - > free ( cl - > shadow . uniform_set ) ;
cl - > shadow . uniform_set = RID ( ) ;
for ( int i = 0 ; i < 4 ; i + + ) {
RD : : get_singleton ( ) - > free ( cl - > shadow . render_fb [ i ] ) ;
RD : : get_singleton ( ) - > free ( cl - > shadow . render_textures [ i ] ) ;
cl - > shadow . render_fb [ i ] = RID ( ) ;
cl - > shadow . render_textures [ i ] = RID ( ) ;
}
RD : : get_singleton ( ) - > free ( cl - > shadow . fix_fb ) ;
RD : : get_singleton ( ) - > free ( cl - > shadow . texture ) ;
cl - > shadow . fix_fb = RID ( ) ;
cl - > shadow . texture = RID ( ) ;
}
if ( p_enable ) {
{ //texture
RD : : TextureFormat tf ;
tf . type = RD : : TEXTURE_TYPE_2D ;
tf . width = p_resolution ;
tf . height = 1 ;
tf . usage_bits = RD : : TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD : : TEXTURE_USAGE_SAMPLING_BIT ;
tf . format = RD : : DATA_FORMAT_R32_SFLOAT ;
cl - > shadow . texture = RD : : get_singleton ( ) - > texture_create ( tf , RD : : TextureView ( ) ) ;
Vector < RID > fb_textures ;
fb_textures . push_back ( cl - > shadow . texture ) ;
cl - > shadow . fix_fb = RD : : get_singleton ( ) - > framebuffer_create ( fb_textures ) ;
}
{
RD : : TextureFormat tf ;
tf . type = RD : : TEXTURE_TYPE_2D ;
tf . width = p_resolution / 2 ;
tf . height = 1 ;
tf . usage_bits = RD : : TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ;
tf . format = RD : : get_singleton ( ) - > texture_is_format_supported_for_usage ( RD : : DATA_FORMAT_X8_D24_UNORM_PACK32 , RD : : TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) ? RD : : DATA_FORMAT_X8_D24_UNORM_PACK32 : RD : : DATA_FORMAT_D32_SFLOAT ;
//chunks to write
cl - > shadow . render_depth = RD : : get_singleton ( ) - > texture_create ( tf , RD : : TextureView ( ) ) ;
RD : : Uniform tex_uniforms ;
tex_uniforms . type = RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE ;
tex_uniforms . binding = 0 ;
for ( int i = 0 ; i < 4 ; i + + ) {
tf . usage_bits = RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_COLOR_ATTACHMENT_BIT ;
tf . format = RD : : DATA_FORMAT_R32_SFLOAT ;
cl - > shadow . render_textures [ i ] = RD : : get_singleton ( ) - > texture_create ( tf , RD : : TextureView ( ) ) ;
Vector < RID > textures ;
textures . push_back ( cl - > shadow . render_textures [ i ] ) ;
textures . push_back ( cl - > shadow . render_depth ) ;
cl - > shadow . render_fb [ i ] = RD : : get_singleton ( ) - > framebuffer_create ( textures ) ;
tex_uniforms . ids . push_back ( default_samplers . samplers [ VS : : CANVAS_ITEM_TEXTURE_FILTER_NEAREST ] [ VS : : CANVAS_ITEM_TEXTURE_REPEAT_DISABLED ] ) ;
tex_uniforms . ids . push_back ( cl - > shadow . render_textures [ i ] ) ;
}
Vector < RD : : Uniform > tex_uniforms_set ;
tex_uniforms_set . push_back ( tex_uniforms ) ;
cl - > shadow . uniform_set = RD : : get_singleton ( ) - > uniform_set_create ( tex_uniforms_set , shadow_render . shader_fix . version_get_shader ( shadow_render . shader_fix_version , 0 ) , 0 ) ;
}
}
//canvas state uniform set needs updating
if ( state . canvas_state_uniform_set . is_valid ( ) & & RD : : get_singleton ( ) - > uniform_set_is_valid ( state . canvas_state_uniform_set ) ) {
RD : : get_singleton ( ) - > free ( state . canvas_state_uniform_set ) ;
}
}
void RasterizerCanvasRD : : light_update_shadow ( RID p_rid , const Transform2D & p_light_xform , int p_light_mask , float p_near , float p_far , LightOccluderInstance * p_occluders ) {
CanvasLight * cl = canvas_light_owner . getornull ( p_rid ) ;
ERR_FAIL_COND ( cl - > shadow . texture . is_null ( ) ) ;
for ( int i = 0 ; i < 4 ; i + + ) {
//make sure it remains orthogonal, makes easy to read angle later
//light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1));
Vector < Color > cc ;
cc . push_back ( Color ( p_far , p_far , p_far , 1.0 ) ) ;
RD : : DrawListID draw_list = RD : : get_singleton ( ) - > draw_list_begin ( cl - > shadow . render_fb [ i ] , RD : : INITIAL_ACTION_CLEAR , RD : : FINAL_ACTION_READ_COLOR_DISCARD_DEPTH , cc ) ;
CameraMatrix projection ;
{
real_t fov = 90 ;
real_t nearp = p_near ;
real_t farp = p_far ;
real_t aspect = 1.0 ;
real_t ymax = nearp * Math : : tan ( Math : : deg2rad ( fov * 0.5 ) ) ;
real_t ymin = - ymax ;
real_t xmin = ymin * aspect ;
real_t xmax = ymax * aspect ;
projection . set_frustum ( xmin , xmax , ymin , ymax , nearp , farp ) ;
}
Vector3 cam_target = Basis ( Vector3 ( 0 , 0 , Math_PI * 2 * ( i / 4.0 ) ) ) . xform ( Vector3 ( 0 , 1 , 0 ) ) ;
projection = projection * CameraMatrix ( Transform ( ) . looking_at ( cam_target , Vector3 ( 0 , 0 , - 1 ) ) . affine_inverse ( ) ) ;
ShadowRenderPushConstant push_constant ;
for ( int y = 0 ; y < 4 ; y + + ) {
for ( int x = 0 ; x < 4 ; x + + ) {
push_constant . projection [ y * 4 + x ] = projection . matrix [ y ] [ x ] ;
}
}
/*if (i == 0)
* p_xform_cache = projection ; */
LightOccluderInstance * instance = p_occluders ;
while ( instance ) {
OccluderPolygon * co = occluder_polygon_owner . getornull ( instance - > polygon ) ;
if ( ! co | | co - > index_array . is_null ( ) | | ! ( p_light_mask & instance - > light_mask ) ) {
instance = instance - > next ;
continue ;
}
_update_transform_2d_to_mat4 ( p_light_xform * instance - > xform_cache , push_constant . modelview ) ;
RD : : get_singleton ( ) - > draw_list_bind_render_pipeline ( draw_list , shadow_render . render_pipelines [ co - > cull_mode ] ) ;
RD : : get_singleton ( ) - > draw_list_bind_vertex_array ( draw_list , co - > vertex_array ) ;
RD : : get_singleton ( ) - > draw_list_bind_index_array ( draw_list , co - > index_array ) ;
RD : : get_singleton ( ) - > draw_list_set_push_constant ( draw_list , & push_constant , sizeof ( ShadowRenderPushConstant ) ) ;
RD : : get_singleton ( ) - > draw_list_draw ( draw_list , true ) ;
instance = instance - > next ;
}
RD : : get_singleton ( ) - > draw_list_end ( ) ;
}
Vector < Color > cc ;
cc . push_back ( Color ( p_far , p_far , p_far , 1.0 ) ) ;
RD : : DrawListID draw_list = RD : : get_singleton ( ) - > draw_list_begin ( cl - > shadow . fix_fb , RD : : INITIAL_ACTION_CLEAR , RD : : FINAL_ACTION_READ_COLOR_DISCARD_DEPTH , cc ) ;
RD : : get_singleton ( ) - > draw_list_bind_render_pipeline ( draw_list , shadow_render . shader_fix_pipeline ) ;
RD : : get_singleton ( ) - > draw_list_bind_index_array ( draw_list , primitive_arrays . index_array [ 3 ] ) ;
RD : : get_singleton ( ) - > draw_list_bind_uniform_set ( draw_list , cl - > shadow . uniform_set , 0 ) ;
RD : : get_singleton ( ) - > draw_list_draw ( draw_list , true ) ;
RD : : get_singleton ( ) - > draw_list_end ( ) ;
}
RID RasterizerCanvasRD : : occluder_polygon_create ( ) {
OccluderPolygon occluder ;
occluder . point_count = 0 ;
occluder . cull_mode = VS : : CANVAS_OCCLUDER_POLYGON_CULL_DISABLED ;
return occluder_polygon_owner . make_rid ( occluder ) ;
}
void RasterizerCanvasRD : : occluder_polygon_set_shape_as_lines ( RID p_occluder , const PoolVector < Vector2 > & p_lines ) {
OccluderPolygon * oc = occluder_polygon_owner . getornull ( p_occluder ) ;
ERR_FAIL_COND ( ! oc ) ;
if ( oc - > point_count ! = p_lines . size ( ) & & oc - > vertex_array . is_valid ( ) ) {
RD : : get_singleton ( ) - > free ( oc - > vertex_array ) ;
RD : : get_singleton ( ) - > free ( oc - > vertex_buffer ) ;
RD : : get_singleton ( ) - > free ( oc - > index_array ) ;
RD : : get_singleton ( ) - > free ( oc - > index_buffer ) ;
oc - > vertex_array = RID ( ) ;
oc - > vertex_buffer = RID ( ) ;
oc - > index_array = RID ( ) ;
oc - > index_buffer = RID ( ) ;
}
if ( p_lines . size ( ) ) {
PoolVector < uint8_t > geometry ;
PoolVector < uint8_t > indices ;
int lc = p_lines . size ( ) ;
geometry . resize ( lc * 6 * sizeof ( float ) ) ;
indices . resize ( lc * 3 * sizeof ( uint16_t ) ) ;
{
PoolVector < uint8_t > : : Write vw = geometry . write ( ) ;
float * vwptr = ( float * ) vw . ptr ( ) ;
PoolVector < uint8_t > : : Write iw = indices . write ( ) ;
uint16_t * iwptr = ( uint16_t * ) iw . ptr ( ) ;
PoolVector < Vector2 > : : Read lr = p_lines . read ( ) ;
const int POLY_HEIGHT = 16384 ;
for ( int i = 0 ; i < lc / 2 ; i + + ) {
vwptr [ i * 12 + 0 ] = lr [ i * 2 + 0 ] . x ;
vwptr [ i * 12 + 1 ] = lr [ i * 2 + 0 ] . y ;
vwptr [ i * 12 + 2 ] = POLY_HEIGHT ;
vwptr [ i * 12 + 3 ] = lr [ i * 2 + 1 ] . x ;
vwptr [ i * 12 + 4 ] = lr [ i * 2 + 1 ] . y ;
vwptr [ i * 12 + 5 ] = POLY_HEIGHT ;
vwptr [ i * 12 + 6 ] = lr [ i * 2 + 1 ] . x ;
vwptr [ i * 12 + 7 ] = lr [ i * 2 + 1 ] . y ;
vwptr [ i * 12 + 8 ] = - POLY_HEIGHT ;
vwptr [ i * 12 + 9 ] = lr [ i * 2 + 0 ] . x ;
vwptr [ i * 12 + 10 ] = lr [ i * 2 + 0 ] . y ;
vwptr [ i * 12 + 11 ] = - POLY_HEIGHT ;
iwptr [ i * 6 + 0 ] = i * 4 + 0 ;
iwptr [ i * 6 + 1 ] = i * 4 + 1 ;
iwptr [ i * 6 + 2 ] = i * 4 + 2 ;
iwptr [ i * 6 + 3 ] = i * 4 + 2 ;
iwptr [ i * 6 + 4 ] = i * 4 + 3 ;
iwptr [ i * 6 + 5 ] = i * 4 + 0 ;
}
}
//if same buffer len is being set, just use BufferSubData to avoid a pipeline flush
if ( oc - > vertex_array . is_null ( ) ) {
//create from scratch
//vertices
oc - > vertex_buffer = RD : : get_singleton ( ) - > vertex_buffer_create ( lc * 6 * sizeof ( real_t ) , geometry ) ;
Vector < RID > buffer ;
buffer . push_back ( oc - > vertex_buffer ) ;
oc - > vertex_array = RD : : get_singleton ( ) - > vertex_array_create ( 4 * lc / 2 , shadow_render . vertex_format , buffer ) ;
//indices
oc - > index_buffer = RD : : get_singleton ( ) - > index_buffer_create ( 3 * lc , RD : : INDEX_BUFFER_FORMAT_UINT16 , indices ) ;
oc - > index_array = RD : : get_singleton ( ) - > index_array_create ( oc - > index_buffer , 0 , 3 * lc ) ;
} else {
//update existing
PoolVector < uint8_t > : : Read vr = geometry . read ( ) ;
RD : : get_singleton ( ) - > buffer_update ( oc - > vertex_buffer , 0 , geometry . size ( ) , vr . ptr ( ) ) ;
PoolVector < uint8_t > : : Read ir = indices . read ( ) ;
RD : : get_singleton ( ) - > buffer_update ( oc - > index_buffer , 0 , indices . size ( ) , ir . ptr ( ) ) ;
}
}
}
void RasterizerCanvasRD : : occluder_polygon_set_cull_mode ( RID p_occluder , VS : : CanvasOccluderPolygonCullMode p_mode ) {
OccluderPolygon * oc = occluder_polygon_owner . getornull ( p_occluder ) ;
ERR_FAIL_COND ( ! oc ) ;
oc - > cull_mode = p_mode ;
}
2019-06-16 10:45:24 +08:00
void RasterizerCanvasRD : : update ( ) {
_dispose_bindings ( ) ;
}
RasterizerCanvasRD : : RasterizerCanvasRD ( RasterizerStorageRD * p_storage ) {
storage = p_storage ;
{ //create default textures
RD : : TextureFormat tformat ;
tformat . format = RD : : DATA_FORMAT_R8G8B8A8_UNORM ;
tformat . width = 4 ;
tformat . height = 4 ;
tformat . usage_bits = RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_CAN_UPDATE_BIT ;
tformat . type = RD : : TEXTURE_TYPE_2D ;
PoolVector < uint8_t > pv ;
pv . resize ( 16 * 4 ) ;
for ( int i = 0 ; i < 16 ; i + + ) {
pv . set ( i * 4 + 0 , 255 ) ;
pv . set ( i * 4 + 1 , 255 ) ;
pv . set ( i * 4 + 2 , 255 ) ;
pv . set ( i * 4 + 3 , 255 ) ;
}
{
Vector < PoolVector < uint8_t > > vpv ;
vpv . push_back ( pv ) ;
default_textures . white_texture = RD : : get_singleton ( ) - > texture_create ( tformat , RD : : TextureView ( ) , vpv ) ;
}
for ( int i = 0 ; i < 16 ; i + + ) {
pv . set ( i * 4 + 0 , 0 ) ;
pv . set ( i * 4 + 1 , 0 ) ;
pv . set ( i * 4 + 2 , 0 ) ;
pv . set ( i * 4 + 3 , 255 ) ;
}
{
Vector < PoolVector < uint8_t > > vpv ;
vpv . push_back ( pv ) ;
default_textures . black_texture = RD : : get_singleton ( ) - > texture_create ( tformat , RD : : TextureView ( ) , vpv ) ;
}
for ( int i = 0 ; i < 16 ; i + + ) {
pv . set ( i * 4 + 0 , 128 ) ;
pv . set ( i * 4 + 1 , 128 ) ;
pv . set ( i * 4 + 2 , 255 ) ;
pv . set ( i * 4 + 3 , 255 ) ;
}
{
Vector < PoolVector < uint8_t > > vpv ;
vpv . push_back ( pv ) ;
default_textures . normal_texture = RD : : get_singleton ( ) - > texture_create ( tformat , RD : : TextureView ( ) , vpv ) ;
}
for ( int i = 0 ; i < 16 ; i + + ) {
pv . set ( i * 4 + 0 , 255 ) ;
pv . set ( i * 4 + 1 , 128 ) ;
pv . set ( i * 4 + 2 , 255 ) ;
pv . set ( i * 4 + 3 , 255 ) ;
}
{
Vector < PoolVector < uint8_t > > vpv ;
vpv . push_back ( pv ) ;
default_textures . aniso_texture = RD : : get_singleton ( ) - > texture_create ( tformat , RD : : TextureView ( ) , vpv ) ;
}
for ( int i = 0 ; i < 16 ; i + + ) {
pv . set ( i * 4 + 0 , 0 ) ;
pv . set ( i * 4 + 1 , 0 ) ;
pv . set ( i * 4 + 2 , 0 ) ;
pv . set ( i * 4 + 3 , 0 ) ;
}
default_textures . default_multimesh_tb = RD : : get_singleton ( ) - > texture_buffer_create ( 16 , RD : : DATA_FORMAT_R8G8B8A8_UNORM , pv ) ;
}
{ //create default samplers
for ( int i = 1 ; i < VS : : CANVAS_ITEM_TEXTURE_FILTER_MAX ; i + + ) {
for ( int j = 1 ; j < VS : : CANVAS_ITEM_TEXTURE_REPEAT_MAX ; j + + ) {
RD : : SamplerState sampler_state ;
switch ( i ) {
case VS : : CANVAS_ITEM_TEXTURE_FILTER_NEAREST : {
sampler_state . mag_filter = RD : : SAMPLER_FILTER_NEAREST ;
sampler_state . min_filter = RD : : SAMPLER_FILTER_NEAREST ;
sampler_state . max_lod = 0 ;
} break ;
case VS : : CANVAS_ITEM_TEXTURE_FILTER_LINEAR : {
sampler_state . mag_filter = RD : : SAMPLER_FILTER_LINEAR ;
sampler_state . min_filter = RD : : SAMPLER_FILTER_LINEAR ;
sampler_state . max_lod = 0 ;
} break ;
case VS : : CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS : {
sampler_state . mag_filter = RD : : SAMPLER_FILTER_LINEAR ;
sampler_state . min_filter = RD : : SAMPLER_FILTER_LINEAR ;
sampler_state . mip_filter = RD : : SAMPLER_FILTER_LINEAR ;
} break ;
case VS : : CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS : {
sampler_state . mag_filter = RD : : SAMPLER_FILTER_NEAREST ;
sampler_state . min_filter = RD : : SAMPLER_FILTER_LINEAR ;
sampler_state . mip_filter = RD : : SAMPLER_FILTER_LINEAR ;
} break ;
default : {
}
}
switch ( j ) {
case VS : : CANVAS_ITEM_TEXTURE_REPEAT_DISABLED : {
sampler_state . repeat_u = RD : : SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE ;
sampler_state . repeat_v = RD : : SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE ;
} break ;
case VS : : CANVAS_ITEM_TEXTURE_REPEAT_ENABLED : {
sampler_state . repeat_u = RD : : SAMPLER_REPEAT_MODE_REPEAT ;
sampler_state . repeat_v = RD : : SAMPLER_REPEAT_MODE_REPEAT ;
} break ;
case VS : : CANVAS_ITEM_TEXTURE_REPEAT_MIRROR : {
sampler_state . repeat_u = RD : : SAMPLER_REPEAT_MODE_MIRRORED_REPEAT ;
sampler_state . repeat_v = RD : : SAMPLER_REPEAT_MODE_MIRRORED_REPEAT ;
} break ;
default : {
}
}
default_samplers . samplers [ i ] [ j ] = RD : : get_singleton ( ) - > sampler_create ( sampler_state ) ;
}
}
default_samplers . default_filter = VS : : CANVAS_ITEM_TEXTURE_FILTER_LINEAR ;
default_samplers . default_repeat = VS : : CANVAS_ITEM_TEXTURE_REPEAT_DISABLED ;
}
{ //shader variants
Vector < String > variants ;
variants . push_back ( " " ) ; //none by default is first variant
variants . push_back ( " #define USE_NINEPATCH \n " ) ; //ninepatch is the second variant
2019-06-25 03:13:06 +08:00
variants . push_back ( " #define USE_PRIMITIVE \n " ) ; //primitve is the third
variants . push_back ( " #define USE_PRIMITIVE \n #define USE_POINT_SIZE \n " ) ; //points need point size
variants . push_back ( " #define USE_ATTRIBUTES \n " ) ; // attributes for vertex arrays
variants . push_back ( " #define USE_ATTRIBUTES \n #define USE_POINT_SIZE \n " ) ; //attributes with point size
2019-06-16 10:45:24 +08:00
shader . canvas_shader . initialize ( variants ) ;
shader . default_version = shader . canvas_shader . version_create ( ) ;
{
//framebuffer formats
RD : : AttachmentFormat af ;
af . format = RD : : DATA_FORMAT_R8G8B8A8_UNORM ;
af . samples = RD : : TEXTURE_SAMPLES_1 ;
2019-06-27 02:11:52 +08:00
af . usage_flags = RD : : TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_CAN_RETRIEVE_BIT ;
2019-06-16 10:45:24 +08:00
Vector < RD : : AttachmentFormat > formats ;
formats . push_back ( af ) ;
shader . framebuffer_formats [ RENDER_TARGET_FORMAT_8_BIT_INT ] = RD : : get_singleton ( ) - > framebuffer_format_create ( formats ) ;
formats . clear ( ) ;
af . format = RD : : DATA_FORMAT_R16G16B16A16_SFLOAT ;
formats . push_back ( af ) ;
shader . framebuffer_formats [ RENDER_TARGET_FORMAT_16_BIT_FLOAT ] = RD : : get_singleton ( ) - > framebuffer_format_create ( formats ) ;
}
for ( int i = 0 ; i < RENDER_TARGET_FORMAT_MAX ; i + + ) {
RD : : FramebufferFormatID fb_format = shader . framebuffer_formats [ i ] ;
for ( int j = 0 ; j < PIPELINE_VARIANT_MAX ; j + + ) {
2019-06-25 03:13:06 +08:00
RD : : RenderPrimitive primitive [ PIPELINE_VARIANT_MAX ] = {
RD : : RENDER_PRIMITIVE_TRIANGLES ,
RD : : RENDER_PRIMITIVE_TRIANGLES ,
RD : : RENDER_PRIMITIVE_TRIANGLES ,
RD : : RENDER_PRIMITIVE_LINES ,
RD : : RENDER_PRIMITIVE_POINTS ,
RD : : RENDER_PRIMITIVE_TRIANGLES ,
RD : : RENDER_PRIMITIVE_LINES ,
RD : : RENDER_PRIMITIVE_POINTS ,
} ;
ShaderVariant shader_variants [ PIPELINE_VARIANT_MAX ] = {
SHADER_VARIANT_QUAD ,
SHADER_VARIANT_NINEPATCH ,
SHADER_VARIANT_PRIMITIVE ,
SHADER_VARIANT_PRIMITIVE ,
SHADER_VARIANT_PRIMITIVE_POINTS ,
SHADER_VARIANT_ATTRIBUTES ,
SHADER_VARIANT_ATTRIBUTES ,
SHADER_VARIANT_ATTRIBUTES_POINTS
} ;
2019-06-16 10:45:24 +08:00
RID shader_variant = shader . canvas_shader . version_get_shader ( shader . default_version , shader_variants [ j ] ) ;
2019-06-25 03:13:06 +08:00
shader . pipeline_variants . variants [ i ] [ j ] . setup ( shader_variant , fb_format , primitive [ j ] , RD : : PipelineRasterizationState ( ) , RD : : PipelineMultisampleState ( ) , RD : : PipelineDepthStencilState ( ) , RD : : PipelineColorBlendState : : create_blend ( ) , 0 ) ;
2019-06-16 10:45:24 +08:00
}
}
shader . default_version_rd_shader = shader . canvas_shader . version_get_shader ( shader . default_version , 0 ) ;
}
2019-07-05 09:54:32 +08:00
{ //shadow rendering
Vector < String > versions ;
versions . push_back ( String ( ) ) ; //no versions
shadow_render . shader . initialize ( versions ) ;
{
Vector < RD : : AttachmentFormat > attachments ;
RD : : AttachmentFormat af_color ;
af_color . format = RD : : DATA_FORMAT_R32_SFLOAT ;
af_color . usage_flags = RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_COLOR_ATTACHMENT_BIT ;
attachments . push_back ( af_color ) ;
shadow_render . framebuffer_fix_format = RD : : get_singleton ( ) - > framebuffer_format_create ( attachments ) ;
RD : : AttachmentFormat af_depth ;
af_depth . format = RD : : DATA_FORMAT_D24_UNORM_S8_UINT ;
af_depth . format = RD : : get_singleton ( ) - > texture_is_format_supported_for_usage ( RD : : DATA_FORMAT_X8_D24_UNORM_PACK32 , RD : : TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) ? RD : : DATA_FORMAT_X8_D24_UNORM_PACK32 : RD : : DATA_FORMAT_D32_SFLOAT ;
af_depth . usage_flags = RD : : TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ;
attachments . push_back ( af_depth ) ;
shadow_render . framebuffer_format = RD : : get_singleton ( ) - > framebuffer_format_create ( attachments ) ;
}
//pipelines
Vector < RD : : VertexDescription > vf ;
RD : : VertexDescription vd ;
vd . format = RD : : DATA_FORMAT_R32G32B32_SFLOAT ;
vd . location = 0 ;
vd . offset = 0 ;
vd . stride = sizeof ( float ) * 3 ;
vf . push_back ( vd ) ;
shadow_render . vertex_format = RD : : get_singleton ( ) - > vertex_format_create ( vf ) ;
shadow_render . shader_version = shadow_render . shader . version_create ( ) ;
for ( int i = 0 ; i < 3 ; i + + ) {
RD : : PipelineRasterizationState rs ;
rs . cull_mode = i = = 0 ? RD : : POLYGON_CULL_DISABLED : ( i = = 1 ? RD : : POLYGON_CULL_FRONT : RD : : POLYGON_CULL_BACK ) ;
RD : : PipelineDepthStencilState ds ;
ds . enable_depth_write = true ;
ds . enable_depth_test = true ;
ds . depth_compare_operator = RD : : COMPARE_OP_LESS ;
shadow_render . render_pipelines [ i ] = RD : : get_singleton ( ) - > render_pipeline_create ( shadow_render . shader . version_get_shader ( shadow_render . shader_version , 0 ) , shadow_render . framebuffer_format , shadow_render . vertex_format , RD : : RENDER_PRIMITIVE_TRIANGLES , rs , RD : : PipelineMultisampleState ( ) , ds , RD : : PipelineColorBlendState : : create_disabled ( ) , 0 ) ;
}
shadow_render . shader_fix . initialize ( versions ) ;
shadow_render . shader_fix_version = shadow_render . shader_fix . version_create ( ) ;
shadow_render . shader_fix_pipeline = RD : : get_singleton ( ) - > render_pipeline_create ( shadow_render . shader_fix . version_get_shader ( shadow_render . shader_fix_version , 0 ) , shadow_render . framebuffer_fix_format , RD : : INVALID_ID , RD : : RENDER_PRIMITIVE_TRIANGLES , RD : : PipelineRasterizationState ( ) , RD : : PipelineMultisampleState ( ) , RD : : PipelineDepthStencilState ( ) , RD : : PipelineColorBlendState : : create_disabled ( ) , 0 ) ;
}
2019-06-16 10:45:24 +08:00
{ //bindings
bindings . id_generator = 0 ;
//generate for 0
bindings . default_empty = request_texture_binding ( RID ( ) , RID ( ) , RID ( ) , VS : : CANVAS_ITEM_TEXTURE_FILTER_DEFAULT , VS : : CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT , RID ( ) ) ;
{ //state allocate
state . canvas_state_buffer = RD : : get_singleton ( ) - > uniform_buffer_create ( sizeof ( State : : Buffer ) ) ;
2019-07-05 09:54:32 +08:00
state . lights_uniform_buffer = RD : : get_singleton ( ) - > uniform_buffer_create ( sizeof ( LightUniform ) * MAX_RENDER_LIGHTS ) ;
2019-06-16 10:45:24 +08:00
}
}
2019-06-25 03:13:06 +08:00
{
//polygon buffers
polygon_buffers . last_id = 1 ;
}
2019-06-16 10:45:24 +08:00
{ // default index buffer
PoolVector < uint8_t > pv ;
pv . resize ( 6 * 4 ) ;
{
PoolVector < uint8_t > : : Write w = pv . write ( ) ;
int * p32 = ( int * ) w . ptr ( ) ;
p32 [ 0 ] = 0 ;
p32 [ 1 ] = 1 ;
p32 [ 2 ] = 2 ;
p32 [ 3 ] = 0 ;
p32 [ 4 ] = 2 ;
p32 [ 5 ] = 3 ;
}
2019-06-25 03:13:06 +08:00
shader . quad_index_buffer = RD : : get_singleton ( ) - > index_buffer_create ( 6 , RenderingDevice : : INDEX_BUFFER_FORMAT_UINT32 , pv ) ;
shader . quad_index_array = RD : : get_singleton ( ) - > index_array_create ( shader . quad_index_buffer , 0 , 6 ) ;
}
{ //primitive
primitive_arrays . index_array [ 0 ] = shader . quad_index_array = RD : : get_singleton ( ) - > index_array_create ( shader . quad_index_buffer , 0 , 1 ) ;
primitive_arrays . index_array [ 1 ] = shader . quad_index_array = RD : : get_singleton ( ) - > index_array_create ( shader . quad_index_buffer , 0 , 2 ) ;
primitive_arrays . index_array [ 2 ] = shader . quad_index_array = RD : : get_singleton ( ) - > index_array_create ( shader . quad_index_buffer , 0 , 3 ) ;
primitive_arrays . index_array [ 3 ] = shader . quad_index_array = RD : : get_singleton ( ) - > index_array_create ( shader . quad_index_buffer , 0 , 6 ) ;
2019-06-16 10:45:24 +08:00
}
{ //default skeleton buffer
2019-06-25 03:13:06 +08:00
shader . default_skeleton_uniform = RD : : get_singleton ( ) - > uniform_buffer_create ( sizeof ( SkeletonUniform ) ) ;
2019-06-16 10:45:24 +08:00
SkeletonUniform su ;
_update_transform_2d_to_mat4 ( Transform2D ( ) , su . skeleton_inverse ) ;
_update_transform_2d_to_mat4 ( Transform2D ( ) , su . skeleton_transform ) ;
2019-06-25 03:13:06 +08:00
RD : : get_singleton ( ) - > buffer_update ( shader . default_skeleton_uniform , 0 , sizeof ( SkeletonUniform ) , & su ) ;
2019-06-16 10:45:24 +08:00
}
{ //default material uniform set
Vector < RD : : Uniform > default_material_uniforms ;
RD : : Uniform u ;
u . type = RD : : UNIFORM_TYPE_UNIFORM_BUFFER ;
u . binding = 2 ;
2019-06-25 03:13:06 +08:00
u . ids . push_back ( shader . default_skeleton_uniform ) ;
2019-06-16 10:45:24 +08:00
default_material_uniforms . push_back ( u ) ;
u . ids . clear ( ) ;
u . type = RD : : UNIFORM_TYPE_TEXTURE_BUFFER ;
u . binding = 1 ;
u . ids . push_back ( default_textures . default_multimesh_tb ) ;
default_material_uniforms . push_back ( u ) ;
2019-06-25 03:13:06 +08:00
shader . default_skeleton_uniform_set = RD : : get_singleton ( ) - > uniform_set_create ( default_material_uniforms , shader . canvas_shader . version_get_shader ( shader . default_version , SHADER_VARIANT_ATTRIBUTES ) , 2 ) ;
2019-06-16 10:45:24 +08:00
}
ERR_FAIL_COND ( sizeof ( PushConstant ) ! = 128 ) ;
}
2019-06-25 03:13:06 +08:00
2019-07-05 09:54:32 +08:00
bool RasterizerCanvasRD : : free ( RID p_rid ) {
if ( canvas_light_owner . owns ( p_rid ) ) {
CanvasLight * cl = canvas_light_owner . getornull ( p_rid ) ;
ERR_FAIL_COND_V ( ! cl , false ) ;
light_set_use_shadow ( p_rid , false , 64 ) ;
canvas_light_owner . free ( p_rid ) ;
//canvas state uniform set needs updating
if ( state . canvas_state_uniform_set . is_valid ( ) & & RD : : get_singleton ( ) - > uniform_set_is_valid ( state . canvas_state_uniform_set ) ) {
RD : : get_singleton ( ) - > free ( state . canvas_state_uniform_set ) ;
}
} else if ( occluder_polygon_owner . owns ( p_rid ) ) {
occluder_polygon_set_shape_as_lines ( p_rid , PoolVector < Vector2 > ( ) ) ;
occluder_polygon_owner . free ( p_rid ) ;
} else {
return false ;
}
return true ;
}
2019-06-25 03:13:06 +08:00
RasterizerCanvasRD : : ~ RasterizerCanvasRD ( ) {
//canvas state
if ( state . canvas_state_buffer . is_valid ( ) ) {
RD : : get_singleton ( ) - > free ( state . canvas_state_buffer ) ;
}
if ( state . canvas_state_uniform_set . is_valid ( ) & & RD : : get_singleton ( ) - > uniform_set_is_valid ( state . canvas_state_uniform_set ) ) {
RD : : get_singleton ( ) - > free ( state . canvas_state_uniform_set ) ;
}
//bindings
{
free_texture_binding ( bindings . default_empty ) ;
//dispose pending
_dispose_bindings ( ) ;
//anything remains?
if ( bindings . texture_bindings . size ( ) ) {
ERR_PRINT ( " Some texture bindings were not properly freed (leaked canvasitems? " ) ;
const TextureBindingID * key = NULL ;
while ( ( key = bindings . texture_bindings . next ( key ) ) ) {
TextureBinding * tb = bindings . texture_bindings [ * key ] ;
tb - > reference_count = 1 ;
free_texture_binding ( * key ) ;
}
//dispose pending
_dispose_bindings ( ) ;
}
}
//shaders
RD : : get_singleton ( ) - > free ( shader . default_skeleton_uniform_set ) ;
RD : : get_singleton ( ) - > free ( shader . default_skeleton_uniform ) ;
shader . canvas_shader . version_free ( shader . default_version ) ;
//buffers
RD : : get_singleton ( ) - > free ( shader . quad_index_array ) ;
RD : : get_singleton ( ) - > free ( shader . quad_index_buffer ) ;
//pipelines don't need freeing, they are all gone after shaders are gone
//samplers
for ( int i = 1 ; i < VS : : CANVAS_ITEM_TEXTURE_FILTER_MAX ; i + + ) {
for ( int j = 1 ; j < VS : : CANVAS_ITEM_TEXTURE_REPEAT_MAX ; j + + ) {
RD : : get_singleton ( ) - > free ( default_samplers . samplers [ i ] [ j ] ) ;
}
}
//textures
RD : : get_singleton ( ) - > free ( default_textures . white_texture ) ;
RD : : get_singleton ( ) - > free ( default_textures . black_texture ) ;
RD : : get_singleton ( ) - > free ( default_textures . normal_texture ) ;
RD : : get_singleton ( ) - > free ( default_textures . aniso_texture ) ;
RD : : get_singleton ( ) - > free ( default_textures . default_multimesh_tb ) ;
}