mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:02:45 +00:00 
			
		
		
		
	LibAccelGfx+LibWeb: Implement draw_scaled_bitmap()
Very basic implementation of command to paint bitmap. In the future we should reuse loaded textures across repaints whenever it is possible.
This commit is contained in:
		
							parent
							
								
									b7f8d7e357
								
							
						
					
					
						commit
						aa6c008450
					
				
					 3 changed files with 110 additions and 2 deletions
				
			
		|  | @ -57,6 +57,25 @@ void main() { | |||
| } | ||||
| )"; | ||||
| 
 | ||||
| char const* blit_vertex_shader_source = R"( | ||||
| attribute vec4 aVertexPosition; | ||||
| attribute vec2 aTextureCoord; | ||||
| varying vec2 vTextureCoord; | ||||
| void main() { | ||||
|     gl_Position = aVertexPosition; | ||||
|     vTextureCoord = aTextureCoord; | ||||
| } | ||||
| )"; | ||||
| 
 | ||||
| char const* blit_fragment_shader_source = R"( | ||||
| precision mediump float; | ||||
| varying vec2 vTextureCoord; | ||||
| uniform sampler2D uSampler; | ||||
| void main() { | ||||
|     gl_FragColor = texture2D(uSampler, vTextureCoord); | ||||
| } | ||||
| )"; | ||||
| 
 | ||||
| OwnPtr<Painter> Painter::create() | ||||
| { | ||||
|     auto& context = Context::the(); | ||||
|  | @ -66,6 +85,7 @@ OwnPtr<Painter> Painter::create() | |||
| Painter::Painter(Context& context) | ||||
|     : m_context(context) | ||||
|     , m_rectangle_program(Program::create(vertex_shader_source, solid_color_fragment_shader_source)) | ||||
|     , m_blit_program(Program::create(blit_vertex_shader_source, blit_fragment_shader_source)) | ||||
| { | ||||
|     m_state_stack.empend(State()); | ||||
| } | ||||
|  | @ -125,6 +145,69 @@ void Painter::fill_rect(Gfx::FloatRect rect, Gfx::Color color) | |||
|     glDrawArrays(GL_TRIANGLE_FAN, 0, 4); | ||||
| } | ||||
| 
 | ||||
| void Painter::draw_scaled_bitmap(Gfx::IntRect const& dest_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, ScalingMode scaling_mode) | ||||
| { | ||||
|     draw_scaled_bitmap(dest_rect.to_type<float>(), bitmap, src_rect.to_type<float>(), scaling_mode); | ||||
| } | ||||
| 
 | ||||
| static Gfx::FloatRect to_texture_space(Gfx::FloatRect rect, Gfx::IntSize image_size) | ||||
| { | ||||
|     auto x = rect.x() / image_size.width(); | ||||
|     auto y = rect.y() / image_size.height(); | ||||
|     auto width = rect.width() / image_size.width(); | ||||
|     auto height = rect.height() / image_size.height(); | ||||
| 
 | ||||
|     return { x, y, width, height }; | ||||
| } | ||||
| 
 | ||||
| static GLenum to_gl_scaling_mode(Painter::ScalingMode scaling_mode) | ||||
| { | ||||
|     switch (scaling_mode) { | ||||
|     case Painter::ScalingMode::NearestNeighbor: | ||||
|         return GL_NEAREST; | ||||
|     case Painter::ScalingMode::Bilinear: | ||||
|         return GL_LINEAR; | ||||
|     default: | ||||
|         VERIFY_NOT_REACHED(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Painter::draw_scaled_bitmap(Gfx::FloatRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::FloatRect const& src_rect, ScalingMode scaling_mode) | ||||
| { | ||||
|     m_blit_program.use(); | ||||
| 
 | ||||
|     GLuint texture; | ||||
| 
 | ||||
|     // FIXME: We should reuse textures across repaints if possible.
 | ||||
|     glGenTextures(1, &texture); | ||||
|     glBindTexture(GL_TEXTURE_2D, texture); | ||||
|     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap.width(), bitmap.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, bitmap.scanline(0)); | ||||
| 
 | ||||
|     GLenum scaling_mode_gl = to_gl_scaling_mode(scaling_mode); | ||||
| 
 | ||||
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, scaling_mode_gl); | ||||
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, scaling_mode_gl); | ||||
| 
 | ||||
|     auto vertices = rect_to_vertices(to_clip_space(transform().map(dst_rect))); | ||||
|     auto texture_coordinates = rect_to_vertices(to_texture_space(src_rect, bitmap.size())); | ||||
| 
 | ||||
|     GLuint vertex_position_attribute = m_blit_program.get_attribute_location("aVertexPosition"); | ||||
|     glVertexAttribPointer(vertex_position_attribute, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), vertices.data()); | ||||
|     glEnableVertexAttribArray(vertex_position_attribute); | ||||
| 
 | ||||
