@@ -38,6 +38,17 @@ namespace Orts.Viewer3D
3838 [ CallOnThread ( "Loader" ) ]
3939 public class SharedTextureManager
4040 {
41+ const int MaxSelectorDirectoryNames = 5 ;
42+ readonly HashSet < string > SelectorDirectoryNames = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) {
43+ "Autumn" ,
44+ "AutumnSnow" ,
45+ "Snow" ,
46+ "Spring" ,
47+ "SpringSnow" ,
48+ "Winter" ,
49+ "WinterSnow" ,
50+ } ;
51+
4152 readonly Viewer Viewer ;
4253 readonly GraphicsDevice GraphicsDevice ;
4354 Dictionary < string , Texture2D > Textures = new Dictionary < string , Texture2D > ( ) ;
@@ -52,123 +63,59 @@ internal SharedTextureManager(Viewer viewer, GraphicsDevice graphicsDevice)
5263
5364 public Texture2D Get ( string path , bool required = false )
5465 {
55- return ( Get ( path , SharedMaterialManager . MissingTexture , required ) ) ;
66+ return Get ( path , SharedMaterialManager . MissingTexture , required ) ;
5667 }
5768
5869 public Texture2D Get ( string path , Texture2D defaultTexture , bool required = false )
5970 {
6071 if ( Thread . CurrentThread . Name != "Loader Process" )
6172 Trace . TraceError ( "SharedTextureManager.Get incorrectly called by {0}; must be Loader Process or crashes will occur." , Thread . CurrentThread . Name ) ;
6273
63- if ( path == null || path == "" )
64- return defaultTexture ;
74+ if ( string . IsNullOrEmpty ( path ) ) return defaultTexture ;
6575
6676 path = path . ToLowerInvariant ( ) ;
67- if ( ! Textures . ContainsKey ( path ) )
77+ if ( Textures . ContainsKey ( path ) ) return Textures [ path ] ;
78+
79+ // DO NOT add additional formats here without explicit approval
80+ // - DDS is used for newer, Open Rails-specific content
81+ // - ACE is used for older, MSTS-specific content
82+ switch ( Path . GetExtension ( path ) )
6883 {
69- try
70- {
71- Texture2D texture ;
72- if ( Path . GetExtension ( path ) == ".dds" )
84+ case ".dds" :
85+ case ".ace" :
86+ try
7387 {
74- if ( File . Exists ( path ) )
75- {
76- DDSLib . DDSFromFile ( path , GraphicsDevice , true , out texture ) ;
77- }
78- else
79- // This solves the case where the global shapes have been overwritten and point to .dds textures
80- // therefore avoiding that routes providing .ace textures show blank global shapes
88+ var levelPath = path ;
89+ for ( var levels = 0 ; levels < MaxSelectorDirectoryNames ; levels ++ )
8190 {
82- var aceTexture = Path . ChangeExtension ( path , ".ace" ) ;
83- if ( File . Exists ( aceTexture ) )
84- {
85- texture = Orts . Formats . Msts . AceFile . Texture2DFromFile ( GraphicsDevice , aceTexture ) ;
86- Trace . TraceWarning ( "Required texture {0} not existing; using existing texture {1}" , path , aceTexture ) ;
87- }
88- else return defaultTexture ;
89- }
90- }
91- else if ( Path . GetExtension ( path ) == ".ace" )
92- {
93- var alternativeTexture = Path . ChangeExtension ( path , ".dds" ) ;
94-
95- if ( File . Exists ( alternativeTexture ) )
96- {
97- DDSLib . DDSFromFile ( alternativeTexture , GraphicsDevice , true , out texture ) ;
98- }
99- else if ( File . Exists ( path ) )
100- {
101- texture = Orts . Formats . Msts . AceFile . Texture2DFromFile ( GraphicsDevice , path ) ;
102- }
103- else
104- {
105- Texture2D missing ( )
106- {
107- if ( required )
108- Trace . TraceWarning ( "Missing texture {0} replaced with default texture" , path ) ;
109- return defaultTexture ;
110- }
111- Texture2D invalid ( )
91+ var dds = Path . ChangeExtension ( levelPath , ".dds" ) ;
92+ var ace = Path . ChangeExtension ( levelPath , ".ace" ) ;
93+ if ( File . Exists ( dds ) )
11294 {
113- if ( required )
114- Trace . TraceWarning ( "Invalid texture {0} replaced with default texture" , path ) ;
115- return defaultTexture ;
95+ DDSLib . DDSFromFile ( dds , GraphicsDevice , true , out Texture2D texture ) ;
96+ return Textures [ path ] = texture ;
11697 }
117- //in case of no texture in wintersnow etc, go up one level
118- DirectoryInfo currentDir ;
119- string searchPath ;
120- try
98+ if ( File . Exists ( ace ) )
12199 {
122- currentDir = Directory . GetParent ( path ) ; //returns the current level of dir
123- searchPath = $ "{ Directory . GetParent ( currentDir . FullName ) . FullName } \\ { Path . GetFileName ( path ) } ";
124- }
125- catch
126- {
127- return missing ( ) ;
128- }
129- if ( File . Exists ( searchPath ) && searchPath . ToLower ( ) . Contains ( "texture" ) ) //in texture and exists
130- {
131- try
132- {
133- texture = Formats . Msts . AceFile . Texture2DFromFile ( GraphicsDevice , searchPath ) ;
134- }
135- catch
136- {
137- return invalid ( ) ;
138- }
139- }
140- else
141- {
142- return missing ( ) ;
100+ return Textures [ path ] = Formats . Msts . AceFile . Texture2DFromFile ( GraphicsDevice , ace ) ;
143101 }
102+ // When a texture is not found, and it is in a selector directory (e.g. "Snow"), we
103+ // go up a level and try again. This repeats a fixed number of times, or until we run
104+ // out of known selector directories.
105+ var directory = Path . GetDirectoryName ( levelPath ) ;
106+ if ( string . IsNullOrEmpty ( directory ) || ! SelectorDirectoryNames . Contains ( Path . GetFileName ( directory ) ) ) break ;
107+ levelPath = Path . Combine ( Path . GetDirectoryName ( directory ) , Path . GetFileName ( levelPath ) ) ;
144108 }
109+ if ( required ) Trace . TraceWarning ( "Ignored missing texture file: {0}" , path ) ;
145110 }
146- else
111+ catch ( Exception error )
147112 {
148- Trace . TraceWarning ( "Unsupported texture format: {0}" , path ) ;
149- return defaultTexture ;
113+ Trace . WriteLine ( new FileLoadException ( path , error ) ) ;
150114 }
151-
152- Textures . Add ( path , texture ) ;
153- return texture ;
154- }
155- catch ( InvalidDataException error )
156- {
157- Trace . TraceWarning ( "Skipped texture with error: {1} in {0}" , path , error . Message ) ;
158115 return defaultTexture ;
159- }
160- catch ( Exception error )
161- {
162- if ( File . Exists ( path ) )
163- Trace . WriteLine ( new FileLoadException ( path , error ) ) ;
164- else
165- Trace . TraceWarning ( "Ignored missing texture file {0}" , path ) ;
116+ default :
117+ Trace . TraceWarning ( "Ignored unsupported texture file: {0}" , path ) ;
166118 return defaultTexture ;
167- }
168- }
169- else
170- {
171- return Textures [ path ] ;
172119 }
173120 }
174121
0 commit comments