Refactor the demo some more.
Move rendering code into its own module and split up `finish_drawing_frame()`.
This commit is contained in:
parent
29b137c81d
commit
4a4011d303
|
@ -17,22 +17,18 @@ use crate::camera::{Camera, Mode};
|
||||||
use crate::concurrent::DemoExecutor;
|
use crate::concurrent::DemoExecutor;
|
||||||
use crate::device::{GroundProgram, GroundVertexArray};
|
use crate::device::{GroundProgram, GroundVertexArray};
|
||||||
use crate::ui::{DemoUI, UIAction};
|
use crate::ui::{DemoUI, UIAction};
|
||||||
use crate::window::{Event, Keycode, SVGPath, View, Window, WindowSize};
|
use crate::window::{Event, Keycode, SVGPath, Window, WindowSize};
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use image::ColorType;
|
|
||||||
use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32};
|
use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32};
|
||||||
use pathfinder_geometry::basic::rect::RectF32;
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
use pathfinder_geometry::basic::transform3d::Transform3DF32;
|
use pathfinder_geometry::color::ColorU;
|
||||||
use pathfinder_geometry::color::{ColorF, ColorU};
|
|
||||||
use pathfinder_gl::GLDevice;
|
use pathfinder_gl::GLDevice;
|
||||||
|
use pathfinder_gpu::Device;
|
||||||
use pathfinder_gpu::resources::ResourceLoader;
|
use pathfinder_gpu::resources::ResourceLoader;
|
||||||
use pathfinder_gpu::{ClearParams, DepthFunc, DepthState, Device, Primitive, RenderState};
|
|
||||||
use pathfinder_gpu::{TextureFormat, UniformData};
|
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy};
|
use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy};
|
||||||
use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderMode, RenderStats, Renderer};
|
use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderStats, Renderer};
|
||||||
use pathfinder_renderer::gpu_data::RenderCommand;
|
|
||||||
use pathfinder_renderer::options::{RenderOptions, RenderTransform};
|
use pathfinder_renderer::options::{RenderOptions, RenderTransform};
|
||||||
use pathfinder_renderer::post::{DEFRINGING_KERNEL_CORE_GRAPHICS, STEM_DARKENING_FACTORS};
|
use pathfinder_renderer::post::STEM_DARKENING_FACTORS;
|
||||||
use pathfinder_renderer::scene::Scene;
|
use pathfinder_renderer::scene::Scene;
|
||||||
use pathfinder_svg::BuiltSVG;
|
use pathfinder_svg::BuiltSVG;
|
||||||
use pathfinder_ui::{MousePosition, UIEvent};
|
use pathfinder_ui::{MousePosition, UIEvent};
|
||||||
|
@ -72,30 +68,16 @@ const TRANSPARENT_BG_COLOR: ColorU = ColorU {
|
||||||
a: 0,
|
a: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const GROUND_SOLID_COLOR: ColorU = ColorU {
|
|
||||||
r: 80,
|
|
||||||
g: 80,
|
|
||||||
b: 80,
|
|
||||||
a: 255,
|
|
||||||
};
|
|
||||||
const GROUND_LINE_COLOR: ColorU = ColorU {
|
|
||||||
r: 127,
|
|
||||||
g: 127,
|
|
||||||
b: 127,
|
|
||||||
a: 255,
|
|
||||||
};
|
|
||||||
|
|
||||||
const APPROX_FONT_SIZE: f32 = 16.0;
|
const APPROX_FONT_SIZE: f32 = 16.0;
|
||||||
|
|
||||||
const MESSAGE_TIMEOUT_SECS: u64 = 5;
|
const MESSAGE_TIMEOUT_SECS: u64 = 5;
|
||||||
|
|
||||||
pub const GRIDLINE_COUNT: i32 = 10;
|
|
||||||
|
|
||||||
pub mod window;
|
pub mod window;
|
||||||
|
|
||||||
mod camera;
|
mod camera;
|
||||||
mod concurrent;
|
mod concurrent;
|
||||||
mod device;
|
mod device;
|
||||||
|
mod renderer;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
pub struct DemoApp<W> where W: Window {
|
pub struct DemoApp<W> where W: Window {
|
||||||
|
@ -224,61 +206,8 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let transform = self.render_transform.clone().unwrap();
|
let transform = self.render_transform.clone().unwrap();
|
||||||
self.current_frame = Some(Frame::new(transform, ui_events));
|
self.current_frame = Some(Frame::new(transform, ui_events));
|
||||||
|
|
||||||
// Initialize and set the appropriate framebuffer.
|
// Prepare to render the frame.
|
||||||
let view = self.ui.mode.view(0);
|
self.prepare_frame_rendering()
|
||||||
self.window.make_current(view);
|
|
||||||
let window_size = self.window_size.device_size();
|
|
||||||
let scene_count = match self.camera.mode() {
|
|
||||||
Mode::VR => {
|
|
||||||
let viewport = self.window.viewport(View::Stereo(0));
|
|
||||||
if self.scene_framebuffer.is_none()
|
|
||||||
|| self.renderer.device.texture_size(
|
|
||||||
&self
|
|
||||||
.renderer
|
|
||||||
.device
|
|
||||||
.framebuffer_texture(self.scene_framebuffer.as_ref().unwrap()),
|
|
||||||
) != viewport.size()
|
|
||||||
{
|
|
||||||
let scene_texture = self
|
|
||||||
.renderer
|
|
||||||
.device
|
|
||||||
.create_texture(TextureFormat::RGBA8, viewport.size());
|
|
||||||
self.scene_framebuffer =
|
|
||||||
Some(self.renderer.device.create_framebuffer(scene_texture));
|
|
||||||
}
|
|
||||||
self.renderer
|
|
||||||
.replace_dest_framebuffer(DestFramebuffer::Other(
|
|
||||||
self.scene_framebuffer.take().unwrap(),
|
|
||||||
));
|
|
||||||
2
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.renderer
|
|
||||||
.replace_dest_framebuffer(DestFramebuffer::Default {
|
|
||||||
viewport: self.window.viewport(View::Mono),
|
|
||||||
window_size,
|
|
||||||
});
|
|
||||||
1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Begin drawing the scene.
|
|
||||||
self.renderer.bind_dest_framebuffer();
|
|
||||||
|
|
||||||
// Clear to the appropriate color.
|
|
||||||
let clear_color = if scene_count == 2 {
|
|
||||||
ColorF::transparent_black()
|
|
||||||
} else {
|
|
||||||
self.background_color().to_f32()
|
|
||||||
};
|
|
||||||
self.renderer.device.clear(&ClearParams {
|
|
||||||
color: Some(clear_color),
|
|
||||||
depth: Some(1.0),
|
|
||||||
stencil: Some(0),
|
|
||||||
..ClearParams::default()
|
|
||||||
});
|
|
||||||
|
|
||||||
scene_count
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_scene(&mut self) {
|
fn build_scene(&mut self) {
|
||||||
|
@ -501,155 +430,12 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
MousePosition { absolute, relative }
|
MousePosition { absolute, relative }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_scene(&mut self) {
|
|
||||||
let view = self.ui.mode.view(0);
|
|
||||||
self.window.make_current(view);
|
|
||||||
|
|
||||||
if self.camera.mode() != Mode::VR {
|
|
||||||
self.draw_environment();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.render_vector_scene();
|
|
||||||
|
|
||||||
// Reattach default framebuffer.
|
|
||||||
if self.camera.mode() != Mode::VR {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let DestFramebuffer::Other(scene_framebuffer) =
|
|
||||||
self.renderer
|
|
||||||
.replace_dest_framebuffer(DestFramebuffer::Default {
|
|
||||||
viewport: self.window.viewport(View::Mono),
|
|
||||||
window_size: self.window_size.device_size(),
|
|
||||||
})
|
|
||||||
{
|
|
||||||
self.scene_framebuffer = Some(scene_framebuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn composite_scene(&mut self, render_scene_index: u32) {
|
|
||||||
let (eye_transforms, scene_transform, modelview_transform) = match self.camera {
|
|
||||||
Camera::ThreeD {
|
|
||||||
ref eye_transforms,
|
|
||||||
ref scene_transform,
|
|
||||||
ref modelview_transform,
|
|
||||||
..
|
|
||||||
} if eye_transforms.len() > 1 => (eye_transforms, scene_transform, modelview_transform),
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!(
|
|
||||||
"scene_transform.perspective={:?}",
|
|
||||||
scene_transform.perspective
|
|
||||||
);
|
|
||||||
debug!(
|
|
||||||
"scene_transform.modelview_to_eye={:?}",
|
|
||||||
scene_transform.modelview_to_eye
|
|
||||||
);
|
|
||||||
debug!("modelview transform={:?}", modelview_transform);
|
|
||||||
|
|
||||||
let viewport = self.window.viewport(View::Stereo(render_scene_index));
|
|
||||||
self.renderer
|
|
||||||
.replace_dest_framebuffer(DestFramebuffer::Default {
|
|
||||||
viewport,
|
|
||||||
window_size: self.window_size.device_size(),
|
|
||||||
});
|
|
||||||
|
|
||||||
self.renderer.bind_draw_framebuffer();
|
|
||||||
self.renderer.device.clear(&ClearParams {
|
|
||||||
color: Some(self.background_color().to_f32()),
|
|
||||||
depth: Some(1.0),
|
|
||||||
stencil: Some(0),
|
|
||||||
rect: Some(viewport),
|
|
||||||
});
|
|
||||||
|
|
||||||
self.draw_environment();
|
|
||||||
|
|
||||||
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
|
|
||||||
let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer);
|
|
||||||
|
|
||||||
let quad_scale_transform = Transform3DF32::from_scale(
|
|
||||||
self.scene_metadata.view_box.size().x(),
|
|
||||||
self.scene_metadata.view_box.size().y(),
|
|
||||||
1.0,
|
|
||||||
);
|
|
||||||
|
|
||||||
let scene_transform_matrix = scene_transform
|
|
||||||
.perspective
|
|
||||||
.post_mul(&scene_transform.modelview_to_eye)
|
|
||||||
.post_mul(&modelview_transform.to_transform())
|
|
||||||
.post_mul(&quad_scale_transform);
|
|
||||||
|
|
||||||
let eye_transform = &eye_transforms[render_scene_index as usize];
|
|
||||||
let eye_transform_matrix = eye_transform
|
|
||||||
.perspective
|
|
||||||
.post_mul(&eye_transform.modelview_to_eye)
|
|
||||||
.post_mul(&modelview_transform.to_transform())
|
|
||||||
.post_mul(&quad_scale_transform);
|
|
||||||
|
|
||||||
debug!(
|
|
||||||
"eye transform({}).modelview_to_eye={:?}",
|
|
||||||
render_scene_index, eye_transform.modelview_to_eye
|
|
||||||
);
|
|
||||||
debug!(
|
|
||||||
"eye transform_matrix({})={:?}",
|
|
||||||
render_scene_index, eye_transform_matrix
|
|
||||||
);
|
|
||||||
debug!("---");
|
|
||||||
|
|
||||||
self.renderer.reproject_texture(
|
|
||||||
scene_texture,
|
|
||||||
&scene_transform_matrix.transform,
|
|
||||||
&eye_transform_matrix.transform,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish_drawing_frame(&mut self) {
|
pub fn finish_drawing_frame(&mut self) {
|
||||||
if let Some(rendering_time) = self.renderer.shift_timer_query() {
|
self.maybe_take_screenshot();
|
||||||
self.current_frame
|
self.update_stats();
|
||||||
.as_mut()
|
self.draw_debug_ui();
|
||||||
.unwrap()
|
|
||||||
.scene_rendering_times
|
|
||||||
.push(rendering_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
let build_time = self.build_time.unwrap();
|
|
||||||
let mut frame = self.current_frame.take().unwrap();
|
|
||||||
|
|
||||||
if self.pending_screenshot_path.is_some() {
|
|
||||||
self.take_screenshot();
|
|
||||||
}
|
|
||||||
|
|
||||||
if !frame.scene_stats.is_empty() || !frame.scene_rendering_times.is_empty() {
|
|
||||||
let zero = RenderStats::default();
|
|
||||||
let aggregate_stats = frame.scene_stats.iter().fold(zero, |sum, item| sum + *item);
|
|
||||||
let total_rendering_time = if frame.scene_rendering_times.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let zero = Duration::new(0, 0);
|
|
||||||
Some(
|
|
||||||
frame
|
|
||||||
.scene_rendering_times
|
|
||||||
.iter()
|
|
||||||
.fold(zero, |sum, item| sum + *item),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
self.renderer
|
|
||||||
.debug_ui
|
|
||||||
.add_sample(aggregate_stats, build_time, total_rendering_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.options.ui != UIVisibility::None {
|
|
||||||
let viewport = self.window.viewport(View::Mono);
|
|
||||||
self.window.make_current(View::Mono);
|
|
||||||
self.renderer
|
|
||||||
.replace_dest_framebuffer(DestFramebuffer::Default {
|
|
||||||
viewport,
|
|
||||||
window_size: self.window_size.device_size(),
|
|
||||||
});
|
|
||||||
self.renderer.draw_debug_ui();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let frame = self.current_frame.take().unwrap();
|
||||||
for ui_event in &frame.ui_events {
|
for ui_event in &frame.ui_events {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
self.renderer.debug_ui.ui.event_queue.push(*ui_event);
|
self.renderer.debug_ui.ui.event_queue.push(*ui_event);
|
||||||
|
@ -670,8 +456,46 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
&mut ui_action,
|
&mut ui_action,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.handle_ui_events(frame, &mut ui_action);
|
||||||
|
|
||||||
|
self.window.present();
|
||||||
|
self.frame_counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_stats(&mut self) {
|
||||||
|
let frame = self.current_frame.as_mut().unwrap();
|
||||||
|
if let Some(rendering_time) = self.renderer.shift_timer_query() {
|
||||||
|
frame.scene_rendering_times.push(rendering_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
if frame.scene_stats.is_empty() && frame.scene_rendering_times.is_empty() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let build_time = self.build_time.unwrap();
|
||||||
|
|
||||||
|
let zero = RenderStats::default();
|
||||||
|
let aggregate_stats = frame.scene_stats.iter().fold(zero, |sum, item| sum + *item);
|
||||||
|
let total_rendering_time = if frame.scene_rendering_times.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let zero = Duration::new(0, 0);
|
||||||
|
Some(
|
||||||
|
frame
|
||||||
|
.scene_rendering_times
|
||||||
|
.iter()
|
||||||
|
.fold(zero, |sum, item| sum + *item),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.renderer.debug_ui.add_sample(aggregate_stats, build_time, total_rendering_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_ui_events(&mut self, mut frame: Frame, ui_action: &mut UIAction) {
|
||||||
frame.ui_events = self.renderer.debug_ui.ui.event_queue.drain();
|
frame.ui_events = self.renderer.debug_ui.ui.event_queue.drain();
|
||||||
self.handle_ui_action(&mut ui_action);
|
|
||||||
|
self.handle_ui_action(ui_action);
|
||||||
|
|
||||||
// Switch camera mode (2D/3D) if requested.
|
// Switch camera mode (2D/3D) if requested.
|
||||||
//
|
//
|
||||||
|
@ -695,111 +519,6 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.window.present();
|
|
||||||
self.frame_counter += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_environment(&self) {
|
|
||||||
// TODO(pcwalton): Use the viewport index!
|
|
||||||
|
|
||||||
let frame = &self.current_frame.as_ref().unwrap();
|
|
||||||
|
|
||||||
let perspective = match frame.transform {
|
|
||||||
RenderTransform::Transform2D(..) => return,
|
|
||||||
RenderTransform::Perspective(perspective) => perspective,
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.ui.background_color == BackgroundColor::Transparent {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ground_scale = self.scene_metadata.view_box.max_x() * 2.0;
|
|
||||||
|
|
||||||
let mut base_transform = perspective.transform;
|
|
||||||
base_transform = base_transform.post_mul(&Transform3DF32::from_translation(
|
|
||||||
-0.5 * self.scene_metadata.view_box.max_x(),
|
|
||||||
self.scene_metadata.view_box.max_y(),
|
|
||||||
-0.5 * ground_scale,
|
|
||||||
));
|
|
||||||
|
|
||||||
// Fill ground.
|
|
||||||
let mut transform = base_transform;
|
|
||||||
transform =
|
|
||||||
transform.post_mul(&Transform3DF32::from_scale(ground_scale, 1.0, ground_scale));
|
|
||||||
|
|
||||||
let device = &self.renderer.device;
|
|
||||||
device.bind_vertex_array(&self.ground_vertex_array.vertex_array);
|
|
||||||
device.use_program(&self.ground_program.program);
|
|
||||||
device.set_uniform(
|
|
||||||
&self.ground_program.transform_uniform,
|
|
||||||
UniformData::from_transform_3d(&transform),
|
|
||||||
);
|
|
||||||
device.set_uniform(
|
|
||||||
&self.ground_program.ground_color_uniform,
|
|
||||||
UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0),
|
|
||||||
);
|
|
||||||
device.set_uniform(
|
|
||||||
&self.ground_program.gridline_color_uniform,
|
|
||||||
UniformData::Vec4(GROUND_LINE_COLOR.to_f32().0),
|
|
||||||
);
|
|
||||||
device.set_uniform(&self.ground_program.gridline_count_uniform,
|
|
||||||
UniformData::Int(GRIDLINE_COUNT));
|
|
||||||
device.draw_arrays(
|
|
||||||
Primitive::TriangleFan,
|
|
||||||
4,
|
|
||||||
&RenderState {
|
|
||||||
depth: Some(DepthState {
|
|
||||||
func: DepthFunc::Less,
|
|
||||||
write: true,
|
|
||||||
}),
|
|
||||||
stencil: None,
|
|
||||||
..RenderState::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_vector_scene(&mut self) {
|
|
||||||
match self.scene_metadata.monochrome_color {
|
|
||||||
None => self.renderer.set_render_mode(RenderMode::Multicolor),
|
|
||||||
Some(fg_color) => {
|
|
||||||
self.renderer.set_render_mode(RenderMode::Monochrome {
|
|
||||||
fg_color: fg_color.to_f32(),
|
|
||||||
bg_color: self.background_color().to_f32(),
|
|
||||||
gamma_correction: self.ui.gamma_correction_effect_enabled,
|
|
||||||
defringing_kernel: if self.ui.subpixel_aa_effect_enabled {
|
|
||||||
// TODO(pcwalton): Select FreeType defringing kernel as necessary.
|
|
||||||
Some(DEFRINGING_KERNEL_CORE_GRAPHICS)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.ui.mode == Mode::TwoD {
|
|
||||||
self.renderer.disable_depth();
|
|
||||||
} else {
|
|
||||||
self.renderer.enable_depth();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.renderer.begin_scene();
|
|
||||||
|
|
||||||
// Issue render commands!
|
|
||||||
for command in self.render_command_stream.as_mut().unwrap() {
|
|
||||||
self.renderer.render_command(&command);
|
|
||||||
|
|
||||||
if let RenderCommand::Finish { build_time } = command {
|
|
||||||
self.build_time = Some(build_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.current_frame
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scene_stats
|
|
||||||
.push(self.renderer.stats);
|
|
||||||
self.renderer.end_scene();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_ui_action(&mut self, ui_action: &mut UIAction) {
|
fn handle_ui_action(&mut self, ui_action: &mut UIAction) {
|
||||||
|
@ -845,23 +564,6 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_screenshot(&mut self) {
|
|
||||||
let screenshot_path = self.pending_screenshot_path.take().unwrap();
|
|
||||||
let drawable_size = self.window_size.device_size();
|
|
||||||
let pixels = self
|
|
||||||
.renderer
|
|
||||||
.device
|
|
||||||
.read_pixels_from_default_framebuffer(drawable_size);
|
|
||||||
image::save_buffer(
|
|
||||||
screenshot_path,
|
|
||||||
&pixels,
|
|
||||||
drawable_size.x() as u32,
|
|
||||||
drawable_size.y() as u32,
|
|
||||||
ColorType::RGBA(8),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn background_color(&self) -> ColorU {
|
fn background_color(&self) -> ColorU {
|
||||||
match self.ui.background_color {
|
match self.ui.background_color {
|
||||||
BackgroundColor::Light => LIGHT_BG_COLOR,
|
BackgroundColor::Light => LIGHT_BG_COLOR,
|
||||||
|
|
|
@ -0,0 +1,338 @@
|
||||||
|
// pathfinder/demo/common/src/renderer.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2019 The Pathfinder Project Developers.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Rendering functionality for the demo.
|
||||||
|
|
||||||
|
use crate::camera::{Camera, Mode};
|
||||||
|
use crate::window::{View, Window};
|
||||||
|
use crate::{BackgroundColor, DemoApp, UIVisibility};
|
||||||
|
use image::ColorType;
|
||||||
|
use pathfinder_geometry::color::{ColorF, ColorU};
|
||||||
|
use pathfinder_gpu::{ClearParams, DepthFunc, DepthState, Device, Primitive, RenderState};
|
||||||
|
use pathfinder_gpu::{TextureFormat, UniformData};
|
||||||
|
use pathfinder_geometry::basic::transform3d::Transform3DF32;
|
||||||
|
use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderMode};
|
||||||
|
use pathfinder_renderer::gpu_data::RenderCommand;
|
||||||
|
use pathfinder_renderer::options::RenderTransform;
|
||||||
|
use pathfinder_renderer::post::DEFRINGING_KERNEL_CORE_GRAPHICS;
|
||||||
|
|
||||||
|
const GROUND_SOLID_COLOR: ColorU = ColorU {
|
||||||
|
r: 80,
|
||||||
|
g: 80,
|
||||||
|
b: 80,
|
||||||
|
a: 255,
|
||||||
|
};
|
||||||
|
|
||||||
|
const GROUND_LINE_COLOR: ColorU = ColorU {
|
||||||
|
r: 127,
|
||||||
|
g: 127,
|
||||||
|
b: 127,
|
||||||
|
a: 255,
|
||||||
|
};
|
||||||
|
|
||||||
|
const GRIDLINE_COUNT: i32 = 10;
|
||||||
|
|
||||||
|
impl<W> DemoApp<W> where W: Window {
|
||||||
|
pub fn prepare_frame_rendering(&mut self) -> u32 {
|
||||||
|
// Make the GL context current.
|
||||||
|
let view = self.ui.mode.view(0);
|
||||||
|
self.window.make_current(view);
|
||||||
|
|
||||||
|
// Set up framebuffers.
|
||||||
|
let window_size = self.window_size.device_size();
|
||||||
|
let scene_count = match self.camera.mode() {
|
||||||
|
Mode::VR => {
|
||||||
|
let viewport = self.window.viewport(View::Stereo(0));
|
||||||
|
if self.scene_framebuffer.is_none()
|
||||||
|
|| self.renderer.device.texture_size(
|
||||||
|
&self
|
||||||
|
.renderer
|
||||||
|
.device
|
||||||
|
.framebuffer_texture(self.scene_framebuffer.as_ref().unwrap()),
|
||||||
|
) != viewport.size()
|
||||||
|
{
|
||||||
|
let scene_texture = self
|
||||||
|
.renderer
|
||||||
|
.device
|
||||||
|
.create_texture(TextureFormat::RGBA8, viewport.size());
|
||||||
|
self.scene_framebuffer =
|
||||||
|
Some(self.renderer.device.create_framebuffer(scene_texture));
|
||||||
|
}
|
||||||
|
self.renderer
|
||||||
|
.replace_dest_framebuffer(DestFramebuffer::Other(
|
||||||
|
self.scene_framebuffer.take().unwrap(),
|
||||||
|
));
|
||||||
|
2
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.renderer
|
||||||
|
.replace_dest_framebuffer(DestFramebuffer::Default {
|
||||||
|
viewport: self.window.viewport(View::Mono),
|
||||||
|
window_size,
|
||||||
|
});
|
||||||
|
1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Begin drawing the scene.
|
||||||
|
self.renderer.bind_dest_framebuffer();
|
||||||
|
|
||||||
|
// Clear to the appropriate color.
|
||||||
|
let clear_color = if scene_count == 2 {
|
||||||
|
ColorF::transparent_black()
|
||||||
|
} else {
|
||||||
|
self.background_color().to_f32()
|
||||||
|
};
|
||||||
|
self.renderer.device.clear(&ClearParams {
|
||||||
|
color: Some(clear_color),
|
||||||
|
depth: Some(1.0),
|
||||||
|
stencil: Some(0),
|
||||||
|
..ClearParams::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
scene_count
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_scene(&mut self) {
|
||||||
|
let view = self.ui.mode.view(0);
|
||||||
|
self.window.make_current(view);
|
||||||
|
|
||||||
|
if self.camera.mode() != Mode::VR {
|
||||||
|
self.draw_environment();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.render_vector_scene();
|
||||||
|
|
||||||
|
// Reattach default framebuffer.
|
||||||
|
if self.camera.mode() != Mode::VR {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let DestFramebuffer::Other(scene_framebuffer) =
|
||||||
|
self.renderer
|
||||||
|
.replace_dest_framebuffer(DestFramebuffer::Default {
|
||||||
|
viewport: self.window.viewport(View::Mono),
|
||||||
|
window_size: self.window_size.device_size(),
|
||||||
|
})
|
||||||
|
{
|
||||||
|
self.scene_framebuffer = Some(scene_framebuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn composite_scene(&mut self, render_scene_index: u32) {
|
||||||
|
let (eye_transforms, scene_transform, modelview_transform) = match self.camera {
|
||||||
|
Camera::ThreeD {
|
||||||
|
ref eye_transforms,
|
||||||
|
ref scene_transform,
|
||||||
|
ref modelview_transform,
|
||||||
|
..
|
||||||
|
} if eye_transforms.len() > 1 => (eye_transforms, scene_transform, modelview_transform),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"scene_transform.perspective={:?}",
|
||||||
|
scene_transform.perspective
|
||||||
|
);
|
||||||
|
debug!(
|
||||||
|
"scene_transform.modelview_to_eye={:?}",
|
||||||
|
scene_transform.modelview_to_eye
|
||||||
|
);
|
||||||
|
debug!("modelview transform={:?}", modelview_transform);
|
||||||
|
|
||||||
|
let viewport = self.window.viewport(View::Stereo(render_scene_index));
|
||||||
|
self.renderer
|
||||||
|
.replace_dest_framebuffer(DestFramebuffer::Default {
|
||||||
|
viewport,
|
||||||
|
window_size: self.window_size.device_size(),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.renderer.bind_draw_framebuffer();
|
||||||
|
self.renderer.device.clear(&ClearParams {
|
||||||
|
color: Some(self.background_color().to_f32()),
|
||||||
|
depth: Some(1.0),
|
||||||
|
stencil: Some(0),
|
||||||
|
rect: Some(viewport),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.draw_environment();
|
||||||
|
|
||||||
|
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
|
||||||
|
let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer);
|
||||||
|
|
||||||
|
let quad_scale_transform = Transform3DF32::from_scale(
|
||||||
|
self.scene_metadata.view_box.size().x(),
|
||||||
|
self.scene_metadata.view_box.size().y(),
|
||||||
|
1.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
let scene_transform_matrix = scene_transform
|
||||||
|
.perspective
|
||||||
|
.post_mul(&scene_transform.modelview_to_eye)
|
||||||
|
.post_mul(&modelview_transform.to_transform())
|
||||||
|
.post_mul(&quad_scale_transform);
|
||||||
|
|
||||||
|
let eye_transform = &eye_transforms[render_scene_index as usize];
|
||||||
|
let eye_transform_matrix = eye_transform
|
||||||
|
.perspective
|
||||||
|
.post_mul(&eye_transform.modelview_to_eye)
|
||||||
|
.post_mul(&modelview_transform.to_transform())
|
||||||
|
.post_mul(&quad_scale_transform);
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"eye transform({}).modelview_to_eye={:?}",
|
||||||
|
render_scene_index, eye_transform.modelview_to_eye
|
||||||
|
);
|
||||||
|
debug!(
|
||||||
|
"eye transform_matrix({})={:?}",
|
||||||
|
render_scene_index, eye_transform_matrix
|
||||||
|
);
|
||||||
|
debug!("---");
|
||||||
|
|
||||||
|
self.renderer.reproject_texture(
|
||||||
|
scene_texture,
|
||||||
|
&scene_transform_matrix.transform,
|
||||||
|
&eye_transform_matrix.transform,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draws the ground, if applicable.
|
||||||
|
fn draw_environment(&self) {
|
||||||
|
let frame = &self.current_frame.as_ref().unwrap();
|
||||||
|
|
||||||
|
let perspective = match frame.transform {
|
||||||
|
RenderTransform::Transform2D(..) => return,
|
||||||
|
RenderTransform::Perspective(perspective) => perspective,
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.ui.background_color == BackgroundColor::Transparent {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ground_scale = self.scene_metadata.view_box.max_x() * 2.0;
|
||||||
|
|
||||||
|
let mut base_transform = perspective.transform;
|
||||||
|
base_transform = base_transform.post_mul(&Transform3DF32::from_translation(
|
||||||
|
-0.5 * self.scene_metadata.view_box.max_x(),
|
||||||
|
self.scene_metadata.view_box.max_y(),
|
||||||
|
-0.5 * ground_scale,
|
||||||
|
));
|
||||||
|
|
||||||
|
// Fill ground.
|
||||||
|
let mut transform = base_transform;
|
||||||
|
transform =
|
||||||
|
transform.post_mul(&Transform3DF32::from_scale(ground_scale, 1.0, ground_scale));
|
||||||
|
|
||||||
|
let device = &self.renderer.device;
|
||||||
|
device.bind_vertex_array(&self.ground_vertex_array.vertex_array);
|
||||||
|
device.use_program(&self.ground_program.program);
|
||||||
|
device.set_uniform(
|
||||||
|
&self.ground_program.transform_uniform,
|
||||||
|
UniformData::from_transform_3d(&transform),
|
||||||
|
);
|
||||||
|
device.set_uniform(
|
||||||
|
&self.ground_program.ground_color_uniform,
|
||||||
|
UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0),
|
||||||
|
);
|
||||||
|
device.set_uniform(
|
||||||
|
&self.ground_program.gridline_color_uniform,
|
||||||
|
UniformData::Vec4(GROUND_LINE_COLOR.to_f32().0),
|
||||||
|
);
|
||||||
|
device.set_uniform(&self.ground_program.gridline_count_uniform,
|
||||||
|
UniformData::Int(GRIDLINE_COUNT));
|
||||||
|
device.draw_arrays(
|
||||||
|
Primitive::TriangleFan,
|
||||||
|
4,
|
||||||
|
&RenderState {
|
||||||
|
depth: Some(DepthState { func: DepthFunc::Less, write: true }),
|
||||||
|
..RenderState::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_vector_scene(&mut self) {
|
||||||
|
match self.scene_metadata.monochrome_color {
|
||||||
|
None => self.renderer.set_render_mode(RenderMode::Multicolor),
|
||||||
|
Some(fg_color) => {
|
||||||
|
self.renderer.set_render_mode(RenderMode::Monochrome {
|
||||||
|
fg_color: fg_color.to_f32(),
|
||||||
|
bg_color: self.background_color().to_f32(),
|
||||||
|
gamma_correction: self.ui.gamma_correction_effect_enabled,
|
||||||
|
defringing_kernel: if self.ui.subpixel_aa_effect_enabled {
|
||||||
|
// TODO(pcwalton): Select FreeType defringing kernel as necessary.
|
||||||
|
Some(DEFRINGING_KERNEL_CORE_GRAPHICS)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.ui.mode == Mode::TwoD {
|
||||||
|
self.renderer.disable_depth();
|
||||||
|
} else {
|
||||||
|
self.renderer.enable_depth();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.renderer.begin_scene();
|
||||||
|
|
||||||
|
// Issue render commands!
|
||||||
|
for command in self.render_command_stream.as_mut().unwrap() {
|
||||||
|
self.renderer.render_command(&command);
|
||||||
|
|
||||||
|
if let RenderCommand::Finish { build_time } = command {
|
||||||
|
self.build_time = Some(build_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_frame
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.scene_stats
|
||||||
|
.push(self.renderer.stats);
|
||||||
|
self.renderer.end_scene();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maybe_take_screenshot(&mut self) {
|
||||||
|
let screenshot_path = match self.pending_screenshot_path.take() {
|
||||||
|
None => return,
|
||||||
|
Some(screenshot_path) => screenshot_path,
|
||||||
|
};
|
||||||
|
|
||||||
|
let drawable_size = self.window_size.device_size();
|
||||||
|
let pixels = self
|
||||||
|
.renderer
|
||||||
|
.device
|
||||||
|
.read_pixels_from_default_framebuffer(drawable_size);
|
||||||
|
image::save_buffer(
|
||||||
|
screenshot_path,
|
||||||
|
&pixels,
|
||||||
|
drawable_size.x() as u32,
|
||||||
|
drawable_size.y() as u32,
|
||||||
|
ColorType::RGBA(8),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_debug_ui(&mut self) {
|
||||||
|
if self.options.ui == UIVisibility::None {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let viewport = self.window.viewport(View::Mono);
|
||||||
|
self.window.make_current(View::Mono);
|
||||||
|
self.renderer.replace_dest_framebuffer(DestFramebuffer::Default {
|
||||||
|
viewport,
|
||||||
|
window_size: self.window_size.device_size(),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.renderer.draw_debug_ui();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue