@@ -21,15 +21,13 @@ use bevy_transform::{
21
21
hierarchy:: { BuildWorldChildren , WorldChildBuilder } ,
22
22
prelude:: { GlobalTransform , Transform } ,
23
23
} ;
24
+ use bevy_utils:: { HashMap , HashSet } ;
24
25
use gltf:: {
25
26
mesh:: Mode ,
26
27
texture:: { MagFilter , MinFilter , WrappingMode } ,
27
28
Material , Primitive ,
28
29
} ;
29
- use std:: {
30
- collections:: { HashMap , HashSet } ,
31
- path:: Path ,
32
- } ;
30
+ use std:: { collections:: VecDeque , path:: Path } ;
33
31
use thiserror:: Error ;
34
32
use wgpu:: { AddressMode , FilterMode , PrimitiveTopology , SamplerDescriptor , TextureFormat } ;
35
33
@@ -83,8 +81,8 @@ async fn load_gltf<'a, 'b>(
83
81
let buffer_data = load_buffers ( & gltf, load_context, load_context. path ( ) ) . await ?;
84
82
85
83
let mut materials = vec ! [ ] ;
86
- let mut named_materials = HashMap :: new ( ) ;
87
- let mut linear_textures = HashSet :: new ( ) ;
84
+ let mut named_materials = HashMap :: default ( ) ;
85
+ let mut linear_textures = HashSet :: default ( ) ;
88
86
for material in gltf. materials ( ) {
89
87
let handle = load_material ( & material, load_context) ;
90
88
if let Some ( name) = material. name ( ) {
@@ -106,7 +104,7 @@ async fn load_gltf<'a, 'b>(
106
104
}
107
105
108
106
let mut meshes = vec ! [ ] ;
109
- let mut named_meshes = HashMap :: new ( ) ;
107
+ let mut named_meshes = HashMap :: default ( ) ;
110
108
for mesh in gltf. meshes ( ) {
111
109
let mut primitives = vec ! [ ] ;
112
110
for primitive in mesh. primitives ( ) {
@@ -195,7 +193,7 @@ async fn load_gltf<'a, 'b>(
195
193
}
196
194
197
195
let mut nodes_intermediate = vec ! [ ] ;
198
- let mut named_nodes_intermediate = HashMap :: new ( ) ;
196
+ let mut named_nodes_intermediate = HashMap :: default ( ) ;
199
197
for node in gltf. nodes ( ) {
200
198
let node_label = node_label ( & node) ;
201
199
nodes_intermediate. push ( (
@@ -229,7 +227,7 @@ async fn load_gltf<'a, 'b>(
229
227
named_nodes_intermediate. insert ( name, node. index ( ) ) ;
230
228
}
231
229
}
232
- let nodes = resolve_node_hierarchy ( nodes_intermediate)
230
+ let nodes = resolve_node_hierarchy ( nodes_intermediate, load_context . path ( ) )
233
231
. into_iter ( )
234
232
. map ( |( label, node) | load_context. set_labeled_asset ( & label, LoadedAsset :: new ( node) ) )
235
233
. collect :: < Vec < bevy_asset:: Handle < GltfNode > > > ( ) ;
@@ -275,7 +273,7 @@ async fn load_gltf<'a, 'b>(
275
273
} ) ;
276
274
277
275
let mut scenes = vec ! [ ] ;
278
- let mut named_scenes = HashMap :: new ( ) ;
276
+ let mut named_scenes = HashMap :: default ( ) ;
279
277
for scene in gltf. scenes ( ) {
280
278
let mut err = None ;
281
279
let mut world = World :: default ( ) ;
@@ -716,42 +714,51 @@ async fn load_buffers(
716
714
717
715
fn resolve_node_hierarchy (
718
716
nodes_intermediate : Vec < ( String , GltfNode , Vec < usize > ) > ,
717
+ asset_path : & Path ,
719
718
) -> Vec < ( String , GltfNode ) > {
720
- let mut max_steps = nodes_intermediate. len ( ) ;
721
- let mut nodes_step = nodes_intermediate
719
+ let mut has_errored = false ;
720
+ let mut empty_children = VecDeque :: new ( ) ;
721
+ let mut parents = vec ! [ None ; nodes_intermediate. len( ) ] ;
722
+ let mut unprocessed_nodes = nodes_intermediate
722
723
. into_iter ( )
723
724
. enumerate ( )
724
- . map ( |( i, ( label, node, children) ) | ( i, label, node, children) )
725
- . collect :: < Vec < _ > > ( ) ;
726
- let mut nodes = std:: collections:: HashMap :: < usize , ( String , GltfNode ) > :: new ( ) ;
727
- while max_steps > 0 && !nodes_step. is_empty ( ) {
728
- if let Some ( ( index, label, node, _) ) = nodes_step
729
- . iter ( )
730
- . find ( |( _, _, _, children) | children. is_empty ( ) )
731
- . cloned ( )
732
- {
733
- nodes. insert ( index, ( label, node) ) ;
734
- for ( _, _, node, children) in nodes_step. iter_mut ( ) {
735
- if let Some ( ( i, _) ) = children
736
- . iter ( )
737
- . enumerate ( )
738
- . find ( |( _, child_index) | * * child_index == index)
739
- {
740
- children. remove ( i) ;
741
-
742
- if let Some ( ( _, child_node) ) = nodes. get ( & index) {
743
- node. children . push ( child_node. clone ( ) )
744
- }
725
+ . map ( |( i, ( label, node, children) ) | {
726
+ for child in children. iter ( ) {
727
+ if let Some ( parent) = parents. get_mut ( * child) {
728
+ * parent = Some ( i) ;
729
+ } else if !has_errored {
730
+ has_errored = true ;
731
+ warn ! ( "Unexpected child in GLTF Mesh {}" , child) ;
745
732
}
746
733
}
747
- nodes_step = nodes_step
748
- . into_iter ( )
749
- . filter ( |( i, _, _, _) | * i != index)
750
- . collect ( )
734
+ let children = children. into_iter ( ) . collect :: < HashSet < _ > > ( ) ;
735
+ if children. is_empty ( ) {
736
+ empty_children. push_back ( i) ;
737
+ }
738
+ ( i, ( label, node, children) )
739
+ } )
740
+ . collect :: < HashMap < _ , _ > > ( ) ;
741
+ let mut nodes = std:: collections:: HashMap :: < usize , ( String , GltfNode ) > :: new ( ) ;
742
+ while let Some ( index) = empty_children. pop_front ( ) {
743
+ let ( label, node, children) = unprocessed_nodes. remove ( & index) . unwrap ( ) ;
744
+ assert ! ( children. is_empty( ) ) ;
745
+ nodes. insert ( index, ( label, node) ) ;
746
+ if let Some ( parent_index) = parents[ index] {
747
+ let ( _, parent_node, parent_children) =
748
+ unprocessed_nodes. get_mut ( & parent_index) . unwrap ( ) ;
749
+
750
+ assert ! ( parent_children. remove( & index) ) ;
751
+ if let Some ( ( _, child_node) ) = nodes. get ( & index) {
752
+ parent_node. children . push ( child_node. clone ( ) )
753
+ }
754
+ if parent_children. is_empty ( ) {
755
+ empty_children. push_back ( parent_index) ;
756
+ }
751
757
}
752
- max_steps -= 1 ;
753
758
}
754
-
759
+ if !unprocessed_nodes. is_empty ( ) {
760
+ warn ! ( "GLTF model must be a tree: {:?}" , asset_path) ;
761
+ }
755
762
let mut nodes_to_sort = nodes. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
756
763
nodes_to_sort. sort_by_key ( |( i, _) | * i) ;
757
764
nodes_to_sort
@@ -799,6 +806,8 @@ impl<'a> DataUri<'a> {
799
806
800
807
#[ cfg( test) ]
801
808
mod test {
809
+ use std:: path:: PathBuf ;
810
+
802
811
use super :: resolve_node_hierarchy;
803
812
use crate :: GltfNode ;
804
813
@@ -813,7 +822,10 @@ mod test {
813
822
}
814
823
#[ test]
815
824
fn node_hierarchy_single_node ( ) {
816
- let result = resolve_node_hierarchy ( vec ! [ ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ] ) ;
825
+ let result = resolve_node_hierarchy (
826
+ vec ! [ ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ] ,
827
+ PathBuf :: new ( ) . as_path ( ) ,
828
+ ) ;
817
829
818
830
assert_eq ! ( result. len( ) , 1 ) ;
819
831
assert_eq ! ( result[ 0 ] . 0 , "l1" ) ;
@@ -822,10 +834,13 @@ mod test {
822
834
823
835
#[ test]
824
836
fn node_hierarchy_no_hierarchy ( ) {
825
- let result = resolve_node_hierarchy ( vec ! [
826
- ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
827
- ( "l2" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
828
- ] ) ;
837
+ let result = resolve_node_hierarchy (
838
+ vec ! [
839
+ ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
840
+ ( "l2" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
841
+ ] ,
842
+ PathBuf :: new ( ) . as_path ( ) ,
843
+ ) ;
829
844
830
845
assert_eq ! ( result. len( ) , 2 ) ;
831
846
assert_eq ! ( result[ 0 ] . 0 , "l1" ) ;
@@ -836,10 +851,13 @@ mod test {
836
851
837
852
#[ test]
838
853
fn node_hierarchy_simple_hierarchy ( ) {
839
- let result = resolve_node_hierarchy ( vec ! [
840
- ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ 1 ] ) ,
841
- ( "l2" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
842
- ] ) ;
854
+ let result = resolve_node_hierarchy (
855
+ vec ! [
856
+ ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ 1 ] ) ,
857
+ ( "l2" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
858
+ ] ,
859
+ PathBuf :: new ( ) . as_path ( ) ,
860
+ ) ;
843
861
844
862
assert_eq ! ( result. len( ) , 2 ) ;
845
863
assert_eq ! ( result[ 0 ] . 0 , "l1" ) ;
@@ -850,15 +868,18 @@ mod test {
850
868
851
869
#[ test]
852
870
fn node_hierarchy_hierarchy ( ) {
853
- let result = resolve_node_hierarchy ( vec ! [
854
- ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ 1 ] ) ,
855
- ( "l2" . to_string( ) , GltfNode :: empty( ) , vec![ 2 ] ) ,
856
- ( "l3" . to_string( ) , GltfNode :: empty( ) , vec![ 3 , 4 , 5 ] ) ,
857
- ( "l4" . to_string( ) , GltfNode :: empty( ) , vec![ 6 ] ) ,
858
- ( "l5" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
859
- ( "l6" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
860
- ( "l7" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
861
- ] ) ;
871
+ let result = resolve_node_hierarchy (
872
+ vec ! [
873
+ ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ 1 ] ) ,
874
+ ( "l2" . to_string( ) , GltfNode :: empty( ) , vec![ 2 ] ) ,
875
+ ( "l3" . to_string( ) , GltfNode :: empty( ) , vec![ 3 , 4 , 5 ] ) ,
876
+ ( "l4" . to_string( ) , GltfNode :: empty( ) , vec![ 6 ] ) ,
877
+ ( "l5" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
878
+ ( "l6" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
879
+ ( "l7" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
880
+ ] ,
881
+ PathBuf :: new ( ) . as_path ( ) ,
882
+ ) ;
862
883
863
884
assert_eq ! ( result. len( ) , 7 ) ;
864
885
assert_eq ! ( result[ 0 ] . 0 , "l1" ) ;
@@ -879,20 +900,26 @@ mod test {
879
900
880
901
#[ test]
881
902
fn node_hierarchy_cyclic ( ) {
882
- let result = resolve_node_hierarchy ( vec ! [
883
- ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ 1 ] ) ,
884
- ( "l2" . to_string( ) , GltfNode :: empty( ) , vec![ 0 ] ) ,
885
- ] ) ;
903
+ let result = resolve_node_hierarchy (
904
+ vec ! [
905
+ ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ 1 ] ) ,
906
+ ( "l2" . to_string( ) , GltfNode :: empty( ) , vec![ 0 ] ) ,
907
+ ] ,
908
+ PathBuf :: new ( ) . as_path ( ) ,
909
+ ) ;
886
910
887
911
assert_eq ! ( result. len( ) , 0 ) ;
888
912
}
889
913
890
914
#[ test]
891
915
fn node_hierarchy_missing_node ( ) {
892
- let result = resolve_node_hierarchy ( vec ! [
893
- ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ 2 ] ) ,
894
- ( "l2" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
895
- ] ) ;
916
+ let result = resolve_node_hierarchy (
917
+ vec ! [
918
+ ( "l1" . to_string( ) , GltfNode :: empty( ) , vec![ 2 ] ) ,
919
+ ( "l2" . to_string( ) , GltfNode :: empty( ) , vec![ ] ) ,
920
+ ] ,
921
+ PathBuf :: new ( ) . as_path ( ) ,
922
+ ) ;
896
923
897
924
assert_eq ! ( result. len( ) , 1 ) ;
898
925
assert_eq ! ( result[ 0 ] . 0 , "l2" ) ;
0 commit comments