2023-12-14 21:54:22 +01:00
/*************************************************************************/
/* rasterizer_scene_gles2.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
# include "rasterizer_scene_gles2.h"
2023-12-15 14:53:15 +01:00
# include "core/config/project_settings.h"
# include "core/containers/vmap.h"
2023-12-14 21:54:22 +01:00
# include "core/math/math_funcs.h"
# include "core/math/transform.h"
# include "core/os/os.h"
# include "rasterizer_canvas_gles2.h"
# include "servers/rendering/rendering_server_raster.h"
# ifndef GLES_OVER_GL
# define glClearDepth glClearDepthf
# endif
# ifndef GLES_OVER_GL
# ifdef IPHONE_ENABLED
# include <OpenGLES/ES2/glext.h>
//void *glResolveMultisampleFramebufferAPPLE;
# define GL_READ_FRAMEBUFFER 0x8CA8
# define GL_DRAW_FRAMEBUFFER 0x8CA9
# endif
# endif
////////////////////////////
2023-12-15 19:36:14 +01:00
void RasterizerSceneGLES2 : : _add_geometry ( RasterizerStorageGLES2 : : Geometry * p_geometry , InstanceBase * p_instance , RasterizerStorageGLES2 : : GeometryOwner * p_owner , int p_material , bool p_depth_pass ) {
2023-12-14 21:54:22 +01:00
RasterizerStorageGLES2 : : Material * material = nullptr ;
RID material_src ;
if ( p_instance - > material_override . is_valid ( ) ) {
material_src = p_instance - > material_override ;
} else if ( p_material > = 0 ) {
material_src = p_instance - > materials [ p_material ] ;
} else {
material_src = p_geometry - > material ;
}
if ( material_src . is_valid ( ) ) {
material = storage - > material_owner . getornull ( material_src ) ;
if ( ! material - > shader | | ! material - > shader - > valid ) {
material = nullptr ;
}
}
if ( ! material ) {
material = storage - > material_owner . getptr ( default_material ) ;
}
ERR_FAIL_COND ( ! material ) ;
2023-12-15 19:36:14 +01:00
_add_geometry_with_material ( p_geometry , p_instance , p_owner , material , p_depth_pass ) ;
2023-12-14 21:54:22 +01:00
while ( material - > next_pass . is_valid ( ) ) {
material = storage - > material_owner . getornull ( material - > next_pass ) ;
if ( ! material | | ! material - > shader | | ! material - > shader - > valid ) {
break ;
}
2023-12-15 19:36:14 +01:00
_add_geometry_with_material ( p_geometry , p_instance , p_owner , material , p_depth_pass ) ;
2023-12-14 21:54:22 +01:00
}
// Repeat the "nested chain" logic also for the overlay
if ( p_instance - > material_overlay . is_valid ( ) ) {
material = storage - > material_owner . getornull ( p_instance - > material_overlay ) ;
if ( ! material | | ! material - > shader | | ! material - > shader - > valid ) {
return ;
}
2023-12-15 19:36:14 +01:00
_add_geometry_with_material ( p_geometry , p_instance , p_owner , material , p_depth_pass ) ;
2023-12-14 21:54:22 +01:00
while ( material - > next_pass . is_valid ( ) ) {
material = storage - > material_owner . getornull ( material - > next_pass ) ;
if ( ! material | | ! material - > shader | | ! material - > shader - > valid ) {
break ;
}
2023-12-15 19:36:14 +01:00
_add_geometry_with_material ( p_geometry , p_instance , p_owner , material , p_depth_pass ) ;
2023-12-14 21:54:22 +01:00
}
}
}
2023-12-15 19:36:14 +01:00
void RasterizerSceneGLES2 : : _add_geometry_with_material ( RasterizerStorageGLES2 : : Geometry * p_geometry , InstanceBase * p_instance , RasterizerStorageGLES2 : : GeometryOwner * p_owner , RasterizerStorageGLES2 : : Material * p_material , bool p_depth_pass ) {
2023-12-14 21:54:22 +01:00
bool has_base_alpha = ( p_material - > shader - > spatial . uses_alpha & & ! p_material - > shader - > spatial . uses_alpha_scissor ) | | p_material - > shader - > spatial . uses_screen_texture | | p_material - > shader - > spatial . uses_depth_texture ;
bool has_blend_alpha = p_material - > shader - > spatial . blend_mode ! = RasterizerStorageGLES2 : : Shader : : Spatial : : BLEND_MODE_MIX ;
bool has_alpha = has_base_alpha | | has_blend_alpha ;
bool mirror = p_instance - > mirror ;
if ( p_material - > shader - > spatial . cull_mode = = RasterizerStorageGLES2 : : Shader : : Spatial : : CULL_MODE_DISABLED ) {
mirror = false ;
} else if ( p_material - > shader - > spatial . cull_mode = = RasterizerStorageGLES2 : : Shader : : Spatial : : CULL_MODE_FRONT ) {
mirror = ! mirror ;
}
//if (p_material->shader->spatial.uses_sss) {
// state.used_sss = true;
//}
if ( p_material - > shader - > spatial . uses_screen_texture ) {
state . used_screen_texture = true ;
}
if ( p_depth_pass ) {
if ( has_blend_alpha | | p_material - > shader - > spatial . uses_depth_texture | | ( has_base_alpha & & p_material - > shader - > spatial . depth_draw_mode ! = RasterizerStorageGLES2 : : Shader : : Spatial : : DEPTH_DRAW_ALPHA_PREPASS ) ) {
return ; //bye
}
if ( ! p_material - > shader - > spatial . uses_alpha_scissor & & ! p_material - > shader - > spatial . writes_modelview_or_projection & & ! p_material - > shader - > spatial . uses_vertex & & ! p_material - > shader - > spatial . uses_discard & & p_material - > shader - > spatial . depth_draw_mode ! = RasterizerStorageGLES2 : : Shader : : Spatial : : DEPTH_DRAW_ALPHA_PREPASS ) {
//shader does not use discard and does not write a vertex position, use generic material
2023-12-15 19:36:14 +01:00
p_material = storage - > material_owner . getptr ( p_material - > shader - > spatial . uses_world_coordinates ? default_worldcoord_material : default_material ) ;
2023-12-14 21:54:22 +01:00
}
has_alpha = false ;
}
RenderList : : Element * e = ( has_alpha | | p_material - > shader - > spatial . no_depth_test ) ? render_list . add_alpha_element ( ) : render_list . add_element ( ) ;
if ( ! e ) {
return ;
}
e - > geometry = p_geometry ;
e - > material = p_material ;
e - > instance = p_instance ;
e - > owner = p_owner ;
e - > sort_key = 0 ;
e - > depth_key = 0 ;
e - > use_accum = false ;
e - > light_index = RenderList : : MAX_LIGHTS ;
e - > use_accum_ptr = & e - > use_accum ;
e - > instancing = ( e - > instance - > base_type = = RS : : INSTANCE_MULTIMESH ) ? 1 : 0 ;
e - > front_facing = false ;
if ( e - > geometry - > last_pass ! = render_pass ) {
e - > geometry - > last_pass = render_pass ;
e - > geometry - > index = current_geometry_index + + ;
}
e - > geometry_index = e - > geometry - > index ;
if ( e - > material - > last_pass ! = render_pass ) {
e - > material - > last_pass = render_pass ;
e - > material - > index = current_material_index + + ;
if ( e - > material - > shader - > last_pass ! = render_pass ) {
e - > material - > shader - > index = current_shader_index + + ;
}
}
e - > material_index = e - > material - > index ;
if ( mirror ) {
e - > front_facing = true ;
}
if ( ! p_depth_pass ) {
e - > depth_layer = e - > instance - > depth_layer ;
e - > priority = p_material - > render_priority ;
if ( has_alpha & & p_material - > shader - > spatial . depth_draw_mode = = RasterizerStorageGLES2 : : Shader : : Spatial : : DEPTH_DRAW_ALPHA_PREPASS ) {
//add element to opaque
RenderList : : Element * eo = render_list . add_element ( ) ;
* eo = * e ;
eo - > use_accum_ptr = & eo - > use_accum ;
}
//add directional lights
2023-12-15 18:11:18 +01:00
e - > light_mode = LIGHTMODE_UNSHADED ;
2023-12-14 21:54:22 +01:00
}
// do not add anything here, as lights are duplicated elements..
if ( p_material - > shader - > spatial . uses_time ) {
RenderingServerRaster : : redraw_request ( false ) ;
}
}
void RasterizerSceneGLES2 : : _copy_texture_to_buffer ( GLuint p_texture , GLuint p_buffer ) {
//copy to front buffer
glBindFramebuffer ( GL_FRAMEBUFFER , p_buffer ) ;
glDepthMask ( GL_FALSE ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_CULL_FACE ) ;
glDisable ( GL_BLEND ) ;
glDepthFunc ( GL_LEQUAL ) ;
glColorMask ( 1 , 1 , 1 , 1 ) ;
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , p_texture ) ;
glViewport ( 0 , 0 , storage - > frame . current_rt - > width , storage - > frame . current_rt - > height ) ;
storage - > shaders . copy . bind ( ) ;
storage - > bind_quad_array ( ) ;
glDrawArrays ( GL_TRIANGLE_FAN , 0 , 4 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
}
2023-12-15 19:36:14 +01:00
void RasterizerSceneGLES2 : : _fill_render_list ( InstanceBase * * p_cull_result , int p_cull_count , bool p_depth_pass ) {
2023-12-14 21:54:22 +01:00
render_pass + + ;
current_material_index = 0 ;
current_geometry_index = 0 ;
current_shader_index = 0 ;
for ( int i = 0 ; i < p_cull_count ; i + + ) {
InstanceBase * instance = p_cull_result [ i ] ;
switch ( instance - > base_type ) {
case RS : : INSTANCE_MESH : {
RasterizerStorageGLES2 : : Mesh * mesh = storage - > mesh_owner . getornull ( instance - > base ) ;
ERR_CONTINUE ( ! mesh ) ;
int num_surfaces = mesh - > surfaces . size ( ) ;
for ( int j = 0 ; j < num_surfaces ; j + + ) {
int material_index = instance - > materials [ j ] . is_valid ( ) ? j : - 1 ;
RasterizerStorageGLES2 : : Surface * surface = mesh - > surfaces [ j ] ;
2023-12-15 19:36:14 +01:00
_add_geometry ( surface , instance , nullptr , material_index , p_depth_pass ) ;
2023-12-14 21:54:22 +01:00
}
} break ;
case RS : : INSTANCE_MULTIMESH : {
RasterizerStorageGLES2 : : MultiMesh * multi_mesh = storage - > multimesh_owner . getptr ( instance - > base ) ;
ERR_CONTINUE ( ! multi_mesh ) ;
if ( multi_mesh - > size = = 0 | | multi_mesh - > visible_instances = = 0 ) {
continue ;
}
RasterizerStorageGLES2 : : Mesh * mesh = storage - > mesh_owner . getptr ( multi_mesh - > mesh ) ;
if ( ! mesh ) {
continue ;
}
int ssize = mesh - > surfaces . size ( ) ;
for ( int j = 0 ; j < ssize ; j + + ) {
RasterizerStorageGLES2 : : Surface * s = mesh - > surfaces [ j ] ;
2023-12-15 19:36:14 +01:00
_add_geometry ( s , instance , multi_mesh , - 1 , p_depth_pass ) ;
2023-12-14 21:54:22 +01:00
}
} break ;
default : {
}
}
}
}
const GLenum RasterizerSceneGLES2 : : gl_primitive [ ] = {
GL_POINTS ,
GL_LINES ,
GL_LINE_STRIP ,
GL_LINE_LOOP ,
GL_TRIANGLES ,
GL_TRIANGLE_STRIP ,
GL_TRIANGLE_FAN
} ;
void RasterizerSceneGLES2 : : _set_cull ( bool p_front , bool p_disabled , bool p_reverse_cull ) {
bool front = p_front ;
if ( p_reverse_cull ) {
front = ! front ;
}
if ( p_disabled ! = state . cull_disabled ) {
if ( p_disabled ) {
glDisable ( GL_CULL_FACE ) ;
} else {
glEnable ( GL_CULL_FACE ) ;
}
state . cull_disabled = p_disabled ;
}
if ( front ! = state . cull_front ) {
glCullFace ( front ? GL_FRONT : GL_BACK ) ;
state . cull_front = front ;
}
}
bool RasterizerSceneGLES2 : : _setup_material ( RasterizerStorageGLES2 : : Material * p_material , bool p_alpha_pass , Size2i p_skeleton_tex_size ) {
// material parameters
state . scene_shader . set_custom_shader ( p_material - > shader - > custom_code_id ) ;
if ( p_material - > shader - > spatial . uses_screen_texture & & storage - > frame . current_rt ) {
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 + storage - > config . max_texture_image_units - 4 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > frame . current_rt - > copy_screen_effect . color ) ;
}
if ( p_material - > shader - > spatial . uses_depth_texture & & storage - > frame . current_rt ) {
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 + storage - > config . max_texture_image_units - 4 ) ;
glBindTexture ( GL_TEXTURE_2D , storage - > frame . current_rt - > depth ) ;
}
bool shader_rebind = state . scene_shader . bind ( ) ;
if ( p_material - > shader - > spatial . no_depth_test | | p_material - > shader - > spatial . uses_depth_texture ) {
glDisable ( GL_DEPTH_TEST ) ;
} else {
glEnable ( GL_DEPTH_TEST ) ;
}
switch ( p_material - > shader - > spatial . depth_draw_mode ) {
case RasterizerStorageGLES2 : : Shader : : Spatial : : DEPTH_DRAW_ALPHA_PREPASS :
case RasterizerStorageGLES2 : : Shader : : Spatial : : DEPTH_DRAW_OPAQUE : {
glDepthMask ( ! p_alpha_pass & & ! p_material - > shader - > spatial . uses_depth_texture ) ;
} break ;
case RasterizerStorageGLES2 : : Shader : : Spatial : : DEPTH_DRAW_ALWAYS : {
glDepthMask ( GL_TRUE & & ! p_material - > shader - > spatial . uses_depth_texture ) ;
} break ;
case RasterizerStorageGLES2 : : Shader : : Spatial : : DEPTH_DRAW_NEVER : {
glDepthMask ( GL_FALSE ) ;
} break ;
}
int tc = p_material - > textures . size ( ) ;
const Pair < StringName , RID > * textures = p_material - > textures . ptr ( ) ;
const ShaderLanguage : : ShaderNode : : Uniform : : Hint * texture_hints = p_material - > shader - > texture_hints . ptr ( ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : SKELETON_TEXTURE_SIZE , p_skeleton_tex_size ) ;
state . current_main_tex = 0 ;
for ( int i = 0 ; i < tc ; i + + ) {
WRAPPED_GL_ACTIVE_TEXTURE ( GL_TEXTURE0 + i ) ;
RasterizerStorageGLES2 : : Texture * t = storage - > texture_owner . getornull ( textures [ i ] . second ) ;
if ( ! t ) {
switch ( texture_hints [ i ] ) {
case ShaderLanguage : : ShaderNode : : Uniform : : HINT_BLACK_ALBEDO :
case ShaderLanguage : : ShaderNode : : Uniform : : HINT_BLACK : {
glBindTexture ( GL_TEXTURE_2D , storage - > resources . black_tex ) ;
} break ;
case ShaderLanguage : : ShaderNode : : Uniform : : HINT_TRANSPARENT : {
glBindTexture ( GL_TEXTURE_2D , storage - > resources . transparent_tex ) ;
} break ;
case ShaderLanguage : : ShaderNode : : Uniform : : HINT_ANISO : {
glBindTexture ( GL_TEXTURE_2D , storage - > resources . aniso_tex ) ;
} break ;
case ShaderLanguage : : ShaderNode : : Uniform : : HINT_NORMAL : {
glBindTexture ( GL_TEXTURE_2D , storage - > resources . normal_tex ) ;
} break ;
default : {
glBindTexture ( GL_TEXTURE_2D , storage - > resources . white_tex ) ;
} break ;
}
continue ;
}
if ( t - > redraw_if_visible ) { //must check before proxy because this is often used with proxies
RenderingServerRaster : : redraw_request ( false ) ;
}
t = t - > get_ptr ( ) ;
# ifdef TOOLS_ENABLED
if ( t - > detect_3d ) {
t - > detect_3d ( t - > detect_3d_ud ) ;
}
# endif
# ifdef TOOLS_ENABLED
if ( t - > detect_normal & & texture_hints [ i ] = = ShaderLanguage : : ShaderNode : : Uniform : : HINT_NORMAL ) {
t - > detect_normal ( t - > detect_normal_ud ) ;
}
# endif
if ( t - > render_target ) {
t - > render_target - > used_in_frame = true ;
}
glBindTexture ( t - > target , t - > tex_id ) ;
if ( i = = 0 ) {
state . current_main_tex = t - > tex_id ;
}
}
state . scene_shader . use_material ( ( void * ) p_material ) ;
return shader_rebind ;
}
2023-12-15 16:48:56 +01:00
void RasterizerSceneGLES2 : : _setup_geometry ( RenderList : : Element * p_element ) {
2023-12-14 21:54:22 +01:00
switch ( p_element - > instance - > base_type ) {
case RS : : INSTANCE_MESH : {
RasterizerStorageGLES2 : : Surface * s = static_cast < RasterizerStorageGLES2 : : Surface * > ( p_element - > geometry ) ;
if ( s - > index_array_len > 0 ) {
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , s - > index_id ) ;
}
for ( int i = 0 ; i < RS : : ARRAY_MAX - 1 ; i + + ) {
if ( s - > attribs [ i ] . enabled ) {
glEnableVertexAttribArray ( i ) ;
if ( ! s - > blend_shape_data . empty ( ) & & i ! = RS : : ARRAY_BONES & & s - > blend_shape_buffer_size > 0 ) {
glBindBuffer ( GL_ARRAY_BUFFER , s - > blend_shape_buffer_id ) ;
// When using octahedral compression (2 component normal/tangent)
// decompression changes the component count to 3/4
int size ;
switch ( i ) {
case RS : : ARRAY_NORMAL : {
size = 3 ;
} break ;
case RS : : ARRAY_TANGENT : {
size = 4 ;
} break ;
default :
size = s - > attribs [ i ] . size ;
}
glVertexAttribPointer ( s - > attribs [ i ] . index , size , GL_FLOAT , GL_FALSE , 8 * 4 * sizeof ( float ) , CAST_INT_TO_UCHAR_PTR ( i * 4 * sizeof ( float ) ) ) ;
} else {
glBindBuffer ( GL_ARRAY_BUFFER , s - > vertex_id ) ;
glVertexAttribPointer ( s - > attribs [ i ] . index , s - > attribs [ i ] . size , s - > attribs [ i ] . type , s - > attribs [ i ] . normalized , s - > attribs [ i ] . stride , CAST_INT_TO_UCHAR_PTR ( s - > attribs [ i ] . offset ) ) ;
}
} else {
glDisableVertexAttribArray ( i ) ;
switch ( i ) {
case RS : : ARRAY_NORMAL : {
glVertexAttrib4f ( RS : : ARRAY_NORMAL , 0.0 , 0.0 , 1 , 1 ) ;
} break ;
case RS : : ARRAY_COLOR : {
glVertexAttrib4f ( RS : : ARRAY_COLOR , 1 , 1 , 1 , 1 ) ;
} break ;
default : {
}
}
}
}
} break ;
case RS : : INSTANCE_MULTIMESH : {
RasterizerStorageGLES2 : : Surface * s = static_cast < RasterizerStorageGLES2 : : Surface * > ( p_element - > geometry ) ;
glBindBuffer ( GL_ARRAY_BUFFER , s - > vertex_id ) ;
if ( s - > index_array_len > 0 ) {
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , s - > index_id ) ;
}
for ( int i = 0 ; i < RS : : ARRAY_MAX - 1 ; i + + ) {
if ( s - > attribs [ i ] . enabled ) {
glEnableVertexAttribArray ( i ) ;
glVertexAttribPointer ( s - > attribs [ i ] . index , s - > attribs [ i ] . size , s - > attribs [ i ] . type , s - > attribs [ i ] . normalized , s - > attribs [ i ] . stride , CAST_INT_TO_UCHAR_PTR ( s - > attribs [ i ] . offset ) ) ;
} else {
glDisableVertexAttribArray ( i ) ;
switch ( i ) {
case RS : : ARRAY_NORMAL : {
glVertexAttrib4f ( RS : : ARRAY_NORMAL , 0.0 , 0.0 , 1 , 1 ) ;
} break ;
case RS : : ARRAY_COLOR : {
glVertexAttrib4f ( RS : : ARRAY_COLOR , 1 , 1 , 1 , 1 ) ;
} break ;
default : {
}
}
}
}
// prepare multimesh (disable)
glDisableVertexAttribArray ( INSTANCE_ATTRIB_BASE + 0 ) ;
glDisableVertexAttribArray ( INSTANCE_ATTRIB_BASE + 1 ) ;
glDisableVertexAttribArray ( INSTANCE_ATTRIB_BASE + 2 ) ;
glDisableVertexAttribArray ( INSTANCE_ATTRIB_BASE + 3 ) ;
glDisableVertexAttribArray ( INSTANCE_ATTRIB_BASE + 4 ) ;
glDisableVertexAttribArray ( INSTANCE_BONE_BASE + 0 ) ;
glDisableVertexAttribArray ( INSTANCE_BONE_BASE + 1 ) ;
glDisableVertexAttribArray ( INSTANCE_BONE_BASE + 2 ) ;
} break ;
default : {
}
}
}
void RasterizerSceneGLES2 : : _render_geometry ( RenderList : : Element * p_element ) {
switch ( p_element - > instance - > base_type ) {
case RS : : INSTANCE_MESH : {
RasterizerStorageGLES2 : : Surface * s = static_cast < RasterizerStorageGLES2 : : Surface * > ( p_element - > geometry ) ;
// drawing
if ( s - > index_array_len > 0 ) {
glDrawElements ( gl_primitive [ s - > primitive ] , s - > index_array_len , ( s - > array_len > = ( 1 < < 16 ) ) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT , nullptr ) ;
storage - > info . render . vertices_count + = s - > index_array_len ;
} else {
glDrawArrays ( gl_primitive [ s - > primitive ] , 0 , s - > array_len ) ;
storage - > info . render . vertices_count + = s - > array_len ;
}
/*
if ( p_element - > instance - > skeleton . is_valid ( ) & & s - > attribs [ RS : : ARRAY_BONES ] . enabled & & s - > attribs [ RS : : ARRAY_WEIGHTS ] . enabled ) {
//clean up after skeleton
glBindBuffer ( GL_ARRAY_BUFFER , storage - > resources . skeleton_transform_buffer ) ;
glDisableVertexAttribArray ( RS : : ARRAY_MAX + 0 ) ;
glDisableVertexAttribArray ( RS : : ARRAY_MAX + 1 ) ;
glDisableVertexAttribArray ( RS : : ARRAY_MAX + 2 ) ;
glVertexAttrib4f ( RS : : ARRAY_MAX + 0 , 1 , 0 , 0 , 0 ) ;
glVertexAttrib4f ( RS : : ARRAY_MAX + 1 , 0 , 1 , 0 , 0 ) ;
glVertexAttrib4f ( RS : : ARRAY_MAX + 2 , 0 , 0 , 1 , 0 ) ;
}
*/
} break ;
case RS : : INSTANCE_MULTIMESH : {
RasterizerStorageGLES2 : : MultiMesh * multi_mesh = static_cast < RasterizerStorageGLES2 : : MultiMesh * > ( p_element - > owner ) ;
RasterizerStorageGLES2 : : Surface * s = static_cast < RasterizerStorageGLES2 : : Surface * > ( p_element - > geometry ) ;
int amount = MIN ( multi_mesh - > size , multi_mesh - > visible_instances ) ;
if ( amount = = - 1 ) {
amount = multi_mesh - > size ;
}
if ( ! amount ) {
return ;
}
int stride = multi_mesh - > color_floats + multi_mesh - > custom_data_floats + multi_mesh - > xform_floats ;
int color_ofs = multi_mesh - > xform_floats ;
int custom_data_ofs = color_ofs + multi_mesh - > color_floats ;
// drawing
const float * base_buffer = multi_mesh - > data . ptr ( ) ;
for ( int i = 0 ; i < amount ; i + + ) {
const float * buffer = base_buffer + i * stride ;
{
glVertexAttrib4fv ( INSTANCE_ATTRIB_BASE + 0 , & buffer [ 0 ] ) ;
glVertexAttrib4fv ( INSTANCE_ATTRIB_BASE + 1 , & buffer [ 4 ] ) ;
glVertexAttrib4fv ( INSTANCE_ATTRIB_BASE + 2 , & buffer [ 8 ] ) ;
}
if ( multi_mesh - > color_floats ) {
if ( multi_mesh - > color_format = = RS : : MULTIMESH_COLOR_8BIT ) {
uint8_t * color_data = ( uint8_t * ) ( buffer + color_ofs ) ;
glVertexAttrib4f ( INSTANCE_ATTRIB_BASE + 3 , color_data [ 0 ] / 255.0 , color_data [ 1 ] / 255.0 , color_data [ 2 ] / 255.0 , color_data [ 3 ] / 255.0 ) ;
} else {
glVertexAttrib4fv ( INSTANCE_ATTRIB_BASE + 3 , buffer + color_ofs ) ;
}
} else {
glVertexAttrib4f ( INSTANCE_ATTRIB_BASE + 3 , 1.0 , 1.0 , 1.0 , 1.0 ) ;
}
if ( multi_mesh - > custom_data_floats ) {
if ( multi_mesh - > custom_data_format = = RS : : MULTIMESH_CUSTOM_DATA_8BIT ) {
uint8_t * custom_data = ( uint8_t * ) ( buffer + custom_data_ofs ) ;
glVertexAttrib4f ( INSTANCE_ATTRIB_BASE + 4 , custom_data [ 0 ] / 255.0 , custom_data [ 1 ] / 255.0 , custom_data [ 2 ] / 255.0 , custom_data [ 3 ] / 255.0 ) ;
} else {
glVertexAttrib4fv ( INSTANCE_ATTRIB_BASE + 4 , buffer + custom_data_ofs ) ;
}
}
if ( s - > index_array_len > 0 ) {
glDrawElements ( gl_primitive [ s - > primitive ] , s - > index_array_len , ( s - > array_len > = ( 1 < < 16 ) ) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT , nullptr ) ;
storage - > info . render . vertices_count + = s - > index_array_len ;
} else {
glDrawArrays ( gl_primitive [ s - > primitive ] , 0 , s - > array_len ) ;
storage - > info . render . vertices_count + = s - > array_len ;
}
}
} break ;
default : {
}
}
}
2023-12-15 19:36:14 +01:00
void RasterizerSceneGLES2 : : _render_render_list ( RenderList : : Element * * p_elements , int p_element_count , const Transform & p_view_transform , const Projection & p_projection , const int p_eye , bool p_reverse_cull , bool p_alpha_pass ) {
2023-12-14 21:54:22 +01:00
Vector2 viewport_size = state . viewport_size ;
Vector2 screen_pixel_size = state . screen_pixel_size ;
bool use_radiance_map = false ;
bool prev_unshaded = false ;
bool prev_instancing = false ;
bool prev_depth_prepass = false ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : SHADELESS , false ) ;
RasterizerStorageGLES2 : : Material * prev_material = nullptr ;
RasterizerStorageGLES2 : : Geometry * prev_geometry = nullptr ;
RasterizerStorageGLES2 : : GeometryOwner * prev_owner = nullptr ;
bool prev_octahedral_compression = false ;
Transform view_transform_inverse = p_view_transform . inverse ( ) ;
Projection projection_inverse = p_projection . inverse ( ) ;
bool prev_base_pass = false ;
bool prev_vertex_lit = false ;
int prev_blend_mode = - 2 ; //will always catch the first go
state . cull_front = false ;
state . cull_disabled = false ;
glCullFace ( GL_BACK ) ;
glEnable ( GL_CULL_FACE ) ;
if ( p_alpha_pass ) {
glEnable ( GL_BLEND ) ;
} else {
glDisable ( GL_BLEND ) ;
}
bool using_fog = false ;
storage - > info . render . draw_call_count + = p_element_count ;
for ( int i = 0 ; i < p_element_count ; i + + ) {
RenderList : : Element * e = p_elements [ i ] ;
RasterizerStorageGLES2 : : Material * material = e - > material ;
bool rebind = false ;
bool accum_pass = * e - > use_accum_ptr ;
* e - > use_accum_ptr = true ; //set to accum for next time this is found
2023-12-15 19:36:14 +01:00
if ( material - > shader ) {
2023-12-14 21:54:22 +01:00
bool unshaded = material - > shader - > spatial . unshaded ;
if ( unshaded ! = prev_unshaded ) {
rebind = true ;
if ( unshaded ) {
state . scene_shader . set_conditional ( SceneShaderGLES2 : : SHADELESS , true ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_RADIANCE_MAP , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_LIGHTING , false ) ;
} else {
state . scene_shader . set_conditional ( SceneShaderGLES2 : : SHADELESS , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_RADIANCE_MAP , use_radiance_map ) ;
}
prev_unshaded = unshaded ;
}
bool base_pass = ! accum_pass & & ! unshaded ; //conditions for a base pass
if ( base_pass ! = prev_base_pass ) {
state . scene_shader . set_conditional ( SceneShaderGLES2 : : BASE_PASS , base_pass ) ;
rebind = true ;
prev_base_pass = base_pass ;
}
int blend_mode = p_alpha_pass ? material - > shader - > spatial . blend_mode : - 1 ; // -1 no blend, no mix
if ( prev_blend_mode ! = blend_mode ) {
if ( prev_blend_mode = = - 1 & & blend_mode ! = - 1 ) {
//does blend
glEnable ( GL_BLEND ) ;
} else if ( blend_mode = = - 1 & & prev_blend_mode ! = - 1 ) {
//do not blend
glDisable ( GL_BLEND ) ;
}
switch ( blend_mode ) {
//-1 not handled because not blend is enabled anyway
case RasterizerStorageGLES2 : : Shader : : Spatial : : BLEND_MODE_MIX : {
glBlendEquation ( GL_FUNC_ADD ) ;
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 {
glBlendFuncSeparate ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA , GL_ZERO , GL_ONE ) ;
}
} break ;
case RasterizerStorageGLES2 : : Shader : : Spatial : : BLEND_MODE_ADD : {
glBlendEquation ( GL_FUNC_ADD ) ;
glBlendFunc ( p_alpha_pass ? GL_SRC_ALPHA : GL_ONE , GL_ONE ) ;
} break ;
case RasterizerStorageGLES2 : : Shader : : Spatial : : BLEND_MODE_SUB : {
glBlendEquation ( GL_FUNC_REVERSE_SUBTRACT ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE ) ;
} break ;
case RasterizerStorageGLES2 : : Shader : : Spatial : : BLEND_MODE_MUL : {
glBlendEquation ( GL_FUNC_ADD ) ;
if ( storage - > frame . current_rt & & storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_TRANSPARENT ] ) {
glBlendFuncSeparate ( GL_DST_COLOR , GL_ZERO , GL_DST_ALPHA , GL_ZERO ) ;
} else {
glBlendFuncSeparate ( GL_DST_COLOR , GL_ZERO , GL_ZERO , GL_ONE ) ;
}
} break ;
}
prev_blend_mode = blend_mode ;
}
//condition to enable vertex lighting on this object
2023-12-15 18:11:18 +01:00
bool vertex_lit = ( material - > shader - > spatial . uses_vertex_lighting | | storage - > config . force_vertex_shading ) & & ( ( ! unshaded ) | | using_fog ) ; //fog forces vertex lighting because it still applies even if unshaded or no fog
2023-12-14 21:54:22 +01:00
if ( vertex_lit ! = prev_vertex_lit ) {
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_VERTEX_LIGHTING , vertex_lit ) ;
prev_vertex_lit = vertex_lit ;
rebind = true ;
}
}
bool depth_prepass = false ;
if ( ! p_alpha_pass & & material - > shader - > spatial . depth_draw_mode = = RasterizerStorageGLES2 : : Shader : : Spatial : : DEPTH_DRAW_ALPHA_PREPASS ) {
depth_prepass = true ;
}
if ( depth_prepass ! = prev_depth_prepass ) {
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_DEPTH_PREPASS , depth_prepass ) ;
prev_depth_prepass = depth_prepass ;
rebind = true ;
}
bool instancing = e - > instance - > base_type = = RS : : INSTANCE_MULTIMESH ;
if ( instancing ! = prev_instancing ) {
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_INSTANCING , instancing ) ;
rebind = true ;
}
2023-12-15 16:48:56 +01:00
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_SKELETON , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_SKELETON_SOFTWARE , false ) ;
2023-12-14 21:54:22 +01:00
2023-12-15 16:48:56 +01:00
if ( e - > owner ! = prev_owner | | e - > geometry ! = prev_geometry ) {
_setup_geometry ( e ) ;
2023-12-14 21:54:22 +01:00
storage - > info . render . surface_switch_count + + ;
}
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_PHYSICAL_LIGHT_ATTENUATION , storage - > config . use_physical_light_attenuation ) ;
2023-12-15 17:00:35 +01:00
bool octahedral_compression = ( ( RasterizerStorageGLES2 : : Surface * ) e - > geometry ) - > format & RenderingServer : : ArrayFormat : : ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION & &
2023-12-14 21:54:22 +01:00
( ( ( RasterizerStorageGLES2 : : Surface * ) e - > geometry ) - > blend_shape_data . empty ( ) | | ( ( RasterizerStorageGLES2 : : Surface * ) e - > geometry ) - > blend_shape_buffer_size = = 0 ) ;
if ( octahedral_compression ! = prev_octahedral_compression ) {
state . scene_shader . set_conditional ( SceneShaderGLES2 : : ENABLE_OCTAHEDRAL_COMPRESSION , octahedral_compression ) ;
rebind = true ;
}
bool shader_rebind = false ;
if ( rebind | | material ! = prev_material ) {
storage - > info . render . material_switch_count + + ;
2023-12-15 16:48:56 +01:00
shader_rebind = _setup_material ( material , p_alpha_pass , Size2i ( 0 , 0 ) ) ;
2023-12-14 21:54:22 +01:00
if ( shader_rebind ) {
storage - > info . render . shader_rebind_count + + ;
}
}
_set_cull ( e - > front_facing , material - > shader - > spatial . cull_mode = = RasterizerStorageGLES2 : : Shader : : Spatial : : CULL_MODE_DISABLED , p_reverse_cull ) ;
if ( i = = 0 | | shader_rebind ) { //first time must rebind
2023-12-15 19:36:14 +01:00
if ( use_radiance_map ) {
// would be a bit weird if we don't have this...
state . scene_shader . set_uniform ( SceneShaderGLES2 : : RADIANCE_INVERSE_XFORM , p_view_transform ) ;
2023-12-14 21:54:22 +01:00
}
2023-12-15 19:36:14 +01:00
state . scene_shader . set_uniform ( SceneShaderGLES2 : : BG_ENERGY , 1.0 ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : BG_COLOR , state . default_bg ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : AMBIENT_SKY_CONTRIBUTION , 1.0 ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : AMBIENT_COLOR , state . default_ambient ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : AMBIENT_ENERGY , 1.0 ) ;
2023-12-14 21:54:22 +01:00
state . scene_shader . set_uniform ( SceneShaderGLES2 : : CAMERA_MATRIX , p_view_transform ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : CAMERA_INVERSE_MATRIX , view_transform_inverse ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : PROJECTION_MATRIX , p_projection ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : PROJECTION_INVERSE_MATRIX , projection_inverse ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : TIME , storage - > frame . time [ 0 ] ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : VIEW_INDEX , p_eye = = 2 ? 1 : 0 ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : VIEWPORT_SIZE , viewport_size ) ;
state . scene_shader . set_uniform ( SceneShaderGLES2 : : SCREEN_PIXEL_SIZE , screen_pixel_size ) ;
}
state . scene_shader . set_uniform ( SceneShaderGLES2 : : WORLD_TRANSFORM , e - > instance - > transform ) ;
_render_geometry ( e ) ;
prev_geometry = e - > geometry ;
prev_owner = e - > owner ;
prev_material = material ;
prev_instancing = instancing ;
prev_octahedral_compression = octahedral_compression ;
}
state . scene_shader . set_conditional ( SceneShaderGLES2 : : ENABLE_OCTAHEDRAL_COMPRESSION , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_SKELETON , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : SHADELESS , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : BASE_PASS , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_INSTANCING , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_RADIANCE_MAP , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : LIGHT_USE_PSSM4 , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : LIGHT_USE_PSSM3 , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : LIGHT_USE_PSSM2 , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : LIGHT_USE_PSSM_BLEND , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_VERTEX_LIGHTING , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_REFLECTION_PROBE1 , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_REFLECTION_PROBE2 , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : FOG_DEPTH_ENABLED , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : FOG_HEIGHT_ENABLED , false ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_DEPTH_PREPASS , false ) ;
}
2023-12-15 14:53:15 +01:00
void RasterizerSceneGLES2 : : _post_process ( const Projection & p_cam_projection ) {
2023-12-14 21:54:22 +01:00
//copy to front buffer
glDepthMask ( GL_FALSE ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_CULL_FACE ) ;
glDisable ( GL_BLEND ) ;
glDepthFunc ( GL_LEQUAL ) ;
glColorMask ( 1 , 1 , 1 , 1 ) ;
//no post process on small or render targets without an env
2023-12-15 14:53:15 +01:00
bool use_post_process = false ;
2023-12-14 21:54:22 +01:00
// If using multisample buffer, resolve to post_process_effect buffer or to front buffer
if ( storage - > frame . current_rt & & storage - > frame . current_rt - > multisample_active ) {
GLuint next_buffer ;
if ( use_post_process ) {
next_buffer = storage - > frame . current_rt - > mip_maps [ 0 ] . sizes [ 0 ] . fbo ;
} else if ( storage - > frame . current_rt - > external . fbo ! = 0 ) {
next_buffer = storage - > frame . current_rt - > external . fbo ;
} else {
// set next_buffer to front buffer so multisample blit can happen if needed
next_buffer = storage - > frame . current_rt - > fbo ;
}
# ifdef GLES_OVER_GL
glBindFramebuffer ( GL_READ_FRAMEBUFFER , storage - > frame . current_rt - > multisample_fbo ) ;
glReadBuffer ( GL_COLOR_ATTACHMENT0 ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , next_buffer ) ;
glBlitFramebuffer ( 0 , 0 , storage - > frame . current_rt - > width , storage - > frame . current_rt - > height , 0 , 0 , storage - > frame . current_rt - > width , storage - > frame . current_rt - > height , GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT , GL_NEAREST ) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , 0 ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
# elif IPHONE_ENABLED
glBindFramebuffer ( GL_READ_FRAMEBUFFER , storage - > frame . current_rt - > multisample_fbo ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , next_buffer ) ;
glResolveMultisampleFramebufferAPPLE ( ) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , 0 ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
# elif ANDROID_ENABLED
// In GLES2 Android Blit is not available, so just copy color texture manually
_copy_texture_to_buffer ( storage - > frame . current_rt - > multisample_color , next_buffer ) ;
# else
// TODO: any other platform not supported? this will fail.. maybe we should just call _copy_texture_to_buffer here as well?
( void ) next_buffer ; // Silence warning as it's unused.
# endif
} else if ( use_post_process ) {
if ( storage - > frame . current_rt - > external . fbo ! = 0 ) {
_copy_texture_to_buffer ( storage - > frame . current_rt - > external . color , storage - > frame . current_rt - > mip_maps [ 0 ] . sizes [ 0 ] . fbo ) ;
} else {
_copy_texture_to_buffer ( storage - > frame . current_rt - > color , storage - > frame . current_rt - > mip_maps [ 0 ] . sizes [ 0 ] . fbo ) ;
}
}
if ( ! use_post_process ) {
return ;
}
// Order of operation
//1) DOF Blur (first blur, then copy to buffer applying the blur) //only on desktop
//2) FXAA
//3) Bloom (Glow) //only on desktop
//4) Adjustments
//Adjustments
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : DISABLE_ALPHA , ! storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_TRANSPARENT ] ) ;
state . tonemap_shader . bind ( ) ;
if ( storage - > frame . current_rt - > use_fxaa ) {
state . tonemap_shader . set_uniform ( TonemapShaderGLES2 : : PIXEL_SIZE , Vector2 ( 1.0 / storage - > frame . current_rt - > width , 1.0 / storage - > frame . current_rt - > height ) ) ;
}
storage - > _copy_screen ( ) ;
//turn off everything used
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_FXAA , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_GLOW_LEVEL1 , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_GLOW_LEVEL2 , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_GLOW_LEVEL3 , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_GLOW_LEVEL4 , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_GLOW_LEVEL5 , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_GLOW_LEVEL6 , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_GLOW_LEVEL7 , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_GLOW_REPLACE , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_GLOW_SCREEN , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_GLOW_SOFTLIGHT , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_GLOW_FILTER_BICUBIC , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_MULTI_TEXTURE_GLOW , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_BCS , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : USE_COLOR_CORRECTION , false ) ;
state . tonemap_shader . set_conditional ( TonemapShaderGLES2 : : DISABLE_ALPHA , false ) ;
}
2023-12-15 19:36:14 +01:00
void RasterizerSceneGLES2 : : render_scene ( const Transform & p_cam_transform , const Projection & p_cam_projection , const int p_eye , bool p_cam_ortogonal , InstanceBase * * p_cull_result , int p_cull_count ) {
2023-12-14 21:54:22 +01:00
Transform cam_transform = p_cam_transform ;
storage - > info . render . object_count + = p_cull_count ;
GLuint current_fb = 0 ;
int viewport_width , viewport_height ;
int viewport_x = 0 ;
int viewport_y = 0 ;
bool probe_interior = false ;
bool reverse_cull = false ;
if ( storage - > frame . current_rt & & storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_VFLIP ] ) {
cam_transform . basis . set_axis ( 1 , - cam_transform . basis . get_axis ( 1 ) ) ;
reverse_cull = true ;
}
2023-12-15 17:30:31 +01:00
state . render_no_shadows = false ;
if ( storage - > frame . current_rt - > multisample_active ) {
current_fb = storage - > frame . current_rt - > multisample_fbo ;
} else if ( storage - > frame . current_rt - > external . fbo ! = 0 ) {
current_fb = storage - > frame . current_rt - > external . fbo ;
2023-12-14 21:54:22 +01:00
} else {
2023-12-15 17:30:31 +01:00
current_fb = storage - > frame . current_rt - > fbo ;
}
2023-12-14 21:54:22 +01:00
2023-12-15 17:30:31 +01:00
viewport_width = storage - > frame . current_rt - > width ;
viewport_height = storage - > frame . current_rt - > height ;
viewport_x = storage - > frame . current_rt - > x ;
2023-12-14 21:54:22 +01:00
2023-12-15 17:30:31 +01:00
if ( storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_DIRECT_TO_SCREEN ] ) {
viewport_y = OS : : get_singleton ( ) - > get_window_size ( ) . height - viewport_height - storage - > frame . current_rt - > y ;
} else {
viewport_y = storage - > frame . current_rt - > y ;
2023-12-14 21:54:22 +01:00
}
state . used_screen_texture = false ;
state . viewport_size . x = viewport_width ;
state . viewport_size . y = viewport_height ;
state . screen_pixel_size . x = 1.0 / viewport_width ;
state . screen_pixel_size . y = 1.0 / viewport_height ;
// render list stuff
render_list . clear ( ) ;
2023-12-15 19:36:14 +01:00
_fill_render_list ( p_cull_result , p_cull_count , false ) ;
2023-12-14 21:54:22 +01:00
// other stuff
glBindFramebuffer ( GL_FRAMEBUFFER , current_fb ) ;
glViewport ( viewport_x , viewport_y , viewport_width , viewport_height ) ;
if ( storage - > frame . current_rt & & storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_DIRECT_TO_SCREEN ] ) {
glScissor ( viewport_x , viewport_y , viewport_width , viewport_height ) ;
glEnable ( GL_SCISSOR_TEST ) ;
}
glDepthFunc ( GL_LEQUAL ) ;
glDepthMask ( GL_TRUE ) ;
glClearDepth ( 1.0f ) ;
glEnable ( GL_DEPTH_TEST ) ;
glClear ( GL_DEPTH_BUFFER_BIT ) ;
// clear color
Color clear_color ( 0 , 0 , 0 , 1 ) ;
if ( storage - > frame . current_rt & & storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_TRANSPARENT ] ) {
clear_color = Color ( 0 , 0 , 0 , 0 ) ;
storage - > frame . clear_request = false ;
} else {
storage - > frame . clear_request = false ;
}
state . default_ambient = Color ( clear_color . r , clear_color . g , clear_color . b , 1.0 ) ;
state . default_bg = Color ( clear_color . r , clear_color . g , clear_color . b , 1.0 ) ;
if ( storage - > frame . current_rt & & storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_DIRECT_TO_SCREEN ] ) {
glDisable ( GL_SCISSOR_TEST ) ;
}
glVertexAttrib4f ( RS : : ARRAY_COLOR , 1 , 1 , 1 , 1 ) ;
glBlendEquation ( GL_FUNC_ADD ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
// render sky
if ( probe_interior ) {
state . default_ambient = Color ( 0 , 0 , 0 , 1 ) ; //black as default ambient for interior
state . default_bg = Color ( 0 , 0 , 0 , 1 ) ; //black as default background for interior
}
// make sure we set our output mode correctly
if ( storage - > frame . current_rt ) {
state . scene_shader . set_conditional ( SceneShaderGLES2 : : OUTPUT_LINEAR , storage - > frame . current_rt - > flags [ RasterizerStorage : : RENDER_TARGET_KEEP_3D_LINEAR ] ) ;
} else {
state . scene_shader . set_conditional ( SceneShaderGLES2 : : OUTPUT_LINEAR , false ) ;
}
// render opaque things first
render_list . sort_by_key ( false ) ;
2023-12-15 19:36:14 +01:00
_render_render_list ( render_list . elements , render_list . element_count , cam_transform , p_cam_projection , p_eye , reverse_cull , false ) ;
2023-12-14 21:54:22 +01:00
if ( storage - > frame . current_rt & & state . used_screen_texture ) {
//copy screen texture
if ( storage - > frame . current_rt - > multisample_active ) {
// Resolve framebuffer to front buffer before copying
# ifdef GLES_OVER_GL
glBindFramebuffer ( GL_READ_FRAMEBUFFER , storage - > frame . current_rt - > multisample_fbo ) ;
glReadBuffer ( GL_COLOR_ATTACHMENT0 ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , storage - > frame . current_rt - > fbo ) ;
glBlitFramebuffer ( 0 , 0 , storage - > frame . current_rt - > width , storage - > frame . current_rt - > height , 0 , 0 , storage - > frame . current_rt - > width , storage - > frame . current_rt - > height , GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT , GL_NEAREST ) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , 0 ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
# elif IPHONE_ENABLED
glBindFramebuffer ( GL_READ_FRAMEBUFFER , storage - > frame . current_rt - > multisample_fbo ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , storage - > frame . current_rt - > fbo ) ;
glResolveMultisampleFramebufferAPPLE ( ) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , 0 ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
# elif ANDROID_ENABLED
// In GLES2 AndroidBlit is not available, so just copy color texture manually
_copy_texture_to_buffer ( storage - > frame . current_rt - > multisample_color , storage - > frame . current_rt - > fbo ) ;
# endif
}
storage - > canvas - > _copy_screen ( Rect2 ( ) ) ;
if ( storage - > frame . current_rt & & storage - > frame . current_rt - > multisample_active ) {
// Rebind the current framebuffer
glBindFramebuffer ( GL_FRAMEBUFFER , current_fb ) ;
glViewport ( 0 , 0 , viewport_width , viewport_height ) ;
}
}
// alpha pass
glBlendEquation ( GL_FUNC_ADD ) ;
glBlendFunc ( GL_ONE , GL_ONE_MINUS_SRC_ALPHA ) ;
render_list . sort_by_reverse_depth_and_priority ( true ) ;
2023-12-15 19:36:14 +01:00
_render_render_list ( & render_list . elements [ render_list . max_elements - render_list . alpha_element_count ] , render_list . alpha_element_count , cam_transform , p_cam_projection , p_eye , reverse_cull , true ) ;
2023-12-14 21:54:22 +01:00
//post process
2023-12-15 14:53:15 +01:00
_post_process ( p_cam_projection ) ;
2023-12-14 21:54:22 +01:00
// return to default
state . scene_shader . set_conditional ( SceneShaderGLES2 : : OUTPUT_LINEAR , false ) ;
}
void RasterizerSceneGLES2 : : set_scene_pass ( uint64_t p_pass ) {
scene_pass = p_pass ;
}
bool RasterizerSceneGLES2 : : free ( RID p_rid ) {
2023-12-15 19:36:14 +01:00
return false ;
2023-12-14 21:54:22 +01:00
}
void RasterizerSceneGLES2 : : set_debug_draw_mode ( RS : : ViewportDebugDraw p_debug_draw ) {
}
void RasterizerSceneGLES2 : : initialize ( ) {
state . scene_shader . init ( ) ;
state . scene_shader . set_conditional ( SceneShaderGLES2 : : USE_RGBA_SHADOWS , storage - > config . use_rgba_3d_shadows ) ;
state . cube_to_dp_shader . init ( ) ;
state . effect_blur_shader . init ( ) ;
state . tonemap_shader . init ( ) ;
render_list . init ( ) ;
render_pass = 1 ;
{
//default material and shader
default_shader = RID_PRIME ( storage - > shader_create ( ) ) ;
storage - > shader_set_code ( default_shader , " shader_type spatial; \n " ) ;
default_material = RID_PRIME ( storage - > material_create ( ) ) ;
storage - > material_set_shader ( default_material , default_shader ) ;
default_shader_twosided = RID_PRIME ( storage - > shader_create ( ) ) ;
default_material_twosided = RID_PRIME ( storage - > material_create ( ) ) ;
storage - > shader_set_code ( default_shader_twosided , " shader_type spatial; render_mode cull_disabled; \n " ) ;
storage - > material_set_shader ( default_material_twosided , default_shader_twosided ) ;
}
{
default_worldcoord_shader = RID_PRIME ( storage - > shader_create ( ) ) ;
storage - > shader_set_code ( default_worldcoord_shader , " shader_type spatial; render_mode world_vertex_coords; \n " ) ;
default_worldcoord_material = RID_PRIME ( storage - > material_create ( ) ) ;
storage - > material_set_shader ( default_worldcoord_material , default_worldcoord_shader ) ;
default_worldcoord_shader_twosided = RID_PRIME ( storage - > shader_create ( ) ) ;
default_worldcoord_material_twosided = RID_PRIME ( storage - > material_create ( ) ) ;
storage - > shader_set_code ( default_worldcoord_shader_twosided , " shader_type spatial; render_mode cull_disabled,world_vertex_coords; \n " ) ;
storage - > material_set_shader ( default_worldcoord_material_twosided , default_worldcoord_shader_twosided ) ;
}
{
//default material and shader
default_overdraw_shader = RID_PRIME ( storage - > shader_create ( ) ) ;
// Use relatively low opacity so that more "layers" of overlapping objects can be distinguished.
storage - > shader_set_code ( default_overdraw_shader , " shader_type spatial; \n render_mode blend_add,unshaded; \n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.1; } " ) ;
default_overdraw_material = RID_PRIME ( storage - > material_create ( ) ) ;
storage - > material_set_shader ( default_overdraw_material , default_overdraw_shader ) ;
}
{
glGenBuffers ( 1 , & state . sky_verts ) ;
glBindBuffer ( GL_ARRAY_BUFFER , state . sky_verts ) ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( Vector3 ) * 8 , nullptr , GL_DYNAMIC_DRAW ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
}
{
uint32_t immediate_buffer_size = GLOBAL_DEF ( " rendering/limits/buffers/immediate_buffer_size_kb " , 2048 ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " rendering/limits/buffers/immediate_buffer_size_kb " , PropertyInfo ( Variant : : INT , " rendering/limits/buffers/immediate_buffer_size_kb " , PROPERTY_HINT_RANGE , " 0,8192,1,or_greater " ) ) ;
glGenBuffers ( 1 , & state . immediate_buffer ) ;
glBindBuffer ( GL_ARRAY_BUFFER , state . immediate_buffer ) ;
glBufferData ( GL_ARRAY_BUFFER , immediate_buffer_size * 1024 , nullptr , GL_DYNAMIC_DRAW ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
}
glFrontFace ( GL_CW ) ;
}
void RasterizerSceneGLES2 : : iteration ( ) {
}
void RasterizerSceneGLES2 : : finalize ( ) {
}
RasterizerSceneGLES2 : : RasterizerSceneGLES2 ( ) {
}
RasterizerSceneGLES2 : : ~ RasterizerSceneGLES2 ( ) {
storage - > free ( default_material ) ;
default_material = RID ( ) ;
storage - > free ( default_material_twosided ) ;
default_material_twosided = RID ( ) ;
storage - > free ( default_shader ) ;
default_shader = RID ( ) ;
storage - > free ( default_shader_twosided ) ;
default_shader_twosided = RID ( ) ;
storage - > free ( default_worldcoord_material ) ;
default_worldcoord_material = RID ( ) ;
storage - > free ( default_worldcoord_material_twosided ) ;
default_worldcoord_material_twosided = RID ( ) ;
storage - > free ( default_worldcoord_shader ) ;
default_worldcoord_shader = RID ( ) ;
storage - > free ( default_worldcoord_shader_twosided ) ;
default_worldcoord_shader_twosided = RID ( ) ;
storage - > free ( default_overdraw_material ) ;
default_overdraw_material = RID ( ) ;
storage - > free ( default_overdraw_shader ) ;
default_overdraw_shader = RID ( ) ;
}