-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add modeling-workspace with dragable triangle demo
This workspace is for now mainly for testing purposes while developing the viewport mechansim, but will later be expanded for 3D modeling.
- Loading branch information
1 parent
e815b34
commit a90437c
Showing
11 changed files
with
429 additions
and
6 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "modeling-workspace" | ||
version = "0.1.0" | ||
edition = "2021" | ||
license = "AGPL-3.0-only" | ||
publish = false | ||
|
||
[dependencies] | ||
workspace = { path = "../workspace" } | ||
viewport = { path = "../viewport" } | ||
computegraph = { path = "../computegraph" } | ||
project = { path = "../project" } | ||
iced = { version = "0.12.1", features = ["advanced"] } | ||
bytemuck = "1.17.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#![warn(clippy::nursery)] | ||
#![warn(clippy::pedantic)] | ||
#![allow(clippy::module_name_repetitions)] | ||
#![allow(clippy::cognitive_complexity)] | ||
|
||
mod viewport; | ||
|
||
use ::viewport::DynamicViewportPlugin; | ||
|
||
#[derive(Debug, Default)] | ||
pub struct ModelingWorkspace {} | ||
|
||
impl workspace::Workspace for ModelingWorkspace { | ||
fn tools(&self) -> Vec<workspace::Toolgroup> { | ||
use workspace::{Action, Tool, Toolgroup}; | ||
vec![Toolgroup { | ||
name: "Some Group".to_string(), | ||
tools: vec![Tool { | ||
name: "Some Tool".to_string(), | ||
action: Action(), | ||
}], | ||
}] | ||
} | ||
|
||
fn viewport_plugins(&self) -> Vec<DynamicViewportPlugin> { | ||
vec![ | ||
DynamicViewportPlugin::new(viewport::ModelingViewportPlugin::default().into()).unwrap(), | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use computegraph::{node, ComputeGraph}; | ||
use viewport::{RenderNodePorts, SceneGraphBuilder, UpdateNodePorts}; | ||
|
||
mod rendering; | ||
mod scene_nodes; | ||
mod state; | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct ModelingViewportPluginOutput {} | ||
|
||
#[derive(Clone, Default, Debug)] | ||
pub struct ModelingViewportPlugin {} | ||
|
||
#[node(ModelingViewportPlugin -> (scene, output))] | ||
fn run( | ||
&self, | ||
_project: &project::ProjectSession, | ||
) -> (viewport::SceneGraph, ModelingViewportPluginOutput) { | ||
let mut graph = ComputeGraph::new(); | ||
let render_node = graph | ||
.add_node(scene_nodes::RenderNode {}, "render".to_string()) | ||
.unwrap(); | ||
let update_node = graph | ||
.add_node(scene_nodes::UpdateStateNode {}, "update".to_string()) | ||
.unwrap(); | ||
let init_node = graph | ||
.add_node(scene_nodes::InitStateNode {}, "init".to_string()) | ||
.unwrap(); | ||
|
||
( | ||
SceneGraphBuilder { | ||
graph, | ||
initial_state: init_node.output(), | ||
render_node: RenderNodePorts { | ||
state_in: render_node.input_state(), | ||
primitive_out: render_node.output(), | ||
}, | ||
update_node: UpdateNodePorts { | ||
event_in: update_node.input_event(), | ||
state_in: update_node.input_state(), | ||
state_out: update_node.output(), | ||
}, | ||
} | ||
.into(), | ||
ModelingViewportPluginOutput {}, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
#![allow(clippy::cast_precision_loss)] | ||
|
||
use iced::widget::shader::{self, wgpu}; | ||
|
||
use super::state::{Uniforms, ViewportState}; | ||
|
||
#[derive(Debug)] | ||
pub struct RenderPrimitive { | ||
pub(crate) state: ViewportState, | ||
} | ||
|
||
impl shader::Primitive for RenderPrimitive { | ||
fn prepare( | ||
&self, | ||
format: wgpu::TextureFormat, | ||
device: &wgpu::Device, | ||
queue: &wgpu::Queue, | ||
bounds: iced::Rectangle, | ||
target_size: iced::Size<u32>, | ||
scale_factor: f32, | ||
storage: &mut shader::Storage, | ||
) { | ||
if !storage.has::<RenderPipeline>() { | ||
storage.store(RenderPipeline::new(device, queue, format, target_size)); | ||
} | ||
let pipeline = storage.get_mut::<RenderPipeline>().unwrap(); | ||
pipeline.update(device, queue, bounds, target_size, scale_factor, self); | ||
} | ||
|
||
fn render( | ||
&self, | ||
storage: &shader::Storage, | ||
target: &wgpu::TextureView, | ||
_target_size: iced::Size<u32>, | ||
viewport: iced::Rectangle<u32>, | ||
encoder: &mut wgpu::CommandEncoder, | ||
) { | ||
let pipeline = storage.get::<RenderPipeline>().unwrap(); | ||
|
||
pipeline.render(encoder, target, viewport); | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
struct RenderPipeline { | ||
pipeline: wgpu::RenderPipeline, | ||
camera_bind_group: wgpu::BindGroup, | ||
uniforms: wgpu::Buffer, | ||
} | ||
|
||
impl RenderPipeline { | ||
fn new( | ||
device: &wgpu::Device, | ||
_queue: &wgpu::Queue, | ||
format: wgpu::TextureFormat, | ||
_target_size: iced::Size<u32>, | ||
) -> Self { | ||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { | ||
label: None, | ||
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!( | ||
"shader.wgsl" | ||
))), | ||
}); | ||
|
||
let camera_bind_group_layout = | ||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { | ||
label: Some("camera_bind_group_layout"), | ||
entries: &[wgpu::BindGroupLayoutEntry { | ||
binding: 0, | ||
visibility: wgpu::ShaderStages::VERTEX, | ||
ty: wgpu::BindingType::Buffer { | ||
ty: wgpu::BufferBindingType::Uniform, | ||
has_dynamic_offset: false, | ||
min_binding_size: None, | ||
}, | ||
count: None, | ||
}], | ||
}); | ||
let uniforms = device.create_buffer(&wgpu::BufferDescriptor { | ||
label: None, | ||
size: std::mem::size_of::<Uniforms>() as u64, | ||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, | ||
mapped_at_creation: false, | ||
}); | ||
|
||
let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { | ||
label: None, | ||
layout: &camera_bind_group_layout, | ||
entries: &[wgpu::BindGroupEntry { | ||
binding: 0, | ||
resource: uniforms.as_entire_binding(), | ||
}], | ||
}); | ||
|
||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { | ||
label: None, | ||
bind_group_layouts: &[&camera_bind_group_layout], | ||
push_constant_ranges: &[], | ||
}); | ||
|
||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { | ||
label: None, | ||
layout: Some(&pipeline_layout), | ||
vertex: wgpu::VertexState { | ||
module: &shader, | ||
entry_point: "vs_main", | ||
buffers: &[], | ||
}, | ||
fragment: Some(wgpu::FragmentState { | ||
module: &shader, | ||
entry_point: "fs_main", | ||
targets: &[Some(wgpu::ColorTargetState { | ||
format, | ||
blend: None, | ||
write_mask: wgpu::ColorWrites::ALL, | ||
})], | ||
}), | ||
primitive: wgpu::PrimitiveState::default(), | ||
depth_stencil: None, | ||
multisample: wgpu::MultisampleState::default(), | ||
multiview: None, | ||
}); | ||
|
||
Self { | ||
pipeline, | ||
camera_bind_group, | ||
uniforms, | ||
} | ||
} | ||
|
||
fn update( | ||
&self, | ||
_device: &wgpu::Device, | ||
queue: &wgpu::Queue, | ||
bounds: iced::Rectangle, | ||
_target_size: iced::Size<u32>, | ||
_scale_factor: f32, | ||
primitive: &RenderPrimitive, | ||
) { | ||
let p = primitive.state.camera_offset; | ||
let x = ((p.x - bounds.x) / bounds.width).mul_add(2.0, -1.0); | ||
let y = ((p.y - bounds.y) / bounds.height).mul_add(-2.0, 1.0); | ||
let uniforms = Uniforms { x, y }; | ||
queue.write_buffer(&self.uniforms, 0, bytemuck::cast_slice(&[uniforms])); | ||
} | ||
|
||
fn render( | ||
&self, | ||
encoder: &mut wgpu::CommandEncoder, | ||
target: &wgpu::TextureView, | ||
viewport: iced::Rectangle<u32>, | ||
) { | ||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { | ||
label: None, | ||
color_attachments: &[Some(wgpu::RenderPassColorAttachment { | ||
view: target, | ||
resolve_target: None, | ||
ops: wgpu::Operations { | ||
load: wgpu::LoadOp::Load, | ||
store: wgpu::StoreOp::Store, | ||
}, | ||
})], | ||
depth_stencil_attachment: None, | ||
timestamp_writes: None, | ||
occlusion_query_set: None, | ||
}); | ||
|
||
render_pass.set_pipeline(&self.pipeline); | ||
render_pass.set_viewport( | ||
viewport.x as f32, | ||
viewport.y as f32, | ||
viewport.width as f32, | ||
viewport.height as f32, | ||
0.0, | ||
1.0, | ||
); | ||
render_pass.set_bind_group(0, &self.camera_bind_group, &[]); | ||
render_pass.draw(0..3, 0..1); | ||
} | ||
} |
Oops, something went wrong.