Beispiel #1
0
Primitive::Ptr Renderer::CreateImage( const sf::FloatRect& rect, const sf::Image& image, sf::Color background_color_hint ) {
	sf::Vector2f offset( LoadImage( image, background_color_hint ) );

	Primitive::Ptr primitive( new Primitive );

	Primitive::Vertex vertex0;
	Primitive::Vertex vertex1;
	Primitive::Vertex vertex2;
	Primitive::Vertex vertex3;

	vertex0.position = sf::Vector2f( std::floor( rect.left + .5f ), std::floor( rect.top + .5f ) );
	vertex1.position = sf::Vector2f( std::floor( rect.left + .5f ), std::floor( rect.top + .5f ) + std::floor( rect.height + .5f ) );
	vertex2.position = sf::Vector2f( std::floor( rect.left + .5f ) + std::floor( rect.width + .5f ), std::floor( rect.top + .5f ) );
	vertex3.position = sf::Vector2f( std::floor( rect.left + .5f ) + std::floor( rect.width + .5f ), std::floor( rect.top + .5f ) + std::floor( rect.height + .5f ) );

	vertex0.color = sf::Color( 255, 255, 255, 255 );
	vertex1.color = sf::Color( 255, 255, 255, 255 );
	vertex2.color = sf::Color( 255, 255, 255, 255 );
	vertex3.color = sf::Color( 255, 255, 255, 255 );

	vertex0.texture_coordinate = offset + sf::Vector2f( 0.f, 0.f );
	vertex1.texture_coordinate = offset + sf::Vector2f( 0.f, static_cast<float>( image.getHeight() ) );
	vertex2.texture_coordinate = offset + sf::Vector2f( static_cast<float>( image.getWidth() ), 0.f );
	vertex3.texture_coordinate = offset + sf::Vector2f( static_cast<float>( image.getWidth() ), static_cast<float>( image.getHeight() ) );

	primitive->AddVertex( vertex0 );
	primitive->AddVertex( vertex1 );
	primitive->AddVertex( vertex2 );
	primitive->AddVertex( vertex2 );
	primitive->AddVertex( vertex1 );
	primitive->AddVertex( vertex3 );

	AddPrimitive( primitive );

	return primitive;
}
Beispiel #2
0
sf::Vector2f Renderer::LoadImage( const sf::Image& image, sf::Color background_color_hint, sf::Color foreground_color_hint, bool force_insert ) {
	const sf::Uint8* pixels_ptr = image.getPixelsPtr();

	if( !force_insert ) {
		std::map<const sf::Uint8*, sf::Vector2f>::iterator iter( m_atlas_offsets.find( pixels_ptr ) );

		if( iter != m_atlas_offsets.end() ) {
			return iter->second;
		}
	}

	sf::Image preblended_image;

	preblended_image.create( image.getWidth(), image.getHeight(), image.getPixelsPtr() );

	// If we get a proper background color hint and preblend is enabled,
	// precompute blended color with ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ).
	if( m_preblend ) {
		if( background_color_hint.a == 255 ) {
			float foreground_r_factor = 1.f;
			float foreground_g_factor = 1.f;
			float foreground_b_factor = 1.f;

			if( foreground_color_hint.a == 255 ) {
				foreground_r_factor = static_cast<float>( foreground_color_hint.r ) / 255.f;
				foreground_g_factor = static_cast<float>( foreground_color_hint.g ) / 255.f;
				foreground_b_factor = static_cast<float>( foreground_color_hint.b ) / 255.f;
			}

			std::size_t pixel_count = preblended_image.getWidth() * preblended_image.getHeight();

			sf::Uint8* bytes = new sf::Uint8[pixel_count * 4];

			memcpy( bytes, preblended_image.getPixelsPtr(), pixel_count * 4 );

			for( std::size_t index = 0; index < pixel_count; ++index ) {
				// Alpha
				float alpha = static_cast<float>( bytes[index * 4 + 3] ) / 255.f;

				// Red
				bytes[index * 4 + 0] = static_cast<sf::Uint8>( static_cast<float>( bytes[index * 4 + 0] ) * foreground_r_factor * alpha + static_cast<float>( background_color_hint.r ) * ( 1.f - alpha ) );

				// Green
				bytes[index * 4 + 1] = static_cast<sf::Uint8>( static_cast<float>( bytes[index * 4 + 1] ) * foreground_g_factor * alpha + static_cast<float>( background_color_hint.g ) * ( 1.f - alpha ) );

				// Blue
				bytes[index * 4 + 2] = static_cast<sf::Uint8>( static_cast<float>( bytes[index * 4 + 2] ) * foreground_b_factor * alpha + static_cast<float>( background_color_hint.b ) * ( 1.f - alpha ) );
			}

			preblended_image.create( preblended_image.getWidth(), preblended_image.getHeight(), bytes );

			delete[] bytes;
		}
		else {
			m_preblend = false;

#ifdef SFGUI_DEBUG
			std::cerr << "Detected alpha value " << static_cast<int>( background_color_hint.a ) << " in background color hint. Disabling preblend.\n";
#endif
		}
	}

	const sf::Uint8* bytes = preblended_image.getPixelsPtr();
	std::size_t byte_count = preblended_image.getWidth() * preblended_image.getHeight() * 4;

	// Disable this check for now.
	static sf::Uint8 alpha_threshold = 255;

	for ( ; byte_count; --byte_count ) {
		// Check if the image makes intentional use of the alpha channel.
		if( m_depth_clear_strategy && !( byte_count % 4 ) && ( bytes[ byte_count - 1 ] > alpha_threshold ) && ( bytes[ byte_count - 1 ] < 255 ) ) {
#ifdef SFGUI_DEBUG
			std::cerr << "Detected alpha value " << static_cast<int>( bytes[ byte_count - 1 ]  ) << " in texture, disabling depth test.\n";
#endif
			m_depth_clear_strategy = NO_DEPTH;
		}
	}

	// Image needs to be loaded into atlas.
	sf::Image old_image = m_texture_atlas.copyToImage();
	sf::Image new_image;

	// We insert padding between atlas elements to prevent
	// texture filtering from screwing up our images.
	// If 1 pixel isn't enough, increase.
	const static unsigned int padding = 1;

	new_image.create( std::max( old_image.getWidth(), preblended_image.getWidth() ), old_image.getHeight() + preblended_image.getHeight() + padding, sf::Color::White );
	new_image.copy( old_image, 0, 0 );

	new_image.copy( preblended_image, 0, old_image.getHeight() + padding );

	m_texture_atlas.loadFromImage( new_image );

	sf::Vector2f offset = sf::Vector2f( 0.f, static_cast<float>( old_image.getHeight() + padding ) );

	InvalidateVBO();

	if( !force_insert ) {
		m_atlas_offsets[pixels_ptr] = offset;
	}

	return offset;
}