Skip to content

Commit ec26422

Browse files
Simplify shapes, complete undo stack for various actions
1 parent d89da05 commit ec26422

4 files changed

Lines changed: 212 additions & 206 deletions

File tree

src/renderer/app_state.rs

Lines changed: 55 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
gpu_state::GpuResourceAllocator,
77
mouse_state::MouseState,
88
shader::{Shader, TextureResource},
9-
shape::{compute_distance, Circle, EditorState, Shape},
9+
shape::{compute_distance, Circle, EditorState},
1010
shape_uniform::{CircleData, ShapeUniform, MAX_CIRCLES},
1111
},
1212
};
@@ -145,6 +145,7 @@ impl<'a> AppState<'a> {
145145
let (start_x, start_y) = self.mouse_state.position();
146146
self.mouse_state.set_start_drag(Some((start_x, start_y)));
147147
draw_uniform.set_circle_center(start_x, start_y);
148+
self.mouse_state.set_selected_shape(None);
148149
}
149150
(true, false) => {
150151
let initial_drag_position = self.mouse_state.start_drag();
@@ -162,7 +163,9 @@ impl<'a> AppState<'a> {
162163
(self.size.width as f32, self.size.height as f32),
163164
);
164165

165-
self.editor_state.push_shape(Shape::Circle(circle));
166+
let element_id = self.editor_state.create_shape(circle);
167+
168+
self.mouse_state.set_selected_shape(Some(element_id));
166169

167170
// Clear state
168171
self.mouse_state.set_start_drag(None);
@@ -177,40 +180,38 @@ impl<'a> AppState<'a> {
177180
// Mouse press - check if we clicked on a circle
178181
let mouse_coordinate = self.mouse_state.position();
179182

180-
if let Some(circle_index) =
181-
self.editor_state.shape_stack.find_shape_at_point(
182-
mouse_coordinate,
183-
self.size.width,
184-
self.size.height,
185-
)
186-
{
187-
// Found a circle - select it and start dragging
188-
self.mouse_state.set_selected_shape(Some(circle_index));
189-
self.mouse_state.set_dragging_shape(true);
190-
191-
// Calculate offset from circle center to mouse position
192-
let Shape::Circle(circle) =
193-
self.editor_state.shape_stack.get_unchecked(circle_index);
194-
195-
let (x, y) = circle.center();
196-
197-
let normalized_mouse_coord = {
198-
let (x_in_pixel_coords, y_in_pixel_coords) =
199-
mouse_coordinate;
200-
201-
(
202-
x_in_pixel_coords / self.size.width as f32,
203-
y_in_pixel_coords / self.size.height as f32,
204-
)
205-
};
206-
207-
let offset_x = normalized_mouse_coord.0 - x;
208-
let offset_y = normalized_mouse_coord.1 - y;
209-
210-
self.mouse_state.set_drag_offset((offset_x, offset_y));
211-
} else {
212-
// Clicked on empty space - deselect any selected circle
213-
self.mouse_state.set_selected_shape(None);
183+
let res = self.editor_state.get_element_by_point(
184+
mouse_coordinate,
185+
(self.size.width as f32, self.size.height as f32),
186+
);
187+
188+
match res {
189+
Some(element) => {
190+
let id = element.id();
191+
let orig_pos = element.inner().center();
192+
193+
self.editor_state.start_shape_translate(id);
194+
195+
// Found a circle - select it and start dragging
196+
self.mouse_state.set_selected_shape(Some(id));
197+
self.mouse_state.set_dragging_shape(true);
198+
199+
let normalized_mouse_coord = {
200+
let (x_in_pixel_coords, y_in_pixel_coords) =
201+
mouse_coordinate;
202+
203+
(
204+
x_in_pixel_coords / self.size.width as f32,
205+
y_in_pixel_coords / self.size.height as f32,
206+
)
207+
};
208+
209+
let offset_x = normalized_mouse_coord.0 - orig_pos.0;
210+
let offset_y = normalized_mouse_coord.1 - orig_pos.1;
211+
212+
self.mouse_state.set_drag_offset((offset_x, offset_y));
213+
}
214+
None => self.mouse_state.set_selected_shape(None),
214215
}
215216
}
216217
(true, false) => {
@@ -234,7 +235,7 @@ impl<'a> AppState<'a> {
234235
} else {
235236
// Selection mode: Handle circle dragging
236237
if self.mouse_state.dragging_shape() {
237-
if let Some(selected_index) = self.mouse_state.selected_shape() {
238+
if let Some(selected_element_id) = self.mouse_state.selected_shape() {
238239
let normalized_x = x / self.size.width as f32;
239240
let normalized_y = y / self.size.height as f32;
240241

@@ -245,8 +246,7 @@ impl<'a> AppState<'a> {
245246

246247
// Move the circle to the new position
247248
self.editor_state
248-
.shape_stack
249-
.move_shape(selected_index, new_x, new_y);
249+
.translate_shape(selected_element_id, (new_x, new_y));
250250
}
251251
}
252252
}
@@ -319,8 +319,8 @@ impl<'a> AppState<'a> {
319319
(KeyCode::Delete, ElementState::Pressed)
320320
| (KeyCode::Backspace, ElementState::Pressed) => {
321321
// Delete the selected circle
322-
if let Some(selected_index) = self.mouse_state.selected_shape() {
323-
self.editor_state.shape_stack.remove_shape(selected_index);
322+
if let Some(selected_element_id) = self.mouse_state.selected_shape() {
323+
self.editor_state.remove_shape_by_id(selected_element_id);
324324
self.mouse_state.set_selected_shape(None);
325325
self.mouse_state.set_dragging_shape(false);
326326
}
@@ -357,29 +357,30 @@ impl<'a> AppState<'a> {
357357
}
358358

359359
fn update_shape_data(&mut self) {
360-
let num_circles = self.editor_state.shape_stack.len().min(MAX_CIRCLES);
360+
let num_circles = self.editor_state.num_elements();
361361

362362
self.shape_uniform.set_num_circles(num_circles as u32);
363-
self.shape_uniform
364-
.set_selected_circle(self.mouse_state.selected_shape());
363+
364+
// Convert element ID to array index for the shader
365+
let selected_index = self
366+
.mouse_state
367+
.selected_shape()
368+
.and_then(|element_id| self.editor_state.get_element_index_by_id(element_id));
369+
370+
self.shape_uniform.set_selected_circle(selected_index);
365371

366372
// Update shape uniform
367373
let shape_uniform_resources = &self.shape_shader.uniform_resources;
368374
self.gpu_allocator
369375
.write_uniform_buffer(&shape_uniform_resources[0].resource, self.shape_uniform);
370376

371377
// Update circle storage buffer
372-
let mut circle_data = vec![CircleData::default(); MAX_CIRCLES];
373-
for (i, (_, shape)) in self
378+
let circle_data = self
374379
.editor_state
375-
.shape_stack
376-
.shapes()
377-
.into_iter()
378-
.take(MAX_CIRCLES)
379-
.enumerate()
380-
{
381-
circle_data[i] = CircleData::from(shape);
382-
}
380+
.elements()
381+
.iter()
382+
.map(|e| CircleData::from(e.inner()))
383+
.collect::<Vec<_>>();
383384

384385
self.gpu_allocator
385386
.write_storage_buffer(&self.circle_storage_buffer, &circle_data);

src/renderer/gpu_state.rs

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -251,33 +251,33 @@ impl<'a> GpuResourceAllocator<'a> {
251251
});
252252

253253
// Create bind group layout for uniform + storage buffer
254-
let bind_group_layout = self
255-
.device
256-
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
257-
entries: &[
258-
wgpu::BindGroupLayoutEntry {
259-
binding: 0,
260-
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
261-
ty: wgpu::BindingType::Buffer {
262-
ty: wgpu::BufferBindingType::Uniform,
263-
has_dynamic_offset: false,
264-
min_binding_size: None,
254+
let bind_group_layout =
255+
self.device
256+
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
257+
entries: &[
258+
wgpu::BindGroupLayoutEntry {
259+
binding: 0,
260+
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
261+
ty: wgpu::BindingType::Buffer {
262+
ty: wgpu::BufferBindingType::Uniform,
263+
has_dynamic_offset: false,
264+
min_binding_size: None,
265+
},
266+
count: None,
265267
},
266-
count: None,
267-
},
268-
wgpu::BindGroupLayoutEntry {
269-
binding: 1,
270-
visibility: wgpu::ShaderStages::FRAGMENT,
271-
ty: wgpu::BindingType::Buffer {
272-
ty: wgpu::BufferBindingType::Storage { read_only: true },
273-
has_dynamic_offset: false,
274-
min_binding_size: None,
268+
wgpu::BindGroupLayoutEntry {
269+
binding: 1,
270+
visibility: wgpu::ShaderStages::FRAGMENT,
271+
ty: wgpu::BindingType::Buffer {
272+
ty: wgpu::BufferBindingType::Storage { read_only: true },
273+
has_dynamic_offset: false,
274+
min_binding_size: None,
275+
},
276+
count: None,
275277
},
276-
count: None,
277-
},
278-
],
279-
label: Some("shape_bind_group_layout"),
280-
});
278+
],
279+
label: Some("shape_bind_group_layout"),
280+
});
281281

282282
let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
283283
layout: &bind_group_layout,
@@ -404,7 +404,11 @@ impl<'a> GpuResourceAllocator<'a> {
404404
pub fn create_render_texture(&self, label: &str, width: u32, height: u32) -> TextureResource {
405405
let texture = self.device.create_texture(&wgpu::TextureDescriptor {
406406
label: Some(label),
407-
size: wgpu::Extent3d { width, height, depth_or_array_layers: 1 },
407+
size: wgpu::Extent3d {
408+
width,
409+
height,
410+
depth_or_array_layers: 1,
411+
},
408412
mip_level_count: 1,
409413
sample_count: 1,
410414
dimension: wgpu::TextureDimension::D2,
@@ -424,7 +428,11 @@ impl<'a> GpuResourceAllocator<'a> {
424428
..Default::default()
425429
});
426430

427-
let diffuse_texture = Texture { texture, view, sampler };
431+
let diffuse_texture = Texture {
432+
texture,
433+
view,
434+
sampler,
435+
};
428436

429437
let texture_bind_group_layout =
430438
self.device
@@ -586,7 +594,11 @@ impl<'a> GpuResourceAllocator<'a> {
586594
self.queue.submit(iter::once(encoder.finish()));
587595
}
588596

589-
pub fn create_texture_resource_from_existing(&self, label: &str, texture: &crate::renderer::Texture) -> TextureResource {
597+
pub fn create_texture_resource_from_existing(
598+
&self,
599+
label: &str,
600+
texture: &crate::renderer::Texture,
601+
) -> TextureResource {
590602
let texture_bind_group_layout =
591603
self.device
592604
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@@ -630,7 +642,11 @@ impl<'a> GpuResourceAllocator<'a> {
630642
// We can't clone the actual wgpu::Texture, so we'll use a dummy one
631643
let dummy_wgpu_texture = self.device.create_texture(&wgpu::TextureDescriptor {
632644
label: Some("dummy_reference"),
633-
size: wgpu::Extent3d { width: 1, height: 1, depth_or_array_layers: 1 },
645+
size: wgpu::Extent3d {
646+
width: 1,
647+
height: 1,
648+
depth_or_array_layers: 1,
649+
},
634650
mip_level_count: 1,
635651
sample_count: 1,
636652
dimension: wgpu::TextureDimension::D2,
@@ -640,7 +656,9 @@ impl<'a> GpuResourceAllocator<'a> {
640656
});
641657

642658
let dummy_view = dummy_wgpu_texture.create_view(&wgpu::TextureViewDescriptor::default());
643-
let dummy_sampler = self.device.create_sampler(&wgpu::SamplerDescriptor::default());
659+
let dummy_sampler = self
660+
.device
661+
.create_sampler(&wgpu::SamplerDescriptor::default());
644662

645663
let dummy_texture = crate::renderer::Texture {
646664
texture: dummy_wgpu_texture,

0 commit comments

Comments
 (0)