gizmo
This commit is contained in:
178
src/debug/gizmo.rs
Normal file
178
src/debug/gizmo.rs
Normal file
@@ -0,0 +1,178 @@
|
||||
use bytemuck::cast_slice;
|
||||
use glam::{Mat4, Vec3};
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
use crate::entity::EntityHandle;
|
||||
use crate::loaders::mesh::{InstanceRaw, Mesh, Vertex};
|
||||
use crate::render::{self, DrawCall, Pipeline};
|
||||
use crate::utility::transform::Transform;
|
||||
use crate::world::Storage;
|
||||
|
||||
const GIZMO_DISTANCE_SCALE: f32 = 0.1;
|
||||
const ARROW_BASE: f32 = 0.85;
|
||||
const ARROW_SPREAD: f32 = 0.08;
|
||||
|
||||
pub fn create_gizmo_mesh(device: &wgpu::Device) -> Mesh
|
||||
{
|
||||
let vertices = vec![
|
||||
Vertex {
|
||||
position: [0.0, 0.0, 0.0],
|
||||
normal: [1.0, 0.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [1.0, 0.0, 0.0],
|
||||
normal: [1.0, 0.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.0, 0.0],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 1.0, 0.0],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.0, 0.0],
|
||||
normal: [0.0, 0.0, 1.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, 0.0, 1.0],
|
||||
normal: [0.0, 0.0, 1.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [ARROW_BASE, ARROW_SPREAD, 0.0],
|
||||
normal: [1.0, 0.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [ARROW_BASE, -ARROW_SPREAD, 0.0],
|
||||
normal: [1.0, 0.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [ARROW_BASE, 0.0, ARROW_SPREAD],
|
||||
normal: [1.0, 0.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [ARROW_BASE, 0.0, -ARROW_SPREAD],
|
||||
normal: [1.0, 0.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [ARROW_SPREAD, ARROW_BASE, 0.0],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-ARROW_SPREAD, ARROW_BASE, 0.0],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, ARROW_BASE, ARROW_SPREAD],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, ARROW_BASE, -ARROW_SPREAD],
|
||||
normal: [0.0, 1.0, 0.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [ARROW_SPREAD, 0.0, ARROW_BASE],
|
||||
normal: [0.0, 0.0, 1.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-ARROW_SPREAD, 0.0, ARROW_BASE],
|
||||
normal: [0.0, 0.0, 1.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, ARROW_SPREAD, ARROW_BASE],
|
||||
normal: [0.0, 0.0, 1.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.0, -ARROW_SPREAD, ARROW_BASE],
|
||||
normal: [0.0, 0.0, 1.0],
|
||||
uv: [0.0, 0.0],
|
||||
},
|
||||
];
|
||||
|
||||
let indices = vec![
|
||||
0, 1, 2, 3, 4, 5, 6, 1, 7, 1, 8, 1, 9, 1, 10, 3, 11, 3, 12, 3, 13, 3, 14, 5, 15, 5, 16, 5,
|
||||
17, 5,
|
||||
];
|
||||
|
||||
Mesh::new(device, &vertices, &indices)
|
||||
}
|
||||
|
||||
pub fn create_gizmo_instance_buffer(device: &wgpu::Device) -> wgpu::Buffer
|
||||
{
|
||||
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Gizmo Instance Buffer"),
|
||||
contents: cast_slice(&[InstanceRaw {
|
||||
model: Mat4::IDENTITY.to_cols_array_2d(),
|
||||
dissolve_amount: 0.0,
|
||||
_padding: [0.0; 3],
|
||||
}]),
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render_transform_gizmo(
|
||||
entity: EntityHandle,
|
||||
transforms: &Storage<Transform>,
|
||||
camera_position: Vec3,
|
||||
gizmo_mesh: &Mesh,
|
||||
instance_buffer: &wgpu::Buffer,
|
||||
) -> Vec<DrawCall>
|
||||
{
|
||||
let transform = match transforms.get(entity)
|
||||
{
|
||||
Some(t) => t,
|
||||
None => return Vec::new(),
|
||||
};
|
||||
|
||||
let distance = camera_position.distance(transform.position);
|
||||
let scale = (distance * GIZMO_DISTANCE_SCALE).max(0.1);
|
||||
|
||||
let model = Mat4::from_scale_rotation_translation(
|
||||
Vec3::splat(scale),
|
||||
transform.rotation,
|
||||
transform.position,
|
||||
);
|
||||
|
||||
let instance_data = InstanceRaw {
|
||||
model: model.to_cols_array_2d(),
|
||||
dissolve_amount: 0.0,
|
||||
_padding: [0.0; 3],
|
||||
};
|
||||
|
||||
render::with_queue(|queue| {
|
||||
queue.write_buffer(instance_buffer, 0, cast_slice(&[instance_data]));
|
||||
});
|
||||
|
||||
vec![DrawCall {
|
||||
vertex_buffer: gizmo_mesh.vertex_buffer.clone(),
|
||||
index_buffer: gizmo_mesh.index_buffer.clone(),
|
||||
num_indices: gizmo_mesh.num_indices,
|
||||
model,
|
||||
pipeline: Pipeline::GizmoLines,
|
||||
instance_buffer: Some(instance_buffer.clone()),
|
||||
num_instances: 1,
|
||||
tile_scale: 4.0,
|
||||
enable_dissolve: false,
|
||||
enable_snow_light: false,
|
||||
displacement_bind_group: None,
|
||||
entity: None,
|
||||
}]
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod collider_debug;
|
||||
pub mod gizmo;
|
||||
pub mod mode;
|
||||
|
||||
pub use mode::DebugMode;
|
||||
|
||||
30
src/main.rs
30
src/main.rs
@@ -22,7 +22,7 @@ use crate::bundles::terrain::{TerrainBundle, TerrainConfig};
|
||||
use crate::bundles::test_char::TestCharBundle;
|
||||
use crate::bundles::Bundle;
|
||||
use crate::components::intent::{FollowPlayerIntent, StopFollowingIntent};
|
||||
use crate::debug::{collider_debug, DebugMode};
|
||||
use crate::debug::{collider_debug, gizmo, DebugMode};
|
||||
use crate::editor::{editor_loop, EditorState, FrameStats};
|
||||
use crate::entity::EntityHandle;
|
||||
use crate::loaders::scene::Space;
|
||||
@@ -281,6 +281,15 @@ fn toggle_editor(game: &mut Game)
|
||||
.set_relative_mouse_mode(&game.window, false);
|
||||
game.editor.right_mouse_held = false;
|
||||
game.input_state.mouse_captured = false;
|
||||
if game.world.gizmo_mesh.is_none()
|
||||
{
|
||||
game.world.gizmo_mesh = Some(render::with_device(|device| {
|
||||
gizmo::create_gizmo_mesh(device)
|
||||
}));
|
||||
game.world.gizmo_instance_buffer = Some(render::with_device(|device| {
|
||||
gizmo::create_gizmo_instance_buffer(device)
|
||||
}));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -477,6 +486,25 @@ fn main() -> Result<(), Box<dyn std::error::Error>>
|
||||
draw_calls.extend(collider_debug::render_collider_debug());
|
||||
}
|
||||
|
||||
if game.editor.active
|
||||
{
|
||||
if let Some(entity) = game.editor.selected_entity
|
||||
{
|
||||
let cam_pos = game.world.active_camera_position();
|
||||
if let (Some(ref mesh), Some(ref buf)) =
|
||||
(&game.world.gizmo_mesh, &game.world.gizmo_instance_buffer)
|
||||
{
|
||||
draw_calls.extend(gizmo::render_transform_gizmo(
|
||||
entity,
|
||||
&game.world.transforms,
|
||||
cam_pos,
|
||||
mesh,
|
||||
buf,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
game.stats.draw_call_count = draw_calls.len();
|
||||
game.stats.fps = 1.0 / delta;
|
||||
game.stats.frame_ms = delta * 1000.0;
|
||||
|
||||
@@ -32,8 +32,8 @@ use crate::paths;
|
||||
use crate::postprocess::{create_blit_pipeline, create_fullscreen_quad, LowResFramebuffer};
|
||||
use crate::texture::{DitherTextures, FlowmapTexture};
|
||||
use pipeline::{
|
||||
create_debug_lines_pipeline, create_main_pipeline, create_snow_clipmap_pipeline,
|
||||
create_wireframe_pipeline,
|
||||
create_debug_lines_pipeline, create_gizmo_lines_pipeline, create_main_pipeline,
|
||||
create_snow_clipmap_pipeline, create_wireframe_pipeline,
|
||||
};
|
||||
use std::num::NonZeroU64;
|
||||
|
||||
@@ -53,6 +53,7 @@ pub struct Renderer
|
||||
snow_clipmap_pipeline: wgpu::RenderPipeline,
|
||||
wireframe_pipeline: Option<wgpu::RenderPipeline>,
|
||||
debug_lines_pipeline: Option<wgpu::RenderPipeline>,
|
||||
gizmo_lines_pipeline: Option<wgpu::RenderPipeline>,
|
||||
debug_overlay: Option<debug_overlay::DebugOverlay>,
|
||||
billboard_pipeline: BillboardPipeline,
|
||||
particle_pipeline: ParticlePipeline,
|
||||
@@ -531,6 +532,12 @@ impl Renderer
|
||||
&bind_group_layout,
|
||||
));
|
||||
|
||||
let gizmo_lines_pipeline = Some(create_gizmo_lines_pipeline(
|
||||
&device,
|
||||
config.format,
|
||||
&bind_group_layout,
|
||||
));
|
||||
|
||||
let billboard_pipeline = BillboardPipeline::new(&device, config.format);
|
||||
let particle_pipeline = ParticlePipeline::new(&device, config.format);
|
||||
let font_atlas = font_atlas::FontAtlas::load(&device, &queue);
|
||||
@@ -564,6 +571,7 @@ impl Renderer
|
||||
snow_clipmap_pipeline,
|
||||
wireframe_pipeline,
|
||||
debug_lines_pipeline,
|
||||
gizmo_lines_pipeline,
|
||||
debug_overlay,
|
||||
billboard_pipeline,
|
||||
particle_pipeline,
|
||||
@@ -740,6 +748,10 @@ impl Renderer
|
||||
.debug_lines_pipeline
|
||||
.as_ref()
|
||||
.unwrap_or(&self.standard_pipeline),
|
||||
Pipeline::GizmoLines => self
|
||||
.gizmo_lines_pipeline
|
||||
.as_ref()
|
||||
.unwrap_or(&self.standard_pipeline),
|
||||
};
|
||||
render_pass.set_pipeline(pipeline);
|
||||
render_pass.set_bind_group(0, &self.bind_group, &[offset as u32]);
|
||||
@@ -770,7 +782,7 @@ impl Renderer
|
||||
{
|
||||
if matches!(
|
||||
draw_call.pipeline,
|
||||
Pipeline::SnowClipmap | Pipeline::DebugLines
|
||||
Pipeline::SnowClipmap | Pipeline::DebugLines | Pipeline::GizmoLines
|
||||
)
|
||||
{
|
||||
continue;
|
||||
@@ -864,7 +876,7 @@ impl Renderer
|
||||
|
||||
if matches!(
|
||||
draw_call.pipeline,
|
||||
Pipeline::SnowClipmap | Pipeline::DebugLines
|
||||
Pipeline::SnowClipmap | Pipeline::DebugLines | Pipeline::GizmoLines
|
||||
)
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -1,6 +1,92 @@
|
||||
use crate::paths;
|
||||
use wesl::Wesl;
|
||||
|
||||
fn create_lines_pipeline(
|
||||
device: &wgpu::Device,
|
||||
format: wgpu::TextureFormat,
|
||||
bind_group_layout: &wgpu::BindGroupLayout,
|
||||
fragment_entry_point: &str,
|
||||
label_prefix: &str,
|
||||
) -> wgpu::RenderPipeline
|
||||
{
|
||||
let compiler = Wesl::new(&paths::SHADERS_DIR);
|
||||
let shader_source = compiler
|
||||
.compile(&paths::shaders::MAIN_PACKAGE.parse().unwrap())
|
||||
.inspect_err(|e| eprintln!("WESL error: {e}"))
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
let shader_label = format!("{label_prefix} Shader");
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some(&shader_label),
|
||||
source: wgpu::ShaderSource::Wgsl(shader_source.into()),
|
||||
});
|
||||
|
||||
let layout_label = format!("{label_prefix} Pipeline Layout");
|
||||
let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some(&layout_label),
|
||||
bind_group_layouts: &[bind_group_layout],
|
||||
immediate_size: 0,
|
||||
});
|
||||
|
||||
let pipeline_label = format!("{label_prefix} Pipeline");
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some(&pipeline_label),
|
||||
layout: Some(&render_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader,
|
||||
entry_point: Some("vs_main"),
|
||||
buffers: &[
|
||||
crate::loaders::mesh::Vertex::desc(),
|
||||
crate::loaders::mesh::InstanceRaw::desc(),
|
||||
],
|
||||
compilation_options: Default::default(),
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
entry_point: Some(fragment_entry_point),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format,
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
compilation_options: Default::default(),
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::LineList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: None,
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
unclipped_depth: false,
|
||||
conservative: false,
|
||||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth32Float,
|
||||
depth_write_enabled: false,
|
||||
depth_compare: wgpu::CompareFunction::Always,
|
||||
stencil: wgpu::StencilState::default(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: 1,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_gizmo_lines_pipeline(
|
||||
device: &wgpu::Device,
|
||||
format: wgpu::TextureFormat,
|
||||
bind_group_layout: &wgpu::BindGroupLayout,
|
||||
) -> wgpu::RenderPipeline
|
||||
{
|
||||
create_lines_pipeline(device, format, bind_group_layout, "fs_gizmo", "Gizmo Lines")
|
||||
}
|
||||
|
||||
pub fn create_shadow_pipeline(
|
||||
device: &wgpu::Device,
|
||||
bind_group_layout: &wgpu::BindGroupLayout,
|
||||
@@ -215,70 +301,7 @@ pub fn create_debug_lines_pipeline(
|
||||
bind_group_layout: &wgpu::BindGroupLayout,
|
||||
) -> wgpu::RenderPipeline
|
||||
{
|
||||
let compiler = Wesl::new(&paths::SHADERS_DIR);
|
||||
let shader_source = compiler
|
||||
.compile(&paths::shaders::MAIN_PACKAGE.parse().unwrap())
|
||||
.inspect_err(|e| eprintln!("WESL error: {e}"))
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some("Debug Lines Shader"),
|
||||
source: wgpu::ShaderSource::Wgsl(shader_source.into()),
|
||||
});
|
||||
|
||||
let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Debug Lines Pipeline Layout"),
|
||||
bind_group_layouts: &[bind_group_layout],
|
||||
immediate_size: 0,
|
||||
});
|
||||
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Debug Lines Pipeline"),
|
||||
layout: Some(&render_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader,
|
||||
entry_point: Some("vs_main"),
|
||||
buffers: &[
|
||||
crate::loaders::mesh::Vertex::desc(),
|
||||
crate::loaders::mesh::InstanceRaw::desc(),
|
||||
],
|
||||
compilation_options: Default::default(),
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
entry_point: Some("fs_main"),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format,
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
compilation_options: Default::default(),
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::LineList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: None,
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
unclipped_depth: false,
|
||||
conservative: false,
|
||||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth32Float,
|
||||
depth_write_enabled: false,
|
||||
depth_compare: wgpu::CompareFunction::Always,
|
||||
stencil: wgpu::StencilState::default(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: 1,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
})
|
||||
create_lines_pipeline(device, format, bind_group_layout, "fs_main", "Debug Lines")
|
||||
}
|
||||
|
||||
pub fn create_snow_clipmap_pipeline(
|
||||
|
||||
@@ -143,6 +143,7 @@ pub enum Pipeline
|
||||
Standard,
|
||||
SnowClipmap,
|
||||
DebugLines,
|
||||
GizmoLines,
|
||||
}
|
||||
|
||||
pub struct DrawCall
|
||||
|
||||
@@ -19,6 +19,7 @@ use crate::components::{
|
||||
};
|
||||
use crate::debug::DebugMode;
|
||||
use crate::entity::{EntityHandle, EntityManager};
|
||||
use crate::loaders::mesh::Mesh;
|
||||
use crate::render::snow::SnowLayer;
|
||||
use crate::states::state::StateMachine;
|
||||
use crate::systems::particle::ParticleBuffers;
|
||||
@@ -125,6 +126,8 @@ pub struct World
|
||||
pub snow_layer: Option<SnowLayer>,
|
||||
pub debug_mode: DebugMode,
|
||||
pub was_dialog_active: bool,
|
||||
pub gizmo_mesh: Option<Mesh>,
|
||||
pub gizmo_instance_buffer: Option<wgpu::Buffer>,
|
||||
}
|
||||
|
||||
impl World
|
||||
@@ -172,6 +175,8 @@ impl World
|
||||
snow_layer: None,
|
||||
debug_mode: DebugMode::default(),
|
||||
was_dialog_active: false,
|
||||
gizmo_mesh: None,
|
||||
gizmo_instance_buffer: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user