diff --git a/editor/editor.jai b/editor/editor.jai index aa7c058..8fa8b1a 100644 --- a/editor/editor.jai +++ b/editor/editor.jai @@ -114,6 +114,7 @@ Editor :: struct { camera: Camera; transform_gizmo: Transform_Gizmo; selected_entities: [..] *Entity; + selected_entity_transforms : Table(*Entity, Transform); mouse_viewport_state: Interaction_State; last_right_mouse_click_time: float; @@ -171,19 +172,31 @@ init_transform_gizmo :: () { } update_transform_gizmo :: (ray: Ray, mouse_position: Vector2) -> bool { - if engine.editor.selected_entities.count != 1 return false; - - selected_entity := engine.editor.selected_entities[0]; - - if key_down(.TAB) { - if engine.editor.transform_gizmo.space == { - case .WORLD; + if engine.editor.selected_entities.count != 1 { + // Hardcode to world + translation when selecting multiple entities + // We currently don't need to do anything but translate in world space, when having multiple entities selected + engine.editor.transform_gizmo.space = .WORLD; + engine.editor.transform_gizmo.transform_type = .TRANSLATION; + } else { + if key_down(.TAB) { + if engine.editor.transform_gizmo.space == { + case .WORLD; engine.editor.transform_gizmo.space = .LOCAL; - case .LOCAL; + case .LOCAL; engine.editor.transform_gizmo.space = .WORLD; + } } } + position : Vector3; + for e: engine.editor.selected_entities { + position += e.transform.position; + } + + position /= cast(float)engine.editor.selected_entities.count; + + selected_entity := engine.editor.selected_entities[0]; + if engine.editor.transform_gizmo.space == { case .WORLD; set_rotation(*engine.editor.transform_gizmo.transform, .{0,0,0,1}); @@ -191,17 +204,28 @@ update_transform_gizmo :: (ray: Ray, mouse_position: Vector2) -> bool { set_rotation(*engine.editor.transform_gizmo.transform, selected_entity.transform.orientation); } + engine.editor.transform_gizmo.actual_entity_position = position; + if engine.editor.transform_gizmo.transform_type == { case .TRANSLATION; if !key_pressed(.MOUSE_LEFT) { - selected_axis, t := intersect_translation_gizmo(ray); - engine.editor.transform_gizmo.selected_axis = selected_axis; + if key_pressed(.CTRL) { + engine.editor.transform_gizmo.selected_axis = .NONE; + table_reset(*engine.editor.selected_entity_transforms); + } else { + selected_axis, t := intersect_translation_gizmo(ray); + engine.editor.transform_gizmo.selected_axis = selected_axis; + table_reset(*engine.editor.selected_entity_transforms); + } } else if engine.editor.transform_gizmo.can_use && engine.editor.transform_gizmo.selected_axis != .NONE { first_update := key_down(.MOUSE_LEFT); if first_update { - engine.editor.transform_gizmo.actual_entity_position = selected_entity.transform.position; - push_transform_undo(engine.editor.selected_entities[0]); + + for engine.editor.selected_entities { + push_transform_undo(it); + table_add(*engine.editor.selected_entity_transforms, it, it.transform); + } } // Move the currently selected entity along the selected axis @@ -231,7 +255,7 @@ update_transform_gizmo :: (ray: Ray, mouse_position: Vector2) -> bool { } r1 : Ray; - r1.origin = selected_entity.transform.position; + r1.origin = position; r1.direction = axis_vec; r2 := normalized_screen_to_ray(*engine.editor.camera, mouse_position); @@ -246,21 +270,28 @@ update_transform_gizmo :: (ray: Ray, mouse_position: Vector2) -> bool { position_change := new_position - engine.editor.transform_gizmo.first_hit_position; - entity_position := engine.editor.transform_gizmo.actual_entity_position + position_change; + for e: engine.editor.selected_entities { + found, transform := table_find_new(*engine.editor.selected_entity_transforms, e); + assert(found); - if engine.editor.transform_gizmo.snap_to_grid { - snap_interval := Vector3.{1,1,1}; - entity_position.x -= fmod_cycling(entity_position.x - selected_entity.snap_offset.x, snap_interval.x);// + selected_entity.snap_offset.x; - entity_position.y -= fmod_cycling(entity_position.y - selected_entity.snap_offset.y, snap_interval.y);// + selected_entity.snap_offset.y; - entity_position.z -= fmod_cycling(entity_position.z - selected_entity.snap_offset.z, snap_interval.z);// + selected_entity.snap_offset.z; - } else if selected_entity.flags & Entity_Flags.SNAP_TO_GRID { - entity_position.x -= fmod_cycling(entity_position.x - selected_entity.snap_offset.x, selected_entity.snap_intervals.x);// + selected_entity.snap_offset.x; - entity_position.y -= fmod_cycling(entity_position.y - selected_entity.snap_offset.y, selected_entity.snap_intervals.y);// + selected_entity.snap_offset.y; - entity_position.z -= fmod_cycling(entity_position.z - selected_entity.snap_offset.z, selected_entity.snap_intervals.z);// + selected_entity.snap_offset.z; + entity_position := transform.position + position_change; + if engine.editor.transform_gizmo.snap_to_grid { + snap_interval := Vector3.{1,1,1}; + entity_position.x -= fmod_cycling(entity_position.x - e.snap_offset.x, snap_interval.x);// + selected_entity.snap_offset.x; + entity_position.y -= fmod_cycling(entity_position.y - e.snap_offset.y, snap_interval.y);// + selected_entity.snap_offset.y; + entity_position.z -= fmod_cycling(entity_position.z - e.snap_offset.z, snap_interval.z);// + selected_entity.snap_offset.z; + } else if selected_entity.flags & Entity_Flags.SNAP_TO_GRID { + entity_position.x -= fmod_cycling(entity_position.x - e.snap_offset.x, e.snap_intervals.x);// + selected_entity.snap_offset.x; + entity_position.y -= fmod_cycling(entity_position.y - e.snap_offset.y, e.snap_intervals.y);// + selected_entity.snap_offset.y; + entity_position.z -= fmod_cycling(entity_position.z - e.snap_offset.z, e.snap_intervals.z);// + selected_entity.snap_offset.z; + } + + e.transform.position = entity_position; + e.transform.dirty = true; } - selected_entity.transform.position = entity_position; - selected_entity.transform.dirty = true; + entity_position := engine.editor.transform_gizmo.actual_entity_position + position_change; + engine.editor.transform_gizmo.actual_entity_position = entity_position; set_position(*engine.editor.transform_gizmo.transform, entity_position); } @@ -670,8 +701,16 @@ intersect_rotation_gizmo :: (ray: Ray) -> Transform_Axis, Vector3 { } update_gizmo_buffers :: () { + position : Vector3; + for e: engine.editor.selected_entities { + position += e.transform.position; + } + + position /= cast(float)engine.editor.selected_entities.count; + entity := engine.editor.selected_entities[0]; - engine.editor.transform_gizmo.transform.position = entity.transform.position; + + engine.editor.transform_gizmo.transform.position = position; engine.editor.transform_gizmo.transform.orientation = ifx engine.editor.transform_gizmo.space == .LOCAL then entity.transform.orientation else .{0,0,0,1}; update_matrix(*engine.editor.transform_gizmo.transform); @@ -689,7 +728,7 @@ update_gizmo_buffers :: () { } render_transform_gizmo :: () { - if engine.editor.selected_entities.count == 1 { + if engine.editor.selected_entities.count > 0 { update_gizmo_buffers(); renderer := engine.renderer; push_cmd_set_draw_mode(renderer, .FILL); diff --git a/editor/editor_ui.jai b/editor/editor_ui.jai index a8182ad..19da616 100644 --- a/editor/editor_ui.jai +++ b/editor/editor_ui.jai @@ -24,6 +24,8 @@ pick_scene_view_at :: (camera: Camera, coordinates: Vector2) { engine.editor.selected_entities.count = 0; } array_add(*engine.editor.selected_entities, hit_entity); + } else { + array_unordered_remove_by_value(*engine.editor.selected_entities, hit_entity); } } else { engine.editor.selected_entities.count = 0; @@ -174,7 +176,7 @@ base_editor_update :: () { if engine.editor.focused_widget == null && engine.mode == .EDITING { engine.editor.should_check_entities = true; - if engine.editor.selected_entities.count == 1 { + if engine.editor.selected_entities.count > 0 { entity := engine.editor.selected_entities[0]; gizmo_scale := distance(entity.transform.position, engine.editor.camera.position) * 0.1 * 0.5; engine.editor.transform_gizmo.uniform_gizmo_scale = gizmo_scale;