mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 22:02:44 +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() | OwnPtr<Painter> Painter::create() | ||||||
| { | { | ||||||
|     auto& context = Context::the(); |     auto& context = Context::the(); | ||||||
|  | @ -66,6 +85,7 @@ OwnPtr<Painter> Painter::create() | ||||||
| Painter::Painter(Context& context) | Painter::Painter(Context& context) | ||||||
|     : m_context(context) |     : m_context(context) | ||||||
|     , m_rectangle_program(Program::create(vertex_shader_source, solid_color_fragment_shader_source)) |     , 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()); |     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); |     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() | void Painter::save() | ||||||
| { | { | ||||||
|     m_state_stack.append(state()); |     m_state_stack.append(state()); | ||||||
|  |  | ||||||
|  | @ -37,6 +37,14 @@ public: | ||||||
|     void fill_rect(Gfx::FloatRect, Gfx::Color); |     void fill_rect(Gfx::FloatRect, Gfx::Color); | ||||||
|     void fill_rect(Gfx::IntRect, 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 set_canvas(Canvas& canvas) { m_canvas = canvas; } | ||||||
|     void flush(); |     void flush(); | ||||||
| 
 | 
 | ||||||
|  | @ -56,6 +64,7 @@ private: | ||||||
|     Vector<State, 1> m_state_stack; |     Vector<State, 1> m_state_stack; | ||||||
| 
 | 
 | ||||||
|     Program m_rectangle_program; |     Program m_rectangle_program; | ||||||
|  |     Program m_blit_program; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -36,9 +36,25 @@ CommandResult PaintingCommandExecutorGPU::fill_rect(Gfx::IntRect const& rect, Co | ||||||
|     return CommandResult::Continue; |     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; |     return CommandResult::Continue; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Aliaksandr Kalenik
						Aliaksandr Kalenik