|     GLuint texture_coord_attribute = m_blit_program.get_attribute_location("aTextureCoord"); | ||||
|     glVertexAttribPointer(texture_coord_attribute, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), texture_coordinates.data()); | ||||
|     glEnableVertexAttribArray(texture_coord_attribute); | ||||
| 
 | ||||
|     glEnable(GL_BLEND); | ||||
|     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
|     glDrawArrays(GL_TRIANGLE_FAN, 0, 4); | ||||
| 
 | ||||
|     glDeleteTextures(1, &texture); | ||||
| } | ||||
| 
 | ||||
| void Painter::save() | ||||
| { | ||||
|     m_state_stack.append(state()); | ||||
|  |  | |||
|  | @ -37,6 +37,14 @@ public: | |||
|     void fill_rect(Gfx::FloatRect, Gfx::Color); | ||||
|     void fill_rect(Gfx::IntRect, Gfx::Color); | ||||
| 
 | ||||
|     enum class ScalingMode { | ||||
|         NearestNeighbor, | ||||
|         Bilinear, | ||||
|     }; | ||||
| 
 | ||||
|     void draw_scaled_bitmap(Gfx::FloatRect const& dst_rect, Gfx::Bitmap const&, Gfx::FloatRect const& src_rect, ScalingMode = ScalingMode::NearestNeighbor); | ||||
|     void draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const&, Gfx::IntRect const& src_rect, ScalingMode = ScalingMode::NearestNeighbor); | ||||
| 
 | ||||
|     void set_canvas(Canvas& canvas) { m_canvas = canvas; } | ||||
|     void flush(); | ||||
| 
 | ||||
|  | @ -56,6 +64,7 @@ private: | |||
|     Vector<State, 1> m_state_stack; | ||||
| 
 | ||||
|     Program m_rectangle_program; | ||||
|     Program m_blit_program; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -36,9 +36,25 @@ CommandResult PaintingCommandExecutorGPU::fill_rect(Gfx::IntRect const& rect, Co | |||
|     return CommandResult::Continue; | ||||
| } | ||||
| 
 | ||||
| CommandResult PaintingCommandExecutorGPU::draw_scaled_bitmap(Gfx::IntRect const&, Gfx::Bitmap const&, Gfx::IntRect const&, float, Gfx::Painter::ScalingMode) | ||||
| CommandResult PaintingCommandExecutorGPU::draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, float, Gfx::Painter::ScalingMode scaling_mode) | ||||
| { | ||||
|     // FIXME
 | ||||
|     // FIXME: We should avoid using Gfx::Painter specific enums in painting commands
 | ||||
|     AccelGfx::Painter::ScalingMode accel_scaling_mode; | ||||
|     switch (scaling_mode) { | ||||
|     case Gfx::Painter::ScalingMode::NearestNeighbor: | ||||
|     case Gfx::Painter::ScalingMode::BoxSampling: | ||||
|     case Gfx::Painter::ScalingMode::SmoothPixels: | ||||
|     case Gfx::Painter::ScalingMode::None: | ||||
|         accel_scaling_mode = AccelGfx::Painter::ScalingMode::NearestNeighbor; | ||||
|         break; | ||||
|     case Gfx::Painter::ScalingMode::BilinearBlend: | ||||
|         accel_scaling_mode = AccelGfx::Painter::ScalingMode::Bilinear; | ||||
|         break; | ||||
|     default: | ||||
|         VERIFY_NOT_REACHED(); | ||||
|     } | ||||
| 
 | ||||
|     painter().draw_scaled_bitmap(dst_rect, bitmap, src_rect, accel_scaling_mode); | ||||
|     return CommandResult::Continue; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Aliaksandr Kalenik
						Aliaksandr Kalenik