11use destiny_pkg:: { manager:: PackagePath , TagHash } ;
22use eframe:: egui:: { self , pos2, vec2, Color32 , RichText , Stroke , Widget } ;
3+ use rayon:: iter:: { ParallelBridge , ParallelIterator } ;
4+ use std:: fmt:: { Display , Formatter } ;
35
6+ use crate :: gui:: texture:: { Texture , TextureDesc } ;
47use crate :: { packages:: package_manager, tagtypes:: TagType } ;
58
69use super :: { common:: ResponseExt , texture:: TextureCache , View , ViewAction } ;
@@ -10,10 +13,12 @@ pub struct TexturesView {
1013 packages_with_textures : Vec < u16 > ,
1114 package_filter : String ,
1215 texture_cache : TextureCache ,
13- textures : Vec < ( usize , TagHash , TagType ) > ,
16+ textures : Vec < ( usize , TagHash , TagType , Option < TextureDesc > ) > ,
1417
1518 keep_aspect_ratio : bool ,
1619 zoom : f32 ,
20+ sorting : Sorting ,
21+ filter_texdesc : String ,
1722}
1823
1924impl TexturesView {
@@ -26,6 +31,8 @@ impl TexturesView {
2631 textures : vec ! [ ] ,
2732 keep_aspect_ratio : true ,
2833 zoom : 1.0 ,
34+ sorting : Sorting :: IndexAsc ,
35+ filter_texdesc : String :: new ( ) ,
2936 }
3037 }
3138
@@ -60,6 +67,23 @@ impl TexturesView {
6067
6168 packages. into_iter ( ) . map ( |( id, _path) | id) . collect ( )
6269 }
70+
71+ fn apply_sorting ( & mut self ) {
72+ match self . sorting {
73+ Sorting :: IndexAsc | Sorting :: IndexDesc => {
74+ self . textures . sort_by_cached_key ( |( i, _, _, _) | * i) ;
75+ }
76+ Sorting :: SizeAsc | Sorting :: SizeDesc => {
77+ self . textures . sort_by_cached_key ( |( _, _, _, desc) | {
78+ desc. as_ref ( ) . map ( |d| d. width * d. height ) . unwrap_or ( 0 )
79+ } ) ;
80+ }
81+ }
82+
83+ if self . sorting . is_descending ( ) {
84+ self . textures . reverse ( ) ;
85+ }
86+ }
6387}
6488
6589impl View for TexturesView {
@@ -89,6 +113,7 @@ impl View for TexturesView {
89113 egui:: ScrollArea :: vertical ( )
90114 . max_width ( f32:: INFINITY )
91115 . show ( ui, |ui| {
116+ let mut update_filters = false ;
92117 for id in & self . packages_with_textures {
93118 let path = & package_manager ( ) . package_paths [ id] ;
94119 let package_name = format ! ( "{}_{}" , path. name, path. id) ;
@@ -107,15 +132,65 @@ impl View for TexturesView {
107132 . filter_map ( |( i, e) | {
108133 let st =
109134 TagType :: from_type_subtype ( e. file_type , e. file_subtype ) ;
135+
136+ let hash = TagHash :: new ( * id, i as u16 ) ;
110137 if st. is_texture ( ) && st. is_header ( ) {
111- Some ( ( i, TagHash :: new ( * id , i as u16 ) , st ) )
138+ Some ( ( i, hash , st , Texture :: load_desc ( hash ) . ok ( ) ) )
112139 } else {
113140 None
114141 }
115142 } )
116143 . collect ( ) ;
144+
145+ update_filters = true ;
117146 }
118147 }
148+
149+ // cohae: Activate at your own risk. May cause death
150+ // if ui
151+ // .selectable_value(
152+ // &mut self.selected_package,
153+ // 0xffff - 1,
154+ // "All Uncompressed".to_string(),
155+ // )
156+ // .changed()
157+ // {
158+ // self.textures = package_manager()
159+ // .package_entry_index
160+ // .iter()
161+ // .par_bridge()
162+ // .flat_map(|(pkg_id, entries)| {
163+ // let mut tex_entries = vec![];
164+ // for (i, e) in entries.iter().enumerate() {
165+ // let hash = TagHash::new(*pkg_id, i as u16);
166+ // let st =
167+ // TagType::from_type_subtype(e.file_type, e.file_subtype);
168+ // if st.is_texture() && st.is_header() {
169+ // let Ok(desc) = Texture::load_desc(hash) else {
170+ // continue;
171+ // };
172+ //
173+ // if !desc.format.is_compressed() {
174+ // tex_entries.push((
175+ // (*pkg_id as usize) * 8192 + i,
176+ // hash,
177+ // st,
178+ // Some(desc),
179+ // ));
180+ // }
181+ // }
182+ // }
183+ //
184+ // tex_entries
185+ // })
186+ // .collect();
187+ //
188+ // update_filters = true;
189+ // }
190+
191+ if update_filters {
192+ self . apply_sorting ( ) ;
193+ }
119194 } ) ;
120195 } ) ;
121196
@@ -127,7 +202,36 @@ impl View for TexturesView {
127202 . ui ( ui) ;
128203
129204 ui. checkbox ( & mut self . keep_aspect_ratio , "Keep aspect ratio" ) ;
205+
206+ if egui:: ComboBox :: from_label ( "Sort by" )
207+ . selected_text ( & self . sorting . to_string ( ) )
208+ . show_ui ( ui, |ui| {
209+ let mut changed = ui
210+ . selectable_value ( & mut self . sorting , Sorting :: IndexAsc , "Index ⬆" )
211+ . changed ( ) ;
212+ changed |= ui
213+ . selectable_value ( & mut self . sorting , Sorting :: IndexDesc , "Index ⬇" )
214+ . changed ( ) ;
215+ changed |= ui
216+ . selectable_value ( & mut self . sorting , Sorting :: SizeAsc , "Size ⬆" )
217+ . changed ( ) ;
218+ changed |= ui
219+ . selectable_value ( & mut self . sorting , Sorting :: SizeDesc , "Size ⬇" )
220+ . changed ( ) ;
221+ changed
222+ } )
223+ . inner
224+ . unwrap_or ( false )
225+ {
226+ self . apply_sorting ( ) ;
227+ }
228+ } ) ;
229+
230+ ui. horizontal ( |ui| {
231+ ui. label ( "Texture desc filter: " ) ;
232+ ui. text_edit_singleline ( & mut self . filter_texdesc ) . changed ( ) ;
130233 } ) ;
234+
131235 ui. separator ( ) ;
132236 egui:: ScrollArea :: vertical ( )
133237 . auto_shrink ( [ false , false ] )
@@ -145,7 +249,16 @@ impl View for TexturesView {
145249 s. interaction . tooltip_delay = 0.0 ;
146250 } ) ;
147251
148- for ( _i, hash, _tag_type) in & self . textures {
252+ let filter = self . filter_texdesc . to_lowercase ( ) ;
253+ for ( _i, hash, _tag_type, desc) in & self . textures {
254+ if let Some ( desc) = desc {
255+ if !filter. is_empty ( )
256+ && !desc. info ( ) . to_lowercase ( ) . contains ( & filter)
257+ {
258+ continue ;
259+ }
260+ }
261+
149262 let img_container = ui. allocate_response (
150263 vec2 ( 128.0 * self . zoom , 128.0 * self . zoom ) ,
151264 egui:: Sense :: click ( ) ,
@@ -205,6 +318,7 @@ impl View for TexturesView {
205318 & self . texture_cache ,
206319 true ,
207320 )
321+ . on_hover_text ( RichText :: new ( format ! ( "{hash}" ) ) . strong ( ) )
208322 . clicked ( )
209323 {
210324 action = Some ( ViewAction :: OpenTag ( * hash) ) ;
@@ -219,3 +333,30 @@ impl View for TexturesView {
219333 action
220334 }
221335}
336+
337+ #[ derive( Default , PartialEq ) ]
338+ pub enum Sorting {
339+ #[ default]
340+ IndexAsc ,
341+ IndexDesc ,
342+
343+ SizeAsc ,
344+ SizeDesc ,
345+ }
346+
347+ impl Sorting {
348+ pub fn is_descending ( & self ) -> bool {
349+ matches ! ( self , Sorting :: IndexDesc | Sorting :: SizeDesc )
350+ }
351+ }
352+
353+ impl Display for Sorting {
354+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
355+ match self {
356+ Sorting :: IndexAsc => f. write_str ( "Index ⬆" ) ,
357+ Sorting :: IndexDesc => f. write_str ( "Index ⬇" ) ,
358+ Sorting :: SizeAsc => f. write_str ( "Size ⬆" ) ,
359+ Sorting :: SizeDesc => f. write_str ( "Size ⬇" ) ,
360+ }
361+ }
362+ }
0 commit comments