core: Add draw_rect to the render backend API

This commit is contained in:
Nathan Adams 2020-09-15 23:14:25 +02:00 committed by Mike Welsh
parent 30b910554a
commit e008603426
4 changed files with 243 additions and 134 deletions

View File

@ -3,6 +3,7 @@ pub use crate::{transform::Transform, Color};
use downcast_rs::Downcast;
use std::io::Read;
pub use swf;
use swf::Matrix;
pub trait RenderBackend: Downcast {
fn set_viewport_dimensions(&mut self, width: u32, height: u32);
@ -34,6 +35,7 @@ pub trait RenderBackend: Downcast {
fn begin_frame(&mut self, clear: Color);
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform);
fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform);
fn draw_rect(&mut self, color: Color, matrix: &Matrix);
fn end_frame(&mut self);
fn draw_letterbox(&mut self, letterbox: Letterbox);
fn push_mask(&mut self);
@ -137,6 +139,7 @@ impl RenderBackend for NullRenderer {
fn end_frame(&mut self) {}
fn render_bitmap(&mut self, _bitmap: BitmapHandle, _transform: &Transform) {}
fn render_shape(&mut self, _shape: ShapeHandle, _transform: &Transform) {}
fn draw_rect(&mut self, _color: Color, _matrix: &Matrix) {}
fn draw_letterbox(&mut self, _letterbox: Letterbox) {}
fn push_mask(&mut self) {}
fn activate_mask(&mut self) {}

View File

@ -5,6 +5,7 @@ use ruffle_core::backend::render::{
};
use ruffle_core::color_transform::ColorTransform;
use ruffle_core::shape_utils::{DistilledShape, DrawCommand};
use ruffle_core::swf::Matrix;
use ruffle_web_common::JsResult;
use std::collections::HashMap;
use std::convert::TryInto;
@ -305,9 +306,7 @@ impl WebCanvasRenderBackend {
#[allow(clippy::float_cmp)]
#[inline]
fn set_transform(&mut self, transform: &Transform) {
let matrix = transform.matrix;
fn set_transform(&mut self, matrix: &Matrix) {
self.context
.set_transform(
matrix.a.into(),
@ -559,7 +558,7 @@ impl RenderBackend for WebCanvasRenderBackend {
}
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform) {
self.set_transform(transform);
self.set_transform(&transform.matrix);
self.set_color_filter(transform);
if let Some(bitmap) = self.bitmaps.get(bitmap.0) {
let _ = self
@ -570,7 +569,7 @@ impl RenderBackend for WebCanvasRenderBackend {
}
fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) {
self.set_transform(transform);
self.set_transform(&transform.matrix);
if let Some(shape) = self.shapes.get(shape.0) {
for command in shape.0.iter() {
match command {
@ -629,6 +628,25 @@ impl RenderBackend for WebCanvasRenderBackend {
}
}
fn draw_rect(&mut self, color: Color, matrix: &Matrix) {
self.set_transform(matrix);
self.clear_color_filter();
self.context.set_fill_style(
&format!(
"rgba({},{},{},{})",
color.r,
color.g,
color.b,
f32::from(color.a) / 255.0
)
.into(),
);
self.context.fill_rect(0.0, 0.0, 1.0, 1.0);
self.clear_color_filter();
}
fn draw_letterbox(&mut self, letterbox: Letterbox) {
self.context.reset_transform().unwrap();
self.context.set_fill_style(&"black".into());
@ -717,7 +735,6 @@ fn swf_shape_to_svg(
) -> ShapeData {
use fnv::FnvHashSet;
use ruffle_core::shape_utils::DrawPath;
use ruffle_core::swf::Matrix;
use svg::node::element::{
path::Data, Definitions, Filter, Image, LinearGradient, Path as SvgPath, Pattern,
RadialGradient, Stop,

View File

@ -4,6 +4,7 @@ use ruffle_core::backend::render::{
RenderBackend, ShapeHandle, Transform,
};
use ruffle_core::shape_utils::DistilledShape;
use ruffle_core::swf::Matrix;
use ruffle_render_common_tess::{GradientSpread, GradientType, ShapeTessellator, Vertex};
use ruffle_web_common::JsResult;
use wasm_bindgen::{JsCast, JsValue};
@ -899,7 +900,6 @@ impl RenderBackend for WebGlRenderBackend {
}
// Scale the quad to the bitmap's dimensions.
use ruffle_core::swf::Matrix;
let scale_transform = Transform {
matrix: transform.matrix
* Matrix {
@ -1074,6 +1074,76 @@ impl RenderBackend for WebGlRenderBackend {
}
}
fn draw_rect(&mut self, color: Color, matrix: &Matrix) {
let world_matrix = [
[matrix.a, matrix.b, 0.0, 0.0],
[matrix.c, matrix.d, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[
matrix.tx.to_pixels() as f32,
matrix.ty.to_pixels() as f32,
0.0,
1.0,
],
];
let mult_color = [1.0, 1.0, 1.0, 1.0];
let add_color = [
color.r as f32 * 255.0,
color.g as f32 * 255.0,
color.b as f32 * 255.0,
color.a as f32 * 255.0,
];
self.set_stencil_state();
let program = &self.color_program;
let src_blend = Gl::SRC_ALPHA;
let dst_blend = Gl::ONE_MINUS_SRC_ALPHA;
// Set common render state, while minimizing unnecessary state changes.
// TODO: Using designated layout specifiers in WebGL2/OpenGL ES 3, we could guarantee that uniforms
// are in the same location between shaders, and avoid changing them unless necessary.
if program as *const ShaderProgram != self.active_program {
self.gl.use_program(Some(&program.program));
self.active_program = program as *const ShaderProgram;
program.uniform_matrix4fv(&self.gl, ShaderUniform::ViewMatrix, &self.view_matrix);
self.mult_color = None;
self.add_color = None;
if (src_blend, dst_blend) != self.blend_func {
self.gl.blend_func(src_blend, dst_blend);
self.blend_func = (src_blend, dst_blend);
}
};
self.color_program
.uniform_matrix4fv(&self.gl, ShaderUniform::WorldMatrix, &world_matrix);
if Some(mult_color) != self.mult_color {
self.color_program
.uniform4fv(&self.gl, ShaderUniform::MultColor, &mult_color);
self.mult_color = Some(mult_color);
}
if Some(add_color) != self.add_color {
self.color_program
.uniform4fv(&self.gl, ShaderUniform::AddColor, &add_color);
self.add_color = Some(add_color);
}
let quad = &self.meshes[self.quad_shape.0];
self.bind_vertex_array(Some(&quad.draws[0].vao));
self.gl.draw_elements_with_i32(
Gl::TRIANGLES,
quad.draws[0].num_indices,
Gl::UNSIGNED_SHORT,
0,
);
}
fn draw_letterbox(&mut self, letterbox: Letterbox) {
self.set_stencil_state();
@ -1345,3 +1415,5 @@ impl ShaderProgram {
);
}
}
impl WebGlRenderBackend {}

View File

@ -37,6 +37,7 @@ mod pipelines;
mod shapes;
pub mod target;
use ruffle_core::swf::{Matrix, Twips};
pub use wgpu;
pub struct WgpuRenderBackend<T: RenderTarget> {
@ -707,116 +708,6 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
pub fn device(&self) -> &wgpu::Device {
&self.device
}
fn draw_rect(&mut self, x: f32, y: f32, width: f32, height: f32, color: Color) {
let (frame_output, encoder) = if let Some((frame_output, encoder)) = &mut self.current_frame
{
(frame_output, encoder)
} else {
return;
};
let world_matrix = [
[width, 0.0, 0.0, 0.0],
[0.0, height, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[x, y, 0.0, 1.0],
];
let mult_color = [
f32::from(color.r) / 255.0,
f32::from(color.g) / 255.0,
f32::from(color.b) / 255.0,
f32::from(color.a) / 255.0,
];
let add_color = [0.0, 0.0, 0.0, 0.0];
let transforms_ubo = create_buffer_with_data(
&self.device,
bytemuck::cast_slice(&[Transforms {
view_matrix: self.view_matrix,
world_matrix,
}]),
wgpu::BufferUsage::UNIFORM,
create_debug_label!("Rectangle transfer buffer"),
);
let colors_ubo = create_buffer_with_data(
&self.device,
bytemuck::cast_slice(&[ColorAdjustments {
mult_color,
add_color,
}]),
wgpu::BufferUsage::UNIFORM,
create_debug_label!("Rectangle colors transfer buffer"),
);
let bind_group_label = create_debug_label!("Rectangle bind group");
let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &self.pipelines.color.bind_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(
transforms_ubo.slice(0..std::mem::size_of::<Transforms>() as u64),
),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Buffer(
colors_ubo.slice(0..std::mem::size_of::<ColorAdjustments>() as u64),
),
},
],
label: bind_group_label.as_deref(),
});
let (color_attachment, resolve_target) = if self.msaa_sample_count >= 2 {
(&self.frame_buffer_view, Some(frame_output.view()))
} else {
(frame_output.view(), None)
};
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: color_attachment,
resolve_target,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
},
}],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor {
attachment: &self.depth_texture_view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
stencil_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
}),
});
render_pass.set_pipeline(&self.pipelines.color.pipeline_for(
self.num_masks,
self.num_masks_active,
self.test_stencil_mask,
self.write_stencil_mask,
));
render_pass.set_bind_group(0, &bind_group, &[]);
render_pass.set_vertex_buffer(0, self.quad_vbo.slice(..));
render_pass.set_index_buffer(self.quad_ibo.slice(..));
if self.num_masks_active < self.num_masks {
render_pass.set_stencil_reference(self.write_stencil_mask);
} else {
render_pass.set_stencil_reference(self.test_stencil_mask);
}
render_pass.draw_indexed(0..6, 0, 0..1);
}
}
impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
@ -983,7 +874,6 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
return;
};
use ruffle_core::swf::Matrix;
let transform = Transform {
matrix: transform.matrix
* Matrix {
@ -1249,6 +1139,121 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
}
}
fn draw_rect(&mut self, color: Color, matrix: &Matrix) {
let (frame_output, encoder) = if let Some((frame_output, encoder)) = &mut self.current_frame
{
(frame_output, encoder)
} else {
return;
};
let world_matrix = [
[matrix.a, matrix.b, 0.0, 0.0],
[matrix.c, matrix.d, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[
matrix.tx.to_pixels() as f32,
matrix.ty.to_pixels() as f32,
0.0,
1.0,
],
];
let mult_color = [
f32::from(color.r) / 255.0,
f32::from(color.g) / 255.0,
f32::from(color.b) / 255.0,
f32::from(color.a) / 255.0,
];
let add_color = [0.0, 0.0, 0.0, 0.0];
let transforms_ubo = create_buffer_with_data(
&self.device,
bytemuck::cast_slice(&[Transforms {
view_matrix: self.view_matrix,
world_matrix,
}]),
wgpu::BufferUsage::UNIFORM,
create_debug_label!("Rectangle transfer buffer"),
);
let colors_ubo = create_buffer_with_data(
&self.device,
bytemuck::cast_slice(&[ColorAdjustments {
mult_color,
add_color,
}]),
wgpu::BufferUsage::UNIFORM,
create_debug_label!("Rectangle colors transfer buffer"),
);
let bind_group_label = create_debug_label!("Rectangle bind group");
let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &self.pipelines.color.bind_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(
transforms_ubo.slice(0..std::mem::size_of::<Transforms>() as u64),
),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Buffer(
colors_ubo.slice(0..std::mem::size_of::<ColorAdjustments>() as u64),
),
},
],
label: bind_group_label.as_deref(),
});
let (color_attachment, resolve_target) = if self.msaa_sample_count >= 2 {
(&self.frame_buffer_view, Some(frame_output.view()))
} else {
(frame_output.view(), None)
};
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: color_attachment,
resolve_target,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
},
}],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor {
attachment: &self.depth_texture_view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
stencil_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
}),
});
render_pass.set_pipeline(&self.pipelines.color.pipeline_for(
self.num_masks,
self.num_masks_active,
self.test_stencil_mask,
self.write_stencil_mask,
));
render_pass.set_bind_group(0, &bind_group, &[]);
render_pass.set_vertex_buffer(0, self.quad_vbo.slice(..));
render_pass.set_index_buffer(self.quad_ibo.slice(..));
if self.num_masks_active < self.num_masks {
render_pass.set_stencil_reference(self.write_stencil_mask);
} else {
render_pass.set_stencil_reference(self.test_stencil_mask);
}
render_pass.draw_indexed(0..6, 0, 0..1);
}
fn end_frame(&mut self) {
if let Some((_frame, encoder)) = self.current_frame.take() {
let register_encoder_label = create_debug_label!("Register encoder");
@ -1272,54 +1277,66 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
Letterbox::None => {}
Letterbox::Letterbox(margin) => {
self.draw_rect(
0.0,
0.0,
self.viewport_width,
margin,
Color {
r: 0,
g: 0,
b: 0,
a: 255,
},
&Matrix::create_box(
self.viewport_width,
margin,
0.0,
Twips::zero(),
Twips::zero(),
),
);
self.draw_rect(
0.0,
self.viewport_height - margin,
self.viewport_width,
margin,
Color {
r: 0,
g: 0,
b: 0,
a: 255,
},
&Matrix::create_box(
self.viewport_width,
margin,
0.0,
Twips::zero(),
Twips::from_pixels((self.viewport_height - margin) as f64),
),
);
}
Letterbox::Pillarbox(margin) => {
self.draw_rect(
0.0,
0.0,
margin,
self.viewport_height,
Color {
r: 0,
g: 0,
b: 0,
a: 255,
},
&Matrix::create_box(
margin,
self.viewport_height,
0.0,
Twips::zero(),
Twips::zero(),
),
);
self.draw_rect(
self.viewport_width - margin,
0.0,
margin,
self.viewport_height,
Color {
r: 0,
g: 0,
b: 0,
a: 255,
},
&Matrix::create_box(
margin,
self.viewport_height,
0.0,
Twips::from_pixels((self.viewport_width - margin) as f64),
Twips::zero(),
),
);
}
}