@ -1,6 +1,6 @@
use bevy ::{
core_pipeline ::clear_color ::ClearColorConfig ,
gltf ::Gltf ,
gltf ::{ Gltf , GltfNode } ,
input ::{
keyboard ::KeyboardInput ,
mouse ::{ MouseMotion , MouseWheel } ,
@ -13,32 +13,47 @@ use bevy::{
render_resource ::{
Extent3d , TextureDescriptor , TextureDimension , TextureFormat , TextureUsages ,
} ,
view ::VisibleEntities ,
} ,
utils::HashSet ,
window::PrimaryWindow ,
} ;
use bevy_rapier3d ::{ prelude ::* , rapier ::prelude ::RigidBodyType } ;
use monologue_trees ::{ debug ::* , text ::* } ;
fn main ( ) {
App ::new ( )
. add_plugins ( DefaultPlugins . set ( WindowPlugin {
. add_plugins ( (
DefaultPlugins . set ( WindowPlugin {
primary_window : Some ( Window {
title : "GLTF Inspector" . into ( ) ,
resolution : ( 640. , 480. ) . into ( ) ,
.. default ( )
} ) ,
.. default ( )
} ) )
} ) ,
DebugInfoPlugin ,
RapierPhysicsPlugin ::< NoUserData > ::default ( ) ,
RapierDebugRenderPlugin ::default ( ) ,
) )
. add_event ::< ManageActive > ( )
. add_startup_system ( load_models )
. add_startup_system ( spawn_base_scene )
. add_startup_system ( spawn_base_ui )
. add_system ( spawn_models )
. add_system ( spawn_ui )
. add_system ( control_animation )
. add_system ( rotate_model )
. add_system ( zoom_model )
. add_system ( scroll )
. add_system ( select )
. add_system ( manage_active )
. add_event ::< Selected > ( )
. add_systems ( PreStartup , load_models )
. add_systems ( Startup , ( spawn_base_scene , spawn_base_ui ) )
. add_systems (
Update ,
(
spawn_models ,
spawn_ui ,
control_animation ,
rotate_model ,
zoom_model ,
scroll ,
select ,
manage_active ,
inspect_nodes ,
selection ,
) ,
)
. run ( ) ;
}
@ -74,9 +89,17 @@ struct Active;
///
/// Event for managing which entities are tagged "Active"
#[ derive( Debug)]
#[ derive( Event, Debug)]
struct ManageActive ( Option < Entity > ) ;
///
/// Event for tracking which entities are selected
#[ derive(Event, Debug) ]
enum Selected {
Hovered ( Entity ) ,
Selected ( Entity ) ,
}
///
/// Load all GLTF models on startup
fn load_models ( mut commands : Commands , ass : Res < AssetServer > ) {
@ -110,8 +133,9 @@ fn spawn_base_ui(mut commands: Commands) {
NodeBundle {
style : Style {
justify_content : JustifyContent ::Center ,
size : Size ::all ( Val ::Percent ( 90.0 ) ) ,
overflow : Overflow ::Hidden ,
width : Val ::Percent ( 90.0 ) ,
height : Val ::Percent ( 90.0 ) ,
overflow : Overflow ::clip ( ) ,
.. default ( )
} ,
.. default ( )
@ -125,8 +149,8 @@ fn spawn_base_ui(mut commands: Commands) {
flex_wrap : FlexWrap ::Wrap ,
flex_direction : FlexDirection ::Row ,
justify_content : JustifyContent ::SpaceAround ,
size: Size ::AUTO ,
max_size: Size ::UNDEFINED ,
width: Val ::Auto ,
height: Val ::Auto ,
.. default ( )
} ,
.. default ( )
@ -271,6 +295,8 @@ fn spawn_models(
scene : handle . clone ( ) ,
.. default ( )
} ,
RigidBody ::KinematicPositionBased ,
Collider ::cylinder ( 1.0 , 1.0 ) ,
Inspect ,
) ) ;
} ) ;
@ -306,7 +332,8 @@ fn spawn_ui(
. with_children ( | parent | {
parent . spawn ( ImageBundle {
style : Style {
size : Size ::all ( Val ::Px ( 256.0 ) ) ,
width : Val ::Px ( 256.0 ) ,
height : Val ::Px ( 256.0 ) ,
padding : UiRect ::all ( Val ::Px ( 5.0 ) ) ,
.. default ( )
} ,
@ -322,6 +349,15 @@ fn spawn_ui(
}
}
fn inspect_nodes ( gltfs : Res < Assets < Gltf > > , nodes : Res < Assets < GltfNode > > , mut done : Local < bool > ) {
if ! ( * done ) {
for gltf in gltfs . iter ( ) {
// info!("Gltf {:#?}", gltf);
* done = true ;
}
}
}
fn control_animation (
mut key_evr : EventReader < KeyboardInput > ,
mut active_evr : EventReader < ManageActive > ,
@ -425,7 +461,7 @@ fn zoom_model(
mut wheel_evr : EventReader < MouseWheel > ,
mut transforms : Query < & mut Transform , ( With < Inspect > , With < Active > , Without < Camera > ) > ,
) {
if keys . pressed ( KeyCode ::L Shift) {
if keys . pressed ( KeyCode :: ShiftLe ft) {
for ev in wheel_evr . iter ( ) {
for mut transform in transforms . iter_mut ( ) {
let scale = ( Vec3 ::ONE * ev . y ) / 100.0 ;
@ -444,7 +480,7 @@ fn scroll(
// Only scroll if scene not selected
if active . is_empty ( ) {
for mut s in query . iter_mut ( ) {
s . position. top = match s . position . top {
s . top = match s . top {
Val ::Px ( current ) = > Val ::Px ( current + ( ev . y * 5.0 ) ) ,
_ = > Val ::Px ( 0.0 ) ,
} ;
@ -471,7 +507,7 @@ fn select(
mut events : EventWriter < ManageActive > ,
) {
for ( interaction , selected_preview ) in query . iter ( ) {
if interaction = = & Interaction ::Click ed {
if interaction = = & Interaction ::Press ed {
// Hide UI
let mut ui_vis = selection_ui . single_mut ( ) ;
* ui_vis = Visibility ::Hidden ;
@ -537,25 +573,23 @@ fn manage_active(
mut events : EventReader < ManageActive > ,
query : Query < & Children > ,
current : Query < Entity , With < Active > > ,
names : Query < & Name > ,
) {
for event in events . iter ( ) {
info ! ( "Setting active: {:?}" , event ) ;
match event {
ManageActive ( None ) = > {
for ManageActive( inner ) in events . iter ( ) {
info ! ( "Setting active: {:?}" , inner ) ;
match inner {
None = > {
for entity in current . iter ( ) {
if let Some ( mut entity_commands ) = commands . get_entity ( entity ) {
entity_commands . remove ::< Active > ( ) ;
entity_commands . remove ::< ColliderDebugColor > ( ) ;
}
}
}
ManageActive ( Some ( entity ) ) = > {
Some ( entity ) = > {
for child in query . iter_descendants ( * entity ) {
if let Some ( mut child_commands ) = commands . get_entity ( child ) {
// info!(
// "Active entity components: {:?} {:?}",
// child,
// names.get(child)
// );
// info!("Name: {:?}", names.get(child));
// child_commands.log_components();
child_commands . insert ( Active ) ;
}
@ -564,3 +598,36 @@ fn manage_active(
}
}
}
fn selection (
mut commands : Commands ,
windows : Query < & Window , With < PrimaryWindow > > ,
mut mouse_events : EventReader < MouseMotion > ,
camera_q : Query < ( & Camera , & GlobalTransform , & VisibleEntities ) , With < Active > > ,
rapier_context : Res < RapierContext > ,
) {
if ! mouse_events . is_empty ( ) {
let window = windows . single ( ) ;
for _ in mouse_events . iter ( ) {
if let Some ( cursor ) = window . cursor_position ( ) {
for ( camera , camera_t , visible_entities ) in camera_q . iter ( ) {
if let Some ( ray ) = camera . viewport_to_world ( camera_t , cursor ) {
if let Some ( ( entity , toi ) ) = rapier_context . cast_ray (
ray . origin ,
ray . direction ,
f32 ::MAX ,
true ,
QueryFilter ::new ( )
. predicate ( & | entity | visible_entities . entities . contains ( & entity ) ) ,
) {
if let Some ( mut cmds ) = commands . get_entity ( entity ) {
info ! ( "hit! ({:?}@{})" , entity , toi ) ;
cmds . insert ( ColliderDebugColor ( Color ::BLUE ) ) ;
}
}
}
}
}
}
}
}