void VertexArrayRenderer::RefreshArray() { SortPrimitives(); m_vertex_data.clear(); m_color_data.clear(); m_texture_data.clear(); m_index_data.clear(); m_vertex_data.reserve( m_vertex_count ); m_color_data.reserve( m_vertex_count ); m_texture_data.reserve( m_vertex_count ); m_index_data.reserve( m_index_count ); m_batches.clear(); m_last_vertex_count = 0; m_last_index_count = 0; auto primitives_size = m_primitives.size(); // Default viewport Batch current_batch; current_batch.viewport = m_default_viewport; current_batch.atlas_page = 0; current_batch.start_index = 0; current_batch.index_count = 0; current_batch.min_index = 0; current_batch.max_index = static_cast<GLuint>( m_vertex_count - 1 ); current_batch.custom_draw = false; sf::FloatRect window_viewport( 0.f, 0.f, static_cast<float>( m_window_size.x ), static_cast<float>( m_window_size.y ) ); for( std::size_t primitive_index = 1; primitive_index != primitives_size + 1; primitive_index += 1 ) { Primitive* primitive = m_primitives[primitive_index - 1].get(); primitive->SetSynced(); if( !primitive->IsVisible() ) { continue; } sf::Vector2f position_transform( primitive->GetPosition() ); auto viewport = primitive->GetViewport(); std::size_t atlas_page = 0; auto viewport_rect = window_viewport; // Check if primitive needs to be rendered in a custom viewport. if( viewport && ( ( *viewport ) != ( *m_default_viewport ) ) ) { sf::Vector2f destination_origin( viewport->GetDestinationOrigin() ); sf::Vector2f size( viewport->GetSize() ); position_transform += ( destination_origin - viewport->GetSourceOrigin() ); if( m_cull ) { viewport_rect.left = destination_origin.x; viewport_rect.top = destination_origin.y; viewport_rect.width = size.x; viewport_rect.height = size.y; } } const std::shared_ptr<Signal>& custom_draw_callback( primitive->GetCustomDrawCallback() ); if( custom_draw_callback ) { // Start a new batch. current_batch.max_index = m_last_vertex_count ? ( static_cast<GLuint>( m_last_vertex_count ) - 1 ) : 0; m_batches.push_back( current_batch ); // Mark current_batch custom draw batch. current_batch.viewport = viewport; current_batch.start_index = 0; current_batch.index_count = 0; current_batch.min_index = 0; current_batch.max_index = 0; current_batch.custom_draw = true; current_batch.custom_draw_callback = custom_draw_callback; // Start a new batch. m_batches.push_back( current_batch ); // Reset current_batch to defaults. current_batch.viewport = m_default_viewport; current_batch.start_index = m_last_index_count; current_batch.index_count = 0; current_batch.min_index = m_last_vertex_count ? ( static_cast<GLuint>( m_last_vertex_count ) - 1 ) : 0; current_batch.custom_draw = false; } else { // Process primitive's vertices and indices const std::vector<Primitive::Vertex>& vertices( primitive->GetVertices() ); const std::vector<GLuint>& indices( primitive->GetIndices() ); sf::Vector2f position( 0.f, 0.f ); sf::FloatRect bounding_rect( 0.f, 0.f, 0.f, 0.f ); for( const auto& vertex : vertices ) { position.x = vertex.position.x + position_transform.x; position.y = vertex.position.y + position_transform.y; m_vertex_data.push_back( position ); m_color_data.push_back( vertex.color ); atlas_page = static_cast<unsigned int>( vertex.texture_coordinate.y ) / m_max_texture_size; // Used to normalize texture coordinates. sf::Vector2f normalizer( 1.f / static_cast<float>( m_texture_atlas[atlas_page]->getSize().x ), 1.f / static_cast<float>( m_texture_atlas[atlas_page]->getSize().y ) ); // Normalize SFML's pixel texture coordinates. m_texture_data.push_back( sf::Vector2f( vertex.texture_coordinate.x * normalizer.x, static_cast<float>( static_cast<unsigned int>( vertex.texture_coordinate.y ) % m_max_texture_size ) * normalizer.y ) ); // Update the bounding rect. if( m_cull ) { if( position.x < bounding_rect.left ) { bounding_rect.width += bounding_rect.left - position.x; bounding_rect.left = position.x; } else if( position.x > bounding_rect.left + bounding_rect.width ) { bounding_rect.width = position.x - bounding_rect.left; } if( position.y < bounding_rect.top ) { bounding_rect.height += bounding_rect.top - position.y; bounding_rect.top = position.y; } else if( position.y > bounding_rect.top + bounding_rect.height ) { bounding_rect.height = position.y - bounding_rect.top; } } } if( m_cull && !viewport_rect.intersects( bounding_rect ) ) { m_vertex_data.resize( m_last_vertex_count ); m_color_data.resize( m_last_vertex_count ); m_texture_data.resize( m_last_vertex_count ); } else { for( const auto& index : indices ) { m_index_data.push_back( m_last_vertex_count + index ); } // Check if we need to start a new batch. if( ( ( *viewport ) != ( *current_batch.viewport ) ) || ( atlas_page != current_batch.atlas_page ) ) { current_batch.max_index = m_last_vertex_count ? ( static_cast<GLuint>( m_last_vertex_count ) - 1 ) : 0; m_batches.push_back( current_batch ); // Reset current_batch to defaults. current_batch.viewport = viewport; current_batch.atlas_page = atlas_page; current_batch.start_index = m_last_index_count; current_batch.index_count = 0; current_batch.min_index = m_last_vertex_count ? ( static_cast<GLuint>( m_last_vertex_count ) - 1 ) : 0; current_batch.custom_draw = false; } current_batch.index_count += static_cast<unsigned int>( indices.size() ); m_last_vertex_count += static_cast<GLsizei>( vertices.size() ); m_last_index_count += static_cast<GLsizei>( indices.size() ); } } } current_batch.max_index = m_last_vertex_count ? ( static_cast<GLuint>( m_last_vertex_count ) - 1 ) : 0; m_batches.push_back( current_batch ); }
void Renderer::RefreshVBO( sf::RenderWindow& window ) { SortPrimitives(); m_vertex_data.clear(); m_color_data.clear(); m_texture_data.clear(); m_viewport_pairs.clear(); m_last_vertex_count = 0; std::size_t primitives_size = m_primitives.size(); // Check for alpha values in all primitives. // Disable depth test if any found. for( std::size_t primitive_index = 0; primitive_index < primitives_size; ++primitive_index ) { const std::vector<Primitive::Vertex>& vertices( m_primitives[primitive_index]->GetVertices() ); std::size_t vertices_size = vertices.size(); for( std::size_t vertex_index = 0; vertex_index < vertices_size; ++vertex_index ) { const Primitive::Vertex& vertex( vertices[vertex_index] ); if( m_depth_clear_strategy && ( vertex.color.a < 255 ) ) { #ifdef SFGUI_DEBUG std::cerr << "Detected alpha value " << static_cast<int>( vertex.color.a ) << " disabling depth test.\n"; #endif m_depth_clear_strategy = NO_DEPTH; } } } // Used to normalize texture coordinates. sf::Vector2f normalizer( 1.f / static_cast<float>( m_texture_atlas.getWidth() ), 1.f / static_cast<float>( m_texture_atlas.getHeight() ) ); // Depth test vars float depth = -4.f; float depth_delta = 4.f / static_cast<float>( primitives_size ); int direction = m_depth_clear_strategy ? -1 : 1; int start = static_cast<int>( m_depth_clear_strategy ? primitives_size : 1 ); std::size_t end = m_depth_clear_strategy ? 0 : primitives_size + 1; RendererViewport::Ptr current_viewport = m_default_viewport; m_viewport_pairs.push_back( ViewportPair( m_default_viewport, 0 ) ); sf::FloatRect window_viewport( 0.f, 0.f, static_cast<float>( window.getSize().x ), static_cast<float>( window.getSize().y ) ); for( std::size_t primitive_index = start; primitive_index != end; primitive_index += direction ) { Primitive* primitive = m_primitives[primitive_index - 1].get(); primitive->SetSynced(); if( !primitive->IsVisible() ) { continue; } sf::Vector2f position_transform( primitive->GetPosition() ); // Check if primitive needs to be rendered in a custom viewport. RendererViewport::Ptr viewport = primitive->GetViewport(); if( viewport != current_viewport ) { current_viewport = viewport; ViewportPair scissor_pair( viewport, m_last_vertex_count ); m_viewport_pairs.push_back( scissor_pair ); } bool cull = m_cull; sf::FloatRect viewport_rect = window_viewport; if( viewport && ( viewport != m_default_viewport ) ) { sf::Vector2f destination_origin( viewport->GetDestinationOrigin() ); sf::Vector2f size( viewport->GetSize() ); position_transform += ( destination_origin - viewport->GetSourceOrigin() ); if( m_cull ) { viewport_rect.left = destination_origin.x; viewport_rect.top = destination_origin.y; viewport_rect.width = size.x; viewport_rect.height = size.y; } } // Process primitive's vertices. const std::vector<Primitive::Vertex>& vertices( primitive->GetVertices() ); std::size_t vertices_size = vertices.size(); for( std::size_t vertex_index = 0; vertex_index < vertices_size; ++vertex_index ) { const Primitive::Vertex& vertex( vertices[vertex_index] ); sf::Vector3f position( vertex.position.x + position_transform.x, vertex.position.y + position_transform.y, depth ); m_vertex_data.push_back( position ); m_color_data.push_back( vertex.color ); // Normalize SFML's pixel texture coordinates. m_texture_data.push_back( sf::Vector2f( vertex.texture_coordinate.x * normalizer.x, vertex.texture_coordinate.y * normalizer.y ) ); if( m_cull && viewport_rect.contains( position.x, position.y ) ) { cull = false; } } if( cull ) { m_vertex_data.resize( m_last_vertex_count ); m_color_data.resize( m_last_vertex_count ); m_texture_data.resize( m_last_vertex_count ); } else { m_last_vertex_count += vertices_size; depth -= depth_delta; } } // Sync vertex data glBindBuffer( GL_ARRAY_BUFFER, m_vertex_vbo ); glBufferData( GL_ARRAY_BUFFER, m_vertex_data.size() * sizeof( sf::Vector3f ), 0, GL_DYNAMIC_DRAW ); if( m_vertex_data.size() > 0 ) { glBufferSubData( GL_ARRAY_BUFFER, 0, m_vertex_data.size() * sizeof( sf::Vector3f ), &m_vertex_data[0] ); } // Sync color data glBindBuffer( GL_ARRAY_BUFFER, m_color_vbo ); glBufferData( GL_ARRAY_BUFFER, m_color_data.size() * sizeof( sf::Color ), 0, GL_DYNAMIC_DRAW ); if( m_color_data.size() > 0 ) { glBufferSubData( GL_ARRAY_BUFFER, 0, m_color_data.size() * sizeof( sf::Color ), &m_color_data[0] ); } // Sync texture coord data glBindBuffer( GL_ARRAY_BUFFER, m_texture_vbo ); glBufferData( GL_ARRAY_BUFFER, m_texture_data.size() * sizeof( sf::Vector2f ), 0, GL_STATIC_DRAW ); if( m_texture_data.size() > 0 ) { glBufferSubData( GL_ARRAY_BUFFER, 0, m_texture_data.size() * sizeof( sf::Vector2f ), &m_texture_data[0] ); } }