use std::sync::Arc;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
};
use rootvg::image::{ImagePrimitive, RcTexture};
use rootvg::math::{PhysicalSizeI32, Point, Rect, ScaleFactor, Size};
use rootvg::quad::{SolidQuad, SolidQuadPrimitive};
use rootvg::{
color::{PackedSrgb, RGBA8},
math::PhysicalSizeU32,
};
const PREPASS_TEXTURE_SIZE: PhysicalSizeU32 = PhysicalSizeU32::new(200, 200);
static SHADER: &'static str = "
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
};
@vertex
fn vs_main(
@builtin(vertex_index) in_vertex_index: u32,
) -> VertexOutput {
var out: VertexOutput;
let x = f32(1 - i32(in_vertex_index)) * 0.9;
let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.9;
out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return vec4<f32>(0.8, 0.1, 0.1, 1.0);
}
";
fn main() {
let env = env_logger::Env::default().filter_or("LOG_LEVEL", "info");
env_logger::init_from_env(env);
let (width, height) = (800, 425);
let event_loop = EventLoop::new().unwrap();
let window = Arc::new(
WindowBuilder::new()
.with_inner_size(winit::dpi::LogicalSize::new(width as f64, height as f64))
.with_title("RootVG Demo")
.build(&event_loop)
.unwrap(),
);
let physical_size = window.inner_size();
let mut physical_size =
PhysicalSizeI32::new(physical_size.width as i32, physical_size.height as i32);
let mut scale_factor: ScaleFactor = window.scale_factor().into();
let mut surface = rootvg::surface::DefaultSurface::new(
physical_size,
scale_factor,
Arc::clone(&window),
rootvg::surface::DefaultSurfaceConfig::default(),
)
.unwrap();
let clear_color: PackedSrgb = RGBA8::new(15, 15, 15, 255).into();
let mut canvas = rootvg::Canvas::new(
&surface.device,
&surface.queue,
surface.format(),
surface.canvas_config(),
);
let prepass_shader = surface
.device
.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Shader"),
source: wgpu::ShaderSource::Wgsl(SHADER.into()),
});
let prepass_pipeline_layout =
surface
.device
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[],
push_constant_ranges: &[],
});
let prepass_pipeline = surface
.device
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&prepass_pipeline_layout),
vertex: wgpu::VertexState {
module: &prepass_shader,
entry_point: "vs_main",
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
module: &prepass_shader,
entry_point: "fs_main",
targets: &[Some(wgpu::ColorTargetState {
format: surface.format(),
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
});
let texture_size = wgpu::Extent3d {
width: PREPASS_TEXTURE_SIZE.width,
height: PREPASS_TEXTURE_SIZE.height,
depth_or_array_layers: 1,
};
let prepass_texture = surface.device.create_texture(&wgpu::TextureDescriptor {
size: texture_size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: surface.format(),
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
label: Some("prepass_texture"),
view_formats: &[],
});
let prepass_rc_texture = RcTexture::from_prepass_texture(
prepass_texture.create_view(&wgpu::TextureViewDescriptor::default()),
PREPASS_TEXTURE_SIZE,
);
let image_primitive = ImagePrimitive::new(prepass_rc_texture, Point::new(180.0, 100.0));
event_loop
.run(move |event, target| {
if let Event::WindowEvent {
window_id: _,
event,
} = event
{
match event {
WindowEvent::Resized(new_size) => {
physical_size =
PhysicalSizeI32::new(new_size.width as i32, new_size.height as i32);
surface.resize(physical_size, scale_factor);
window.request_redraw();
}
WindowEvent::ScaleFactorChanged {
scale_factor: new_scale,
inner_size_writer: _,
} => {
scale_factor = new_scale.into();
surface.resize(physical_size, scale_factor);
window.request_redraw();
}
WindowEvent::RedrawRequested => {
{
let mut cx = canvas.begin(physical_size, scale_factor);
cx.add(SolidQuadPrimitive::new(&SolidQuad {
bounds: Rect::new(Point::new(100.0, 50.0), Size::new(200.0, 200.0)),
bg_color: RGBA8::new(100, 100, 100, 255).into(),
..Default::default()
}));
cx.set_z_index(1);
cx.add(image_primitive.clone());
cx.set_z_index(2);
cx.add(SolidQuadPrimitive::new(&SolidQuad {
bounds: Rect::new(Point::new(275.0, 70.0), Size::new(200.0, 200.0)),
bg_color: RGBA8::new(200, 100, 200, 100).into(),
..Default::default()
}));
}
let mut encoder = surface.device.create_command_encoder(
&wgpu::CommandEncoderDescriptor { label: None },
);
{
let view = prepass_texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut pre_render_pass =
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 0.0,
}),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
occlusion_query_set: None,
timestamp_writes: None,
});
pre_render_pass.set_pipeline(&prepass_pipeline);
pre_render_pass.draw(0..3, 0..1);
}
let frame = surface.get_current_texture().unwrap();
let view = frame
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
canvas
.render_to_target(
Some(clear_color),
&surface.device,
&surface.queue,
&mut encoder,
&view,
physical_size,
)
.unwrap();
surface.queue.submit(Some(encoder.finish()));
frame.present();
}
WindowEvent::CloseRequested => target.exit(),
_ => {}
}
}
})
.unwrap();
}