use crate::render::adapter::wgpu::pixel::WgpuPixelRender;
use crate::render::adapter::wgpu::WgpuRender;
use crate::render::adapter::{RenderCell, RtComposite};
use crate::render::graph::{UnifiedColor, UnifiedTransform};
pub struct WgpuRenderCore {
pub device: wgpu::Device,
pub queue: wgpu::Queue,
pub pixel_renderer: WgpuPixelRender,
pub ratio_x: f32,
pub ratio_y: f32,
pub render_scale: f32,
}
impl WgpuRenderCore {
pub fn new(
device: wgpu::Device,
queue: wgpu::Queue,
pixel_renderer: WgpuPixelRender,
ratio_x: f32,
ratio_y: f32,
) -> Self {
Self {
device,
queue,
pixel_renderer,
ratio_x,
ratio_y,
render_scale: 1.0,
}
}
pub fn set_render_scale(&mut self, scale: f32) {
self.render_scale = scale;
self.pixel_renderer.set_render_scale(scale);
}
pub fn set_ratio(&mut self, rx: f32, ry: f32) {
self.ratio_x = rx;
self.ratio_y = ry;
self.pixel_renderer.set_ratio(rx, ry);
}
pub fn set_sharpness(&mut self, sharpness: f32) {
self.pixel_renderer.set_sharpness(sharpness);
}
pub fn canvas_size(&self) -> (u32, u32) {
(self.pixel_renderer.canvas_width, self.pixel_renderer.canvas_height)
}
pub fn set_viewport_scale(&mut self, scale: f32) {
self.pixel_renderer.set_viewport_scale(scale);
}
pub fn rbuf2rt(&mut self, rbuf: &[RenderCell], rtidx: usize, debug: bool) {
self.pixel_renderer.bind_target(rtidx);
if debug {
self.pixel_renderer.set_clear_color(UnifiedColor::new(1.0, 0.0, 0.0, 1.0));
} else {
self.pixel_renderer.set_clear_color(UnifiedColor::new(0.0, 0.0, 0.0, 1.0));
}
self.pixel_renderer.clear();
self.pixel_renderer.render_rbuf(&self.device, &self.queue, rbuf, self.ratio_x, self.ratio_y);
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some(&format!("Render to RT{} Encoder", rtidx)),
});
if let Err(e) = self.pixel_renderer.render_to_current_target(&mut encoder, None) {
log::error!("WgpuRenderCore: render error: {}", e);
return;
}
self.queue.submit(std::iter::once(encoder.finish()));
}
pub fn set_rt_visible(&mut self, texture_index: usize, visible: bool) {
self.pixel_renderer.set_render_texture_hidden(texture_index, !visible);
}
pub fn get_rt_hidden(&self, texture_index: usize) -> bool {
self.pixel_renderer.get_render_texture_hidden(texture_index)
}
pub fn blend_rts(&mut self, src1: usize, src2: usize, target: usize, effect: usize, progress: f32) {
self.pixel_renderer.set_render_texture_hidden(target, false);
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Transition Encoder"),
});
if let Err(e) = self.pixel_renderer.render_trans_frame_to_texture(
&self.device,
&self.queue,
&mut encoder,
src1,
src2,
target,
effect,
progress,
) {
log::error!("WgpuRenderCore: transition error: {}", e);
return;
}
self.queue.submit(std::iter::once(encoder.finish()));
}
pub fn copy_rt(&mut self, src_index: usize, dst_index: usize) {
self.pixel_renderer.copy_rt(&self.device, &self.queue, src_index, dst_index);
}
pub fn present(&mut self, surface_view: &wgpu::TextureView, composites: &[RtComposite]) {
self.pixel_renderer.bind_screen();
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Present Encoder"),
});
{
let _clear_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Clear Screen Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: surface_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: None,
occlusion_query_set: None,
timestamp_writes: None,
});
}
let pcw = self.pixel_renderer.canvas_width as f32;
let pch = self.pixel_renderer.canvas_height as f32;
for composite in composites {
let rtidx = composite.rt;
if self.pixel_renderer.get_render_texture_hidden(rtidx) {
continue;
}
let (area, transform) = if let Some(ref vp) = composite.viewport {
let rs = self.render_scale;
let vp_x = vp.x as f32 * rs;
let vp_y = vp.y as f32 * rs;
let pw = vp.w as f32 * rs;
let ph = vp.h as f32 * rs;
let (content_w, content_h) = composite.content_size
.map(|(w, h)| (w as f32 * rs, h as f32 * rs))
.unwrap_or((pw, ph));
let area = [0.0, 0.0, content_w / pcw, content_h / pch];
let mut base_transform = UnifiedTransform::new();
base_transform.scale(pw / pcw, ph / pch);
let tx = (2.0 * vp_x + pw - pcw) / pcw;
let ty = (pch - 2.0 * vp_y - ph) / pch;
base_transform.translate(tx, ty);
let final_transform = if let Some(ref user_transform) = composite.transform {
base_transform.compose(user_transform)
} else {
base_transform
};
(area, final_transform)
} else {
let area = [0.0, 0.0, 1.0, 1.0];
let transform = composite.transform.unwrap_or_else(UnifiedTransform::new);
(area, transform)
};
let alpha_f = composite.alpha as f32 / 255.0;
let color = UnifiedColor::new(1.0, 1.0, 1.0, alpha_f);
if let Err(e) = self.pixel_renderer.render_texture_to_screen_impl(
&self.device,
&self.queue,
&mut encoder,
surface_view,
rtidx,
area,
&transform,
&color,
) {
log::error!("WgpuRenderCore: present error: {}", e);
}
}
self.queue.submit(std::iter::once(encoder.finish()));
}
pub fn present_default(&mut self, surface_view: &wgpu::TextureView) {
self.present(surface_view, &[RtComposite::fullscreen(2)]);
}
}
pub struct WgpuRenderCoreBuilder {
pub canvas_width: u32,
pub canvas_height: u32,
pub surface_format: wgpu::TextureFormat,
pub ratio_x: f32,
pub ratio_y: f32,
pub render_scale: f32,
}
impl WgpuRenderCoreBuilder {
pub fn new(canvas_width: u32, canvas_height: u32, surface_format: wgpu::TextureFormat) -> Self {
Self {
canvas_width,
canvas_height,
surface_format,
ratio_x: 1.0,
ratio_y: 1.0,
render_scale: 1.0,
}
}
pub fn with_ratio(mut self, rx: f32, ry: f32) -> Self {
self.ratio_x = rx;
self.ratio_y = ry;
self
}
pub fn with_render_scale(mut self, scale: f32) -> Self {
self.render_scale = scale;
self
}
pub fn build_layered(
self,
device: wgpu::Device,
queue: wgpu::Queue,
layer_size: u32,
layers: &[&[u8]],
) -> Result<WgpuRenderCore, String> {
let mut pixel_renderer = WgpuPixelRender::new_with_format(
self.canvas_width,
self.canvas_height,
self.surface_format,
);
pixel_renderer.load_symbol_texture_array(&device, &queue, layer_size, layers)?;
pixel_renderer.create_shader(&device);
pixel_renderer.create_buffer(&device);
pixel_renderer.create_bind_group(&device);
pixel_renderer.init_render_textures(&device, &queue)?;
pixel_renderer.init_general2d_renderer(&device);
pixel_renderer.init_transition_renderer(&device);
pixel_renderer.set_ratio(self.ratio_x, self.ratio_y);
pixel_renderer.set_render_scale(self.render_scale);
let mut core = WgpuRenderCore::new(
device,
queue,
pixel_renderer,
self.ratio_x,
self.ratio_y,
);
core.render_scale = self.render_scale;
Ok(core)
}
}