Fix requiring viewport to be visible to render preview image

This commit is contained in:
Connor Slade
2025-02-15 18:26:57 -05:00
parent f5862d1efc
commit de034afefa
7 changed files with 86 additions and 57 deletions

View File

@@ -91,6 +91,7 @@
- [x] Cleanup self intersection resolution
- [ ] Dont fail to load an stl without normals
- [ ] 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
- [ ] Save panel layout
- [ ] Random triangle color render mode

View File

@@ -13,6 +13,7 @@ use egui::{Vec2, Visuals};
use egui_dock::{DockState, NodeIndex};
use egui_phosphor::regular::CARET_RIGHT;
use egui_tracing::EventCollector;
use egui_wgpu::RenderState;
use nalgebra::Vector2;
use parking_lot::RwLock;
use tracing::{info, warn};
@@ -23,7 +24,7 @@ use crate::{
elephant_foot_fixer::{self},
PluginManager,
},
render::{camera::Camera, rendered_mesh::RenderedMesh},
render::{camera::Camera, preview, rendered_mesh::RenderedMesh},
ui::{
drag_and_drop,
popup::{Popup, PopupIcon, PopupManager},
@@ -43,6 +44,7 @@ use remote_print::RemotePrint;
use slice_operation::{SliceOperation, SliceResult};
pub struct App {
pub render_state: RenderState,
// todo: dock state in ui_state?
pub dock_state: DockState<Tab>,
pub fps: FpsTracker,
@@ -66,7 +68,12 @@ pub struct FpsTracker {
}
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 surface = dock_state.main_surface_mut();
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]);
Self {
render_state,
dock_state,
popup: PopupManager::new(),
state: UiState {
@@ -218,8 +226,8 @@ impl eframe::App for App {
// todo: probably dont do this
let app = unsafe { &mut *(self as *mut _) };
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 {
Theme::Dark => ctx.set_visuals(Visuals::dark()),
Theme::Light => ctx.set_visuals(Visuals::light()),
@@ -230,6 +238,7 @@ impl eframe::App for App {
}
self.remote_print.tick(app);
preview::process_previews(app);
drag_and_drop::update(self, ctx);
windows::ui(self, ctx);
}

View File

@@ -68,13 +68,13 @@ fn main() -> Result<()> {
..Default::default()
},
Box::new(|cc| {
render::init_wgpu(cc);
let render_state = render::init_wgpu(cc);
let mut fonts = FontDefinitions::default();
egui_phosphor::add_to_fonts(&mut fonts, egui_phosphor::Variant::Regular);
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();

View File

@@ -2,6 +2,7 @@ use std::mem;
use dispatch::solid_line::SolidLineDispatch;
use eframe::CreationContext;
use egui_wgpu::RenderState;
use nalgebra::Vector4;
use pipelines::{
model::ModelPipeline, slice_preview::SlicePreviewPipeline, target_point::TargetPointPipeline,
@@ -34,7 +35,7 @@ pub struct ModelVertex {
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 device = &render_state.device;
@@ -47,6 +48,8 @@ pub fn init_wgpu(cc: &CreationContext) {
resources.insert(SlicePreviewRenderResources {
slice_preview_pipeline: SlicePreviewPipeline::new(device),
});
render_state.clone()
}
impl ModelVertex {

View File

@@ -1,7 +1,7 @@
use std::f32::consts::PI;
use image::{Rgba, RgbaImage};
use nalgebra::{Vector2, Vector3};
use nalgebra::{Matrix4, Vector2, Vector3};
use tracing::info;
use wgpu::{
BufferAddress, BufferDescriptor, BufferUsages, Color, CommandEncoderDescriptor, Device,
@@ -11,20 +11,33 @@ use wgpu::{
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
pub fn render_preview_image(
device: &Device,
queue: &Queue,
size: (u32, u32),
model_pipeline: &mut ModelPipeline,
workspace: &WorkspaceRenderCallback,
) -> RgbaImage {
fn render_preview_image(app: &App, size: (u32, u32)) -> RgbaImage {
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_view = 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 distance = (min - max).magnitude() / 2.0;
let mut old_workspace = workspace.clone();
old_workspace.camera = Camera {
workspace.camera = Camera {
target,
distance,
angle: Vector2::new(0.0, PI / 10.0),
..old_workspace.camera
..workspace.camera
};
let workspace = WorkspaceRenderCallback {
transform: old_workspace
.camera
.view_projection_matrix(size.0 as f32 / size.1 as f32),
..old_workspace
};
model_pipeline.prepare(device, &workspace);
let aspect = size.0 as f32 / size.1 as f32;
workspace.transform = workspace.camera.view_projection_matrix(aspect);
resources.model_pipeline.prepare(device, &workspace);
render_preview(
device,
queue,
model_pipeline,
&resources.model_pipeline,
&workspace,
&texture_view,
&resolved_texture_view,

View File

@@ -6,13 +6,12 @@ use nalgebra::{Matrix4, Vector3};
use parking_lot::RwLock;
use wgpu::{CommandBuffer, CommandEncoder, Device, Queue, RenderPass};
use crate::app::{config::Config, slice_operation::SliceOperation};
use crate::app::config::Config;
use super::{
camera::Camera,
dispatch::solid_line::SolidLineDispatch,
pipelines::{model::ModelPipeline, target_point::TargetPointPipeline},
preview::render_preview_image,
rendered_mesh::RenderedMesh,
};
@@ -27,6 +26,7 @@ pub struct WorkspaceRenderResources {
pub struct WorkspaceRenderCallback {
pub camera: Camera,
pub transform: Matrix4<f32>,
pub is_moving: bool,
pub bed_size: Vector3<f32>,
pub grid_size: f32,
@@ -34,8 +34,6 @@ pub struct WorkspaceRenderCallback {
pub models: Arc<RwLock<Vec<RenderedMesh>>>,
pub config: Config,
pub is_moving: bool,
pub slice_operation: Option<SliceOperation>,
pub line_support_debug: Vec<[Vector3<f32>; 2]>,
}
@@ -50,15 +48,6 @@ impl CallbackTrait for WorkspaceRenderCallback {
) -> Vec<CommandBuffer> {
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.model_pipeline.prepare(device, self);
resources.target_point_pipeline.prepare(queue, self);

View File

@@ -2,6 +2,8 @@ use eframe::Theme;
use egui::{CentralPanel, Color32, Context, Frame, Id, Sense, Ui, WidgetText};
use egui_dock::{DockArea, NodeIndex, SurfaceIndex, TabViewer};
use egui_wgpu::Callback;
use nalgebra::Matrix4;
use parking_lot::MappedRwLockWriteGuard;
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);
let aspect = rect.width() / rect.height();
let view_projection = app.camera.view_projection_matrix(aspect);
let callback = Callback::new_paint_callback(
rect,
WorkspaceRenderCallback {
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(),
},
app.get_workspace_render_callback(view_projection, response.dragged()),
);
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()
})
}
}