Fix requiring viewport to be visible to render preview image
This commit is contained in:
3
TODO.md
3
TODO.md
@@ -91,6 +91,7 @@
|
|||||||
- [x] Cleanup self intersection resolution
|
- [x] Cleanup self intersection resolution
|
||||||
- [ ] Dont fail to load an stl without normals
|
- [ ] Dont fail to load an stl without normals
|
||||||
- [ ] GPU accalration for post processing effect?
|
- [ ] GPU accalration for post processing effect?
|
||||||
- [ ] Fix requiring viewport to be visible to render preview image
|
- [x] Fix requiring viewport to be visible to render preview image
|
||||||
- [x] Visulize mesh outside of bounging box
|
- [x] Visulize mesh outside of bounging box
|
||||||
- [ ] Save panel layout
|
- [ ] Save panel layout
|
||||||
|
- [ ] Random triangle color render mode
|
||||||
|
@@ -13,6 +13,7 @@ use egui::{Vec2, Visuals};
|
|||||||
use egui_dock::{DockState, NodeIndex};
|
use egui_dock::{DockState, NodeIndex};
|
||||||
use egui_phosphor::regular::CARET_RIGHT;
|
use egui_phosphor::regular::CARET_RIGHT;
|
||||||
use egui_tracing::EventCollector;
|
use egui_tracing::EventCollector;
|
||||||
|
use egui_wgpu::RenderState;
|
||||||
use nalgebra::Vector2;
|
use nalgebra::Vector2;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
@@ -23,7 +24,7 @@ use crate::{
|
|||||||
elephant_foot_fixer::{self},
|
elephant_foot_fixer::{self},
|
||||||
PluginManager,
|
PluginManager,
|
||||||
},
|
},
|
||||||
render::{camera::Camera, rendered_mesh::RenderedMesh},
|
render::{camera::Camera, preview, rendered_mesh::RenderedMesh},
|
||||||
ui::{
|
ui::{
|
||||||
drag_and_drop,
|
drag_and_drop,
|
||||||
popup::{Popup, PopupIcon, PopupManager},
|
popup::{Popup, PopupIcon, PopupManager},
|
||||||
@@ -43,6 +44,7 @@ use remote_print::RemotePrint;
|
|||||||
use slice_operation::{SliceOperation, SliceResult};
|
use slice_operation::{SliceOperation, SliceResult};
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
|
pub render_state: RenderState,
|
||||||
// todo: dock state in ui_state?
|
// todo: dock state in ui_state?
|
||||||
pub dock_state: DockState<Tab>,
|
pub dock_state: DockState<Tab>,
|
||||||
pub fps: FpsTracker,
|
pub fps: FpsTracker,
|
||||||
@@ -66,7 +68,12 @@ pub struct FpsTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(config_dir: PathBuf, config: Config, event_collector: EventCollector) -> Self {
|
pub fn new(
|
||||||
|
render_state: RenderState,
|
||||||
|
config_dir: PathBuf,
|
||||||
|
config: Config,
|
||||||
|
event_collector: EventCollector,
|
||||||
|
) -> Self {
|
||||||
let mut dock_state = DockState::new(vec![Tab::Viewport]);
|
let mut dock_state = DockState::new(vec![Tab::Viewport]);
|
||||||
let surface = dock_state.main_surface_mut();
|
let surface = dock_state.main_surface_mut();
|
||||||
let [_old_node, new_node] = surface.split_left(NodeIndex::root(), 0.20, vec![Tab::Models]);
|
let [_old_node, new_node] = surface.split_left(NodeIndex::root(), 0.20, vec![Tab::Models]);
|
||||||
@@ -75,6 +82,7 @@ impl App {
|
|||||||
surface.split_below(new_node, 0.5, vec![Tab::Workspace, Tab::RemotePrint]);
|
surface.split_below(new_node, 0.5, vec![Tab::Workspace, Tab::RemotePrint]);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
render_state,
|
||||||
dock_state,
|
dock_state,
|
||||||
popup: PopupManager::new(),
|
popup: PopupManager::new(),
|
||||||
state: UiState {
|
state: UiState {
|
||||||
@@ -218,8 +226,8 @@ impl eframe::App for App {
|
|||||||
// todo: probably dont do this
|
// todo: probably dont do this
|
||||||
let app = unsafe { &mut *(self as *mut _) };
|
let app = unsafe { &mut *(self as *mut _) };
|
||||||
self.popup.render(app, ctx);
|
self.popup.render(app, ctx);
|
||||||
// only update the visuals if the theme has changed
|
|
||||||
|
|
||||||
|
// only update the visuals if the theme has changed
|
||||||
match self.config.theme {
|
match self.config.theme {
|
||||||
Theme::Dark => ctx.set_visuals(Visuals::dark()),
|
Theme::Dark => ctx.set_visuals(Visuals::dark()),
|
||||||
Theme::Light => ctx.set_visuals(Visuals::light()),
|
Theme::Light => ctx.set_visuals(Visuals::light()),
|
||||||
@@ -230,6 +238,7 @@ impl eframe::App for App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.remote_print.tick(app);
|
self.remote_print.tick(app);
|
||||||
|
preview::process_previews(app);
|
||||||
drag_and_drop::update(self, ctx);
|
drag_and_drop::update(self, ctx);
|
||||||
windows::ui(self, ctx);
|
windows::ui(self, ctx);
|
||||||
}
|
}
|
||||||
|
@@ -68,13 +68,13 @@ fn main() -> Result<()> {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Box::new(|cc| {
|
Box::new(|cc| {
|
||||||
render::init_wgpu(cc);
|
let render_state = render::init_wgpu(cc);
|
||||||
|
|
||||||
let mut fonts = FontDefinitions::default();
|
let mut fonts = FontDefinitions::default();
|
||||||
egui_phosphor::add_to_fonts(&mut fonts, egui_phosphor::Variant::Regular);
|
egui_phosphor::add_to_fonts(&mut fonts, egui_phosphor::Variant::Regular);
|
||||||
cc.egui_ctx.set_fonts(fonts);
|
cc.egui_ctx.set_fonts(fonts);
|
||||||
|
|
||||||
Box::new(App::new(config_dir, config, collector))
|
Box::new(App::new(render_state, config_dir, config, collector))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@@ -2,6 +2,7 @@ use std::mem;
|
|||||||
|
|
||||||
use dispatch::solid_line::SolidLineDispatch;
|
use dispatch::solid_line::SolidLineDispatch;
|
||||||
use eframe::CreationContext;
|
use eframe::CreationContext;
|
||||||
|
use egui_wgpu::RenderState;
|
||||||
use nalgebra::Vector4;
|
use nalgebra::Vector4;
|
||||||
use pipelines::{
|
use pipelines::{
|
||||||
model::ModelPipeline, slice_preview::SlicePreviewPipeline, target_point::TargetPointPipeline,
|
model::ModelPipeline, slice_preview::SlicePreviewPipeline, target_point::TargetPointPipeline,
|
||||||
@@ -34,7 +35,7 @@ pub struct ModelVertex {
|
|||||||
pub position: [f32; 4],
|
pub position: [f32; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_wgpu(cc: &CreationContext) {
|
pub fn init_wgpu(cc: &CreationContext) -> RenderState {
|
||||||
let render_state = cc.wgpu_render_state.as_ref().unwrap();
|
let render_state = cc.wgpu_render_state.as_ref().unwrap();
|
||||||
let device = &render_state.device;
|
let device = &render_state.device;
|
||||||
|
|
||||||
@@ -47,6 +48,8 @@ pub fn init_wgpu(cc: &CreationContext) {
|
|||||||
resources.insert(SlicePreviewRenderResources {
|
resources.insert(SlicePreviewRenderResources {
|
||||||
slice_preview_pipeline: SlicePreviewPipeline::new(device),
|
slice_preview_pipeline: SlicePreviewPipeline::new(device),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
render_state.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModelVertex {
|
impl ModelVertex {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
use image::{Rgba, RgbaImage};
|
use image::{Rgba, RgbaImage};
|
||||||
use nalgebra::{Vector2, Vector3};
|
use nalgebra::{Matrix4, Vector2, Vector3};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
BufferAddress, BufferDescriptor, BufferUsages, Color, CommandEncoderDescriptor, Device,
|
BufferAddress, BufferDescriptor, BufferUsages, Color, CommandEncoderDescriptor, Device,
|
||||||
@@ -11,20 +11,33 @@ use wgpu::{
|
|||||||
TextureFormat, TextureUsages, TextureView, TextureViewDescriptor,
|
TextureFormat, TextureUsages, TextureView, TextureViewDescriptor,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::TEXTURE_FORMAT;
|
use crate::{app::App, TEXTURE_FORMAT};
|
||||||
|
|
||||||
use super::{camera::Camera, pipelines::model::ModelPipeline, workspace::WorkspaceRenderCallback};
|
use super::{
|
||||||
|
camera::Camera,
|
||||||
|
pipelines::model::ModelPipeline,
|
||||||
|
workspace::{WorkspaceRenderCallback, WorkspaceRenderResources},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn process_previews(app: &App) {
|
||||||
|
match &app.slice_operation {
|
||||||
|
Some(slice_operation) if slice_operation.needs_preview_image() => {
|
||||||
|
let image = render_preview_image(app, (512, 512));
|
||||||
|
slice_operation.add_preview_image(image);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Allow rendering multiple preview images at once
|
// TODO: Allow rendering multiple preview images at once
|
||||||
pub fn render_preview_image(
|
fn render_preview_image(app: &App, size: (u32, u32)) -> RgbaImage {
|
||||||
device: &Device,
|
|
||||||
queue: &Queue,
|
|
||||||
size: (u32, u32),
|
|
||||||
model_pipeline: &mut ModelPipeline,
|
|
||||||
workspace: &WorkspaceRenderCallback,
|
|
||||||
) -> RgbaImage {
|
|
||||||
info!("Generating {}x{} preview image", size.0, size.1);
|
info!("Generating {}x{} preview image", size.0, size.1);
|
||||||
|
|
||||||
|
let mut resources = app.get_callback_resource_mut::<WorkspaceRenderResources>();
|
||||||
|
let (device, queue) = (&app.render_state.device, &app.render_state.queue);
|
||||||
|
|
||||||
|
let mut workspace = app.get_workspace_render_callback(Matrix4::zeros(), false);
|
||||||
|
|
||||||
let (texture, resolved_texture, depth_texture) = init_textures(device, size);
|
let (texture, resolved_texture, depth_texture) = init_textures(device, size);
|
||||||
let texture_view = texture.create_view(&TextureViewDescriptor::default());
|
let texture_view = texture.create_view(&TextureViewDescriptor::default());
|
||||||
let resolved_texture_view = resolved_texture.create_view(&TextureViewDescriptor::default());
|
let resolved_texture_view = resolved_texture.create_view(&TextureViewDescriptor::default());
|
||||||
@@ -40,26 +53,22 @@ pub fn render_preview_image(
|
|||||||
let target = (min + max) / 2.0;
|
let target = (min + max) / 2.0;
|
||||||
let distance = (min - max).magnitude() / 2.0;
|
let distance = (min - max).magnitude() / 2.0;
|
||||||
|
|
||||||
let mut old_workspace = workspace.clone();
|
workspace.camera = Camera {
|
||||||
old_workspace.camera = Camera {
|
|
||||||
target,
|
target,
|
||||||
distance,
|
distance,
|
||||||
angle: Vector2::new(0.0, PI / 10.0),
|
angle: Vector2::new(0.0, PI / 10.0),
|
||||||
..old_workspace.camera
|
..workspace.camera
|
||||||
};
|
};
|
||||||
|
|
||||||
let workspace = WorkspaceRenderCallback {
|
let aspect = size.0 as f32 / size.1 as f32;
|
||||||
transform: old_workspace
|
workspace.transform = workspace.camera.view_projection_matrix(aspect);
|
||||||
.camera
|
|
||||||
.view_projection_matrix(size.0 as f32 / size.1 as f32),
|
resources.model_pipeline.prepare(device, &workspace);
|
||||||
..old_workspace
|
|
||||||
};
|
|
||||||
model_pipeline.prepare(device, &workspace);
|
|
||||||
|
|
||||||
render_preview(
|
render_preview(
|
||||||
device,
|
device,
|
||||||
queue,
|
queue,
|
||||||
model_pipeline,
|
&resources.model_pipeline,
|
||||||
&workspace,
|
&workspace,
|
||||||
&texture_view,
|
&texture_view,
|
||||||
&resolved_texture_view,
|
&resolved_texture_view,
|
||||||
|
@@ -6,13 +6,12 @@ use nalgebra::{Matrix4, Vector3};
|
|||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use wgpu::{CommandBuffer, CommandEncoder, Device, Queue, RenderPass};
|
use wgpu::{CommandBuffer, CommandEncoder, Device, Queue, RenderPass};
|
||||||
|
|
||||||
use crate::app::{config::Config, slice_operation::SliceOperation};
|
use crate::app::config::Config;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
camera::Camera,
|
camera::Camera,
|
||||||
dispatch::solid_line::SolidLineDispatch,
|
dispatch::solid_line::SolidLineDispatch,
|
||||||
pipelines::{model::ModelPipeline, target_point::TargetPointPipeline},
|
pipelines::{model::ModelPipeline, target_point::TargetPointPipeline},
|
||||||
preview::render_preview_image,
|
|
||||||
rendered_mesh::RenderedMesh,
|
rendered_mesh::RenderedMesh,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,6 +26,7 @@ pub struct WorkspaceRenderResources {
|
|||||||
pub struct WorkspaceRenderCallback {
|
pub struct WorkspaceRenderCallback {
|
||||||
pub camera: Camera,
|
pub camera: Camera,
|
||||||
pub transform: Matrix4<f32>,
|
pub transform: Matrix4<f32>,
|
||||||
|
pub is_moving: bool,
|
||||||
|
|
||||||
pub bed_size: Vector3<f32>,
|
pub bed_size: Vector3<f32>,
|
||||||
pub grid_size: f32,
|
pub grid_size: f32,
|
||||||
@@ -34,8 +34,6 @@ pub struct WorkspaceRenderCallback {
|
|||||||
pub models: Arc<RwLock<Vec<RenderedMesh>>>,
|
pub models: Arc<RwLock<Vec<RenderedMesh>>>,
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
|
|
||||||
pub is_moving: bool,
|
|
||||||
pub slice_operation: Option<SliceOperation>,
|
|
||||||
pub line_support_debug: Vec<[Vector3<f32>; 2]>,
|
pub line_support_debug: Vec<[Vector3<f32>; 2]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,15 +48,6 @@ impl CallbackTrait for WorkspaceRenderCallback {
|
|||||||
) -> Vec<CommandBuffer> {
|
) -> Vec<CommandBuffer> {
|
||||||
let resources = resources.get_mut::<WorkspaceRenderResources>().unwrap();
|
let resources = resources.get_mut::<WorkspaceRenderResources>().unwrap();
|
||||||
|
|
||||||
match &self.slice_operation {
|
|
||||||
Some(slice_operation) if slice_operation.needs_preview_image() => {
|
|
||||||
let pipeline = &mut resources.model_pipeline;
|
|
||||||
let image = render_preview_image(device, queue, (512, 512), pipeline, self);
|
|
||||||
slice_operation.add_preview_image(image);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
resources.solid_line.prepare(device, queue, self);
|
resources.solid_line.prepare(device, queue, self);
|
||||||
resources.model_pipeline.prepare(device, self);
|
resources.model_pipeline.prepare(device, self);
|
||||||
resources.target_point_pipeline.prepare(queue, self);
|
resources.target_point_pipeline.prepare(queue, self);
|
||||||
|
@@ -2,6 +2,8 @@ use eframe::Theme;
|
|||||||
use egui::{CentralPanel, Color32, Context, Frame, Id, Sense, Ui, WidgetText};
|
use egui::{CentralPanel, Color32, Context, Frame, Id, Sense, Ui, WidgetText};
|
||||||
use egui_dock::{DockArea, NodeIndex, SurfaceIndex, TabViewer};
|
use egui_dock::{DockArea, NodeIndex, SurfaceIndex, TabViewer};
|
||||||
use egui_wgpu::Callback;
|
use egui_wgpu::Callback;
|
||||||
|
use nalgebra::Matrix4;
|
||||||
|
use parking_lot::MappedRwLockWriteGuard;
|
||||||
|
|
||||||
use crate::{app::App, render::workspace::WorkspaceRenderCallback};
|
use crate::{app::App, render::workspace::WorkspaceRenderCallback};
|
||||||
|
|
||||||
@@ -135,24 +137,40 @@ fn viewport(app: &mut App, ui: &mut Ui, _ctx: &Context) {
|
|||||||
};
|
};
|
||||||
ui.painter().rect_filled(rect, 0.0, color);
|
ui.painter().rect_filled(rect, 0.0, color);
|
||||||
|
|
||||||
|
let aspect = rect.width() / rect.height();
|
||||||
|
let view_projection = app.camera.view_projection_matrix(aspect);
|
||||||
|
|
||||||
let callback = Callback::new_paint_callback(
|
let callback = Callback::new_paint_callback(
|
||||||
rect,
|
rect,
|
||||||
WorkspaceRenderCallback {
|
app.get_workspace_render_callback(view_projection, response.dragged()),
|
||||||
camera: app.camera.clone(),
|
|
||||||
transform: app
|
|
||||||
.camera
|
|
||||||
.view_projection_matrix(rect.width() / rect.height()),
|
|
||||||
|
|
||||||
bed_size: app.slice_config.platform_size,
|
|
||||||
grid_size: app.config.grid_size,
|
|
||||||
|
|
||||||
is_moving: response.dragged(),
|
|
||||||
slice_operation: app.slice_operation.clone(),
|
|
||||||
|
|
||||||
models: app.meshes.clone(),
|
|
||||||
config: app.config.clone(),
|
|
||||||
line_support_debug: app.state.line_support_debug.clone(),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ui.painter().add(callback);
|
ui.painter().add(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
pub fn get_workspace_render_callback(
|
||||||
|
&self,
|
||||||
|
view_projection: Matrix4<f32>,
|
||||||
|
is_moving: bool,
|
||||||
|
) -> WorkspaceRenderCallback {
|
||||||
|
WorkspaceRenderCallback {
|
||||||
|
camera: self.camera.clone(),
|
||||||
|
transform: view_projection,
|
||||||
|
|
||||||
|
bed_size: self.slice_config.platform_size,
|
||||||
|
grid_size: self.config.grid_size,
|
||||||
|
|
||||||
|
is_moving,
|
||||||
|
models: self.meshes.clone(),
|
||||||
|
config: self.config.clone(),
|
||||||
|
line_support_debug: self.state.line_support_debug.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_callback_resource_mut<T: 'static>(&self) -> MappedRwLockWriteGuard<T> {
|
||||||
|
MappedRwLockWriteGuard::map(self.render_state.renderer.write(), |x| {
|
||||||
|
x.callback_resources.get_mut::<T>().unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user