1+ use std:: f32:: consts:: PI ;
2+
13use alkahest_renderer:: {
24 camera:: Camera ,
3- ecs:: { resources:: SelectedEntity , transform:: Transform } ,
5+ ecs:: {
6+ resources:: SelectedEntity ,
7+ transform:: { Transform , TransformFlags } ,
8+ } ,
49 icons:: { ICON_AXIS_ARROW , ICON_CURSOR_DEFAULT , ICON_RESIZE , ICON_ROTATE_ORBIT } ,
510 renderer:: Renderer ,
611 resources:: AppResources ,
@@ -9,9 +14,10 @@ use egui::{
914 epaint:: Vertex , Context , LayerId , Mesh , PointerButton , Pos2 , Rgba , RichText , Rounding , Ui ,
1015 UiStackInfo ,
1116} ;
12- use glam:: { DQuat , DVec3 } ;
17+ use glam:: { DQuat , DVec3 , Quat , Vec3 } ;
1318use transform_gizmo_egui:: {
14- math:: Transform as GTransform , Gizmo , GizmoConfig , GizmoInteraction , GizmoResult ,
19+ math:: Transform as GTransform , EnumSet , Gizmo , GizmoConfig , GizmoInteraction , GizmoMode ,
20+ GizmoResult ,
1521} ;
1622use winit:: window:: Window ;
1723
@@ -111,6 +117,13 @@ impl GuiView for GizmoSelector {
111117 }
112118}
113119
120+ #[ derive( Default ) ]
121+ pub struct GizmoInfo {
122+ pub gizmo : Gizmo ,
123+ pub mode_filter : Option < EnumSet < GizmoMode > > ,
124+ pub rotation_axis : Option < Vec3 > ,
125+ }
126+
114127pub fn draw_transform_gizmos ( renderer : & Renderer , ctx : & egui:: Context , resources : & AppResources ) {
115128 let Some ( selected) = resources. get :: < SelectedEntity > ( ) . selected ( ) else {
116129 return ;
@@ -134,26 +147,69 @@ pub fn draw_transform_gizmos(renderer: &Renderer, ctx: &egui::Context, resources
134147 } ;
135148 let camera = resources. get :: < Camera > ( ) ;
136149
137- let mut gizmo = resources. get_mut :: < Gizmo > ( ) ;
138- let old_config = * gizmo. config ( ) ;
139- gizmo. update_config ( GizmoConfig {
140- view_matrix : camera. world_to_camera . as_dmat4 ( ) . into ( ) ,
141- projection_matrix : camera. camera_to_projective . as_dmat4 ( ) . into ( ) ,
142- modes : gizmo_mode. to_enumset ( ) ,
143- ..old_config
144- } ) ;
150+ let mut gizmo_info = resources. get_mut :: < Vec < GizmoInfo > > ( ) ;
145151
146- if let Some ( ( _result, new_transform) ) = gizmo_interact (
147- & mut gizmo,
152+ for ( i, info) in gizmo_info. iter_mut ( ) . enumerate ( ) {
153+ let old_config = * info. gizmo . config ( ) ;
154+
155+ if transform
156+ . flags
157+ . contains ( TransformFlags :: SCALE_IS_BIDIRECTIONAL )
158+ || i == 1
159+ {
160+ info. gizmo . update_config ( GizmoConfig {
161+ view_matrix : camera. world_to_camera . as_dmat4 ( ) . into ( ) ,
162+ projection_matrix : camera. camera_to_projective . as_dmat4 ( ) . into ( ) ,
163+ modes : match info. mode_filter {
164+ Some ( filter) => gizmo_mode. to_enumset ( ) . intersection ( filter) ,
165+ None => gizmo_mode. to_enumset ( ) ,
166+ } ,
167+ ..old_config
168+ } ) ;
169+ } else {
170+ info. gizmo . update_config ( GizmoConfig {
171+ view_matrix : camera. world_to_camera . as_dmat4 ( ) . into ( ) ,
172+ projection_matrix : camera. camera_to_projective . as_dmat4 ( ) . into ( ) ,
173+ modes : EnumSet :: empty ( ) ,
174+ ..old_config
175+ } ) ;
176+ }
177+ }
178+
179+ let end = if transform
180+ . flags
181+ . contains ( TransformFlags :: SCALE_IS_BIDIRECTIONAL )
182+ {
183+ gizmo_info. len ( )
184+ } else {
185+ gizmo_info. len ( ) . min ( 1 )
186+ } ;
187+
188+ if let Some ( ( _result, new_transform, i) ) = gizmo_interact (
189+ & mut gizmo_info[ ..end] ,
148190 ctx,
149191 & [ GTransform {
150192 scale : transform. scale . as_dvec3 ( ) . into ( ) ,
151193 rotation : transform. rotation . as_dquat ( ) . into ( ) ,
152194 translation : transform. translation . as_dvec3 ( ) . into ( ) ,
153195 } ] ,
196+ & mut [ GTransform :: default ( ) ] ,
154197 ) {
155198 renderer. pickbuffer . cancel_request ( ) ;
156- transform. translation = DVec3 :: from ( new_transform[ 0 ] . translation ) . as_vec3 ( ) ;
199+
200+ transform. translation = DVec3 :: from ( new_transform[ 0 ] . translation ) . as_vec3 ( )
201+ + if transform
202+ . flags
203+ . contains ( TransformFlags :: SCALE_IS_BIDIRECTIONAL )
204+ {
205+ if i == 0 {
206+ DVec3 :: from ( new_transform[ 0 ] . scale ) . as_vec3 ( ) - transform. scale
207+ } else {
208+ transform. scale - DVec3 :: from ( new_transform[ 0 ] . scale ) . as_vec3 ( )
209+ }
210+ } else {
211+ Vec3 :: ZERO
212+ } ;
157213 transform. rotation = DQuat :: from ( new_transform[ 0 ] . rotation ) . as_quat ( ) . normalize ( ) ;
158214 transform. scale = DVec3 :: from ( new_transform[ 0 ] . scale ) . as_vec3 ( ) ;
159215 }
@@ -162,52 +218,77 @@ pub fn draw_transform_gizmos(renderer: &Renderer, ctx: &egui::Context, resources
162218
163219#[ must_use]
164220fn gizmo_interact (
165- gizmo : & mut Gizmo ,
221+ gizmo_info : & mut [ GizmoInfo ] ,
166222 ctx : & egui:: Context ,
167223 targets : & [ GTransform ] ,
168- ) -> Option < ( GizmoResult , Vec < GTransform > ) > {
224+ targets_scratch : & mut [ GTransform ] ,
225+ ) -> Option < ( GizmoResult , Vec < GTransform > , usize ) > {
169226 let cursor_pos = ctx
170227 . input ( |input| input. pointer . hover_pos ( ) )
171228 . unwrap_or_default ( ) ;
172229
173- let mut viewport = gizmo. config ( ) . viewport ;
174- if !viewport. is_finite ( ) {
175- viewport = ctx. screen_rect ( ) ;
230+ let mut active_result = None ;
231+ for ( i, info) in gizmo_info. iter_mut ( ) . enumerate ( ) {
232+ let mut viewport = info. gizmo . config ( ) . viewport ;
233+ if !viewport. is_finite ( ) {
234+ viewport = ctx. screen_rect ( ) ;
235+ }
236+ info. gizmo . update_config ( GizmoConfig {
237+ viewport,
238+ pixels_per_point : ctx. pixels_per_point ( ) ,
239+ ..* info. gizmo . config ( )
240+ } ) ;
241+ if active_result. is_none ( ) {
242+ for ( target, target_scratch) in targets. iter ( ) . zip ( targets_scratch. iter_mut ( ) ) {
243+ target_scratch. rotation = if let Some ( axis) = info. rotation_axis {
244+ DQuat :: from ( target. rotation )
245+ . as_quat ( )
246+ . mul_quat ( Quat :: from_axis_angle ( axis, PI ) )
247+ . as_dquat ( )
248+ . into ( )
249+ } else {
250+ target. rotation
251+ } ;
252+ target_scratch. translation = target. translation ;
253+ target_scratch. scale = target. scale ;
254+ }
255+ let gizmo_result = info. gizmo . update (
256+ GizmoInteraction {
257+ cursor_pos : ( cursor_pos. x , cursor_pos. y ) ,
258+ drag_started : ctx
259+ . input ( |input| input. pointer . button_pressed ( PointerButton :: Primary ) ) ,
260+ dragging : ctx. input ( |input| input. pointer . button_down ( PointerButton :: Primary ) ) ,
261+ } ,
262+ targets_scratch,
263+ ) ;
264+ active_result = gizmo_result. map ( |( g, v) | ( g, v, i) ) ;
265+ }
176266 }
177267
178- gizmo. update_config ( GizmoConfig {
179- viewport,
180- pixels_per_point : ctx. pixels_per_point ( ) ,
181- ..* gizmo. config ( )
182- } ) ;
183-
184- let gizmo_result = gizmo. update (
185- GizmoInteraction {
186- cursor_pos : ( cursor_pos. x , cursor_pos. y ) ,
187- drag_started : ctx. input ( |input| input. pointer . button_pressed ( PointerButton :: Primary ) ) ,
188- dragging : ctx. input ( |input| input. pointer . button_down ( PointerButton :: Primary ) ) ,
189- } ,
190- targets,
191- ) ;
192-
193- let draw_data = gizmo. draw ( ) ;
194-
195- ctx. layer_painter ( egui:: LayerId :: background ( ) )
196- // .with_clip_rect(egui_viewport)
197- . add ( Mesh {
198- indices : draw_data. indices ,
199- vertices : draw_data
200- . vertices
201- . into_iter ( )
202- . zip ( draw_data. colors )
203- . map ( |( pos, [ r, g, b, a] ) | Vertex {
204- pos : pos. into ( ) ,
205- uv : Pos2 :: default ( ) ,
206- color : Rgba :: from_rgba_premultiplied ( r, g, b, a) . into ( ) ,
207- } )
208- . collect ( ) ,
209- ..Default :: default ( )
210- } ) ;
268+ for ( i, info) in gizmo_info. iter_mut ( ) . enumerate ( ) {
269+ if active_result
270+ . as_ref ( )
271+ . map_or ( true , |( _, _, active) | * active == i)
272+ {
273+ let draw_data = info. gizmo . draw ( ) ;
211274
212- gizmo_result
275+ ctx. layer_painter ( egui:: LayerId :: background ( ) )
276+ // .with_clip_rect(egui_viewport)
277+ . add ( Mesh {
278+ indices : draw_data. indices ,
279+ vertices : draw_data
280+ . vertices
281+ . into_iter ( )
282+ . zip ( draw_data. colors )
283+ . map ( |( pos, [ r, g, b, a] ) | Vertex {
284+ pos : pos. into ( ) ,
285+ uv : Pos2 :: default ( ) ,
286+ color : Rgba :: from_rgba_premultiplied ( r, g, b, a) . into ( ) ,
287+ } )
288+ . collect ( ) ,
289+ ..Default :: default ( )
290+ } ) ;
291+ }
292+ }
293+ active_result
213294}
0 commit comments