@@ -4,15 +4,16 @@ use std::cell::RefCell;
44use std:: collections:: BTreeMap ;
55use std:: rc:: Rc ;
66
7- use crate :: sbc:: panels:: brush:: { non_empty, BrushAction , BrushActions , ASSETS } ;
8- use crate :: sbc:: panels:: controls:: grid:: { list_assets , GridView } ;
7+ use crate :: sbc:: panels:: brush:: { non_empty, BrushAction , BrushActions } ;
8+ use crate :: sbc:: panels:: controls:: grid:: GridView ;
99use crate :: sbc:: panels:: field:: FieldValue ;
1010use crate :: sbc:: panels:: fields:: { BooleanField , ChoiceField , ColorField , NumericField } ;
1111use crate :: sbc:: panels:: runtime:: {
1212 AssetGrid , AssetGridDef , Brush , EditorModel , FieldMut , FieldRef , TableEntry , TableModel ,
1313} ;
1414use crate :: sbc:: rml:: escape_rml;
1515use crate :: sbc:: states:: { BrushKind , BrushSettings } ;
16+ use crate :: sbc:: textures:: materials:: { Material , CHANNELS } ;
1617
1718/// Blend modes, in the order `texture_editor.lua` lists them.
1819const MODES : & [ & str ] = & [
@@ -74,21 +75,6 @@ pub(super) const ACTIONS: &[BrushAction] = &[
7475 } ,
7576] ;
7677
77- /// A material's channels, as `TextureManager.materialTextures` defines them: one
78- /// texture per channel, found by suffix next to the diffuse.
79- ///
80- /// `normal` is a channel of every material but has no enable toggle, exactly as
81- /// Lua skips it when it builds the checkboxes.
82- const CHANNELS : & [ ( & str , & str , bool ) ] = & [
83- ( "diffuse" , "Diffuse" , true ) ,
84- ( "specular" , "Specular" , true ) ,
85- ( "normal" , "Normal" , false ) ,
86- ( "emission" , "Emission" , true ) ,
87- ( "refl" , "Refl" , true ) ,
88- ] ;
89-
90- const IMAGE_EXTS : & [ & str ] = & [ ".png" , ".jpg" , ".tga" , ".dds" , ".bmp" ] ;
91-
9278/// The engine exposes at most four DNTS (splat normal) channels.
9379pub ( super ) const DNTS_COUNT : i32 = 4 ;
9480
@@ -99,14 +85,6 @@ pub(super) fn toggle_channels() -> impl Iterator<Item = &'static str> {
9985 . map ( |( channel, _, _) | * channel)
10086}
10187
102- /// One material: its name, and the channel textures that exist for it.
103- #[ derive( Clone ) ]
104- pub ( super ) struct Material {
105- /// The bare material name (`dirt1`), which is what the picker shows.
106- pub ( super ) name : String ,
107- pub ( super ) channels : BTreeMap < String , String > ,
108- }
109-
11088pub ( super ) struct SavedBrush {
11189 pub ( super ) id : String ,
11290 pub ( super ) material : String ,
@@ -115,46 +93,6 @@ pub(super) struct SavedBrush {
11593
11694pub ( super ) const ADD_BRUSH_ID : & str = "__add_saved_brush__" ;
11795
118- /// The material a texture belongs to: its file name with the channel suffix
119- /// stripped, and without the directory. `.../brush_textures/dirt1_diffuse.png`
120- /// is the `diffuse` of `dirt1`.
121- fn material_of ( path : & str ) -> Option < ( String , & ' static str ) > {
122- let file = path. rsplit ( '/' ) . next ( ) ?;
123- let stem = file. rsplit_once ( '.' ) . map ( |( s, _) | s) . unwrap_or ( file) ;
124- for ( channel, _, _) in CHANNELS {
125- if let Some ( base) = stem. strip_suffix ( & format ! ( "_{channel}" ) ) {
126- return Some ( ( base. to_string ( ) , channel) ) ;
127- }
128- }
129- None
130- }
131-
132- /// Group the files under `brush_textures/` into materials. A material exists if
133- /// it has a diffuse; the other channels are optional, which is why the picker
134- /// shows which ones were found.
135- pub ( super ) fn list_materials ( interface : & NativeInterfaceRef ) -> Vec < Material > {
136- let root = format ! ( "{ASSETS}/brush_textures" ) ;
137- let mut found: BTreeMap < String , BTreeMap < String , String > > = BTreeMap :: new ( ) ;
138-
139- for item in list_assets ( interface, & root, IMAGE_EXTS ) {
140- if item. is_directory {
141- continue ;
142- }
143- if let Some ( ( name, channel) ) = material_of ( & item. id ) {
144- found
145- . entry ( name)
146- . or_default ( )
147- . insert ( channel. to_string ( ) , item. id . clone ( ) ) ;
148- }
149- }
150-
151- found
152- . into_iter ( )
153- . filter ( |( _, channels) | channels. contains_key ( "diffuse" ) )
154- . map ( |( name, channels) | Material { name, channels } )
155- . collect ( )
156- }
157-
15896pub ( super ) fn material_tooltip ( material : & Material ) -> String {
15997 let channel = |name : & str , title : & str | {
16098 let ( color, mark) = if material. channels . contains_key ( name) {
@@ -677,26 +615,6 @@ pub(super) fn enabled_name(channel: &str) -> String {
677615mod tests {
678616 use super :: * ;
679617
680- /// The VFS hands back full paths, so the material's name is the file's, not
681- /// the path's -- every material was captioned "springboard" until it was.
682- #[ test]
683- fn a_material_is_named_after_its_file_not_its_path ( ) {
684- let ( name, channel) =
685- material_of ( "springboard/assets/core/brush_textures/dirt1_diffuse.png" ) . unwrap ( ) ;
686- assert_eq ! ( name, "dirt1" ) ;
687- assert_eq ! ( channel, "diffuse" ) ;
688-
689- let ( name, channel) =
690- material_of ( "springboard/assets/core/brush_textures/cement_normal.png" ) . unwrap ( ) ;
691- assert_eq ! ( name, "cement" ) ;
692- assert_eq ! ( channel, "normal" ) ;
693- }
694-
695- #[ test]
696- fn a_texture_with_no_channel_suffix_belongs_to_no_material ( ) {
697- assert ! ( material_of( "brush_textures/readme.png" ) . is_none( ) ) ;
698- }
699-
700618 #[ test]
701619 fn normal_is_a_channel_but_has_no_toggle ( ) {
702620 let toggles: Vec < & str > = toggle_channels ( ) . collect ( ) ;
0 commit comments