1 using System; 2 using System.Collections.Generic; 3 using System.Drawing; 4 using System.IO; 5 using OpenBveApi; 6 using OpenBveApi.Hosts; 7 using OpenBveApi.Interface; 8 using OpenBveApi.Math; 9 using OpenBveApi.Objects; 10 using OpenBveApi.Routes; 11 using OpenBveApi.Textures; 12 using OpenBveApi.Trains; 13 using OpenBveApi.World; 14 using TrainManager; 15 using TrainManager.Trains; 16 17 namespace ObjectViewer { 18 /// <summary>Represents the host application.</summary> 19 internal class Host : HostInterface { 20 21 // --- functions --- 22 23 /// <summary>Reports a problem to the host application.</summary> 24 /// <param name="type">The type of problem that is reported.</param> 25 /// <param name="text">The textual message that describes the problem.</param> ReportProblem(ProblemType type, string text)26 public override void ReportProblem(ProblemType type, string text) { 27 switch (type) 28 { 29 case ProblemType.DirectoryNotFound: 30 case ProblemType.FileNotFound: 31 case ProblemType.PathNotFound: 32 if (!MissingFiles.Contains(text)) 33 { 34 Interface.AddMessage(MessageType.Error, true, type + " : " + text); 35 } 36 break; 37 default: 38 Interface.AddMessage(MessageType.Error, false, type + " : " + text); 39 break; 40 } 41 } 42 AddMessage(MessageType type, bool FileNotFound, string text)43 public override void AddMessage(MessageType type, bool FileNotFound, string text) 44 { 45 Interface.AddMessage(type, FileNotFound, text); 46 } 47 48 // --- texture --- 49 50 /// <summary>Queries the dimensions of a texture.</summary> 51 /// <param name="path">The path to the file or folder that contains the texture.</param> 52 /// <param name="width">Receives the width of the texture.</param> 53 /// <param name="height">Receives the height of the texture.</param> 54 /// <returns>Whether querying the dimensions was successful.</returns> QueryTextureDimensions(string path, out int width, out int height)55 public override bool QueryTextureDimensions(string path, out int width, out int height) { 56 if (File.Exists(path) || Directory.Exists(path)) { 57 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { 58 if (Program.CurrentHost.Plugins[i].Texture != null) { 59 try { 60 if (Program.CurrentHost.Plugins[i].Texture.CanLoadTexture(path)) { 61 try { 62 if (Program.CurrentHost.Plugins[i].Texture.QueryTextureDimensions(path, out width, out height)) { 63 return true; 64 } 65 Interface.AddMessage(MessageType.Error, false, 66 "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at QueryTextureDimensions" 67 ); 68 } catch (Exception ex) { 69 Interface.AddMessage(MessageType.Error, false, 70 "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at QueryTextureDimensions:" + ex.Message 71 ); 72 } 73 } 74 } catch (Exception ex) { 75 Interface.AddMessage(MessageType.Error, false, 76 "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadTexture:" + ex.Message 77 ); 78 } 79 } 80 } 81 FileInfo f = new FileInfo(path); 82 if (f.Length == 0) 83 { 84 Interface.AddMessage(MessageType.Error, false, "Zero-byte texture file encountered at " + path); 85 } 86 else 87 { 88 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading texture " + path); 89 } 90 91 } else { 92 ReportProblem(ProblemType.PathNotFound, path); 93 } 94 width = 0; 95 height = 0; 96 return false; 97 } 98 99 /// <summary>Loads a texture and returns the texture data.</summary> 100 /// <param name="path">The path to the file or folder that contains the texture.</param> 101 /// <param name="parameters">The parameters that specify how to process the texture.</param> 102 /// <param name="texture">Receives the texture.</param> 103 /// <returns>Whether loading the texture was successful.</returns> LoadTexture(string path, TextureParameters parameters, out Texture texture)104 public override bool LoadTexture(string path, TextureParameters parameters, out Texture texture) { 105 if (File.Exists(path) || Directory.Exists(path)) { 106 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { 107 if (Program.CurrentHost.Plugins[i].Texture != null) { 108 try { 109 if (Program.CurrentHost.Plugins[i].Texture.CanLoadTexture(path)) { 110 try { 111 if (Program.CurrentHost.Plugins[i].Texture.LoadTexture(path, out texture)) { 112 texture.CompatibleTransparencyMode = false; 113 texture = texture.ApplyParameters(parameters); 114 return true; 115 } 116 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadTexture"); 117 } catch (Exception ex) { 118 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadTexture:" + ex.Message); 119 } 120 } 121 } catch (Exception ex) { 122 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadTexture:" + ex.Message); 123 } 124 } 125 } 126 FileInfo f = new FileInfo(path); 127 if (f.Length == 0) 128 { 129 Interface.AddMessage(MessageType.Error, false, "Zero-byte texture file encountered at " + path); 130 } 131 else 132 { 133 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading texture " + path); 134 } 135 } else { 136 ReportProblem(ProblemType.PathNotFound, path); 137 } 138 texture = null; 139 return false; 140 } 141 LoadTexture(ref Texture Texture, OpenGlTextureWrapMode wrapMode)142 public override bool LoadTexture(ref Texture Texture, OpenGlTextureWrapMode wrapMode) 143 { 144 return Program.Renderer.TextureManager.LoadTexture(ref Texture, wrapMode, CPreciseTimer.GetClockTicks(), Interface.CurrentOptions.Interpolation, Interface.CurrentOptions.AnisotropicFilteringLevel); 145 } 146 RegisterTexture(string path, TextureParameters parameters, out Texture handle, bool loadTexture = false)147 public override bool RegisterTexture(string path, TextureParameters parameters, out Texture handle, bool loadTexture = false) { 148 if (File.Exists(path) || Directory.Exists(path)) { 149 Texture data; 150 if (Program.Renderer.TextureManager.RegisterTexture(path, parameters, out data)) { 151 handle = data; 152 if (loadTexture) 153 { 154 LoadTexture(ref data, OpenGlTextureWrapMode.ClampClamp); 155 } 156 return true; 157 } 158 } else { 159 ReportProblem(ProblemType.PathNotFound, path); 160 } 161 handle = null; 162 return false; 163 } 164 RegisterTexture(Bitmap texture, TextureParameters parameters, out Texture handle)165 public override bool RegisterTexture(Bitmap texture, TextureParameters parameters, out Texture handle) 166 { 167 handle = new Texture(texture, parameters); 168 return true; 169 } 170 171 /// <summary>Registers a texture and returns a handle to the texture.</summary> 172 /// <param name="texture">The texture data.</param> 173 /// <param name="parameters">The parameters that specify how to process the texture.</param> 174 /// <param name="handle">Receives the handle to the texture.</param> 175 /// <returns>Whether loading the texture was successful.</returns> RegisterTexture(Texture texture, TextureParameters parameters, out Texture handle)176 public override bool RegisterTexture(Texture texture, TextureParameters parameters, out Texture handle) { 177 texture = texture.ApplyParameters(parameters); 178 handle = Program.Renderer.TextureManager.RegisterTexture(texture); 179 return true; 180 } 181 182 183 // --- sound --- 184 185 /// <summary>Loads a sound and returns the sound data.</summary> 186 /// <param name="path">The path to the file or folder that contains the sound.</param> 187 /// <param name="sound">Receives the sound.</param> 188 /// <returns>Whether loading the sound was successful.</returns> LoadSound(string path, out OpenBveApi.Sounds.Sound sound)189 public override bool LoadSound(string path, out OpenBveApi.Sounds.Sound sound) { 190 if (File.Exists(path) || Directory.Exists(path)) { 191 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { 192 if (Program.CurrentHost.Plugins[i].Sound != null) { 193 try { 194 if (Program.CurrentHost.Plugins[i].Sound.CanLoadSound(path)) { 195 try { 196 if (Program.CurrentHost.Plugins[i].Sound.LoadSound(path, out sound)) { 197 return true; 198 } 199 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadSound"); 200 } catch (Exception ex) { 201 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadSound:" + ex.Message); 202 } 203 } 204 } catch (Exception ex) { 205 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadSound:" + ex.Message); 206 } 207 } 208 } 209 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading sound " + path); 210 } else { 211 ReportProblem(ProblemType.PathNotFound, path); 212 } 213 sound = null; 214 return false; 215 } 216 217 /// <summary>Registers a sound and returns a handle to the sound.</summary> 218 /// <param name="path">The path to the file or folder that contains the sound.</param> 219 /// <param name="handle">Receives a handle to the sound.</param> 220 /// <returns>Whether loading the sound was successful.</returns> RegisterSound(string path, out OpenBveApi.Sounds.SoundHandle handle)221 public override bool RegisterSound(string path, out OpenBveApi.Sounds.SoundHandle handle) { 222 if (File.Exists(path) || Directory.Exists(path)) { 223 // Sounds.SoundBuffer data; 224 // data = Sounds.RegisterBuffer(path, 0.0); // TODO 225 } else { 226 ReportProblem(ProblemType.PathNotFound, path); 227 } 228 handle = null; 229 return false; 230 } 231 232 /// <summary>Registers a sound and returns a handle to the sound.</summary> 233 /// <param name="sound">The sound data.</param> 234 /// <param name="handle">Receives a handle to the sound.</param> 235 /// <returns>Whether loading the sound was successful.</returns> RegisterSound(OpenBveApi.Sounds.Sound sound, out OpenBveApi.Sounds.SoundHandle handle)236 public override bool RegisterSound(OpenBveApi.Sounds.Sound sound, out OpenBveApi.Sounds.SoundHandle handle) { 237 //handle = Sounds.RegisterBuffer(sound, 0.0); // TODO 238 handle = null; 239 return true; 240 } 241 LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject Object)242 public override bool LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject Object) 243 { 244 if (base.LoadObject(path, Encoding, out Object)) 245 { 246 return true; 247 } 248 249 if (File.Exists(path) || Directory.Exists(path)) { 250 Encoding = TextEncoding.GetSystemEncodingFromFile(path, Encoding); 251 252 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { 253 if (Program.CurrentHost.Plugins[i].Object != null) { 254 try { 255 if (Program.CurrentHost.Plugins[i].Object.CanLoadObject(path)) { 256 try 257 { 258 UnifiedObject obj; 259 if (Program.CurrentHost.Plugins[i].Object.LoadObject(path, Encoding, out obj)) { 260 obj.OptimizeObject(false, Interface.CurrentOptions.ObjectOptimizationBasicThreshold, true); 261 Object = obj; 262 263 StaticObject staticObject = Object as StaticObject; 264 if (staticObject != null) 265 { 266 StaticObjectCache.Add(ValueTuple.Create(path, false), staticObject); 267 return true; 268 } 269 270 AnimatedObjectCollection aoc = Object as AnimatedObjectCollection; 271 if (aoc != null) 272 { 273 AnimatedObjectCollectionCache.Add(path, aoc); 274 } 275 276 return true; 277 } 278 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadObject"); 279 } catch (Exception ex) { 280 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadObject:" + ex.Message); 281 } 282 } 283 } catch (Exception ex) { 284 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadObject:" + ex.Message); 285 } 286 } 287 } 288 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading object " + path); 289 } else { 290 ReportProblem(ProblemType.PathNotFound, path); 291 } 292 Object = null; 293 return false; 294 } 295 ExecuteFunctionScript(OpenBveApi.FunctionScripting.FunctionScript functionScript, AbstractTrain train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState)296 public override void ExecuteFunctionScript(OpenBveApi.FunctionScripting.FunctionScript functionScript, AbstractTrain train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState) 297 { 298 FunctionScripts.ExecuteFunctionScript(functionScript, (TrainBase)train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); 299 } 300 CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness)301 public override int CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness) 302 { 303 return Program.Renderer.CreateStaticObject(Prototype, Position, WorldTransformation, LocalTransformation, ObjectDisposalMode.Accurate, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, 25.0, TrackPosition, Brightness); 304 } 305 CreateStaticObject(StaticObject Prototype, Transformation LocalTransformation, Matrix4D Rotate, Matrix4D Translate, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness)306 public override int CreateStaticObject(StaticObject Prototype, Transformation LocalTransformation, Matrix4D Rotate, Matrix4D Translate, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness) 307 { 308 return Program.Renderer.CreateStaticObject(Prototype, LocalTransformation, Rotate, Translate, ObjectDisposalMode.Accurate, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, 25.0, TrackPosition, Brightness); 309 } 310 CreateDynamicObject(ref ObjectState internalObject)311 public override void CreateDynamicObject(ref ObjectState internalObject) 312 { 313 Program.Renderer.CreateDynamicObject(ref internalObject); 314 } 315 ShowObject(ObjectState objectToShow, ObjectType objectType)316 public override void ShowObject(ObjectState objectToShow, ObjectType objectType) 317 { 318 Program.Renderer.VisibleObjects.ShowObject(objectToShow, objectType); 319 } 320 HideObject(ObjectState objectToHide)321 public override void HideObject(ObjectState objectToHide) 322 { 323 Program.Renderer.VisibleObjects.HideObject(objectToHide); 324 } 325 326 public override int AnimatedWorldObjectsUsed 327 { 328 get 329 { 330 return ObjectManager.AnimatedWorldObjectsUsed; 331 } 332 set 333 { 334 int a = ObjectManager.AnimatedWorldObjectsUsed; 335 if (ObjectManager.AnimatedWorldObjects.Length -1 == a) 336 { 337 /* 338 * HACK: We cannot resize an array via an accessor property 339 * With this in mind, resize it via the indexer instead 340 */ 341 Array.Resize(ref ObjectManager.AnimatedWorldObjects, ObjectManager.AnimatedWorldObjects.Length << 1); 342 } 343 344 ObjectManager.AnimatedWorldObjectsUsed = value; 345 } 346 } 347 348 public override WorldObject[] AnimatedWorldObjects 349 { 350 get 351 { 352 return ObjectManager.AnimatedWorldObjects; 353 } 354 set 355 { 356 ObjectManager.AnimatedWorldObjects = value; 357 } 358 } 359 360 public override Dictionary<int, Track> Tracks 361 { 362 get 363 { 364 return Program.CurrentRoute.Tracks; 365 } 366 set 367 { 368 Program.CurrentRoute.Tracks = value; 369 } 370 } 371 ParseTrackFollowingObject(string objectPath, string tfoFile)372 public override AbstractTrain ParseTrackFollowingObject(string objectPath, string tfoFile) 373 { 374 throw new NotImplementedException(); 375 } 376 377 public override AbstractTrain[] Trains 378 { 379 get 380 { 381 // ReSharper disable once CoVariantArrayConversion 382 return Program.TrainManager.Trains; 383 } 384 } 385 ClosestTrain(AbstractTrain Train)386 public override AbstractTrain ClosestTrain(AbstractTrain Train) 387 { 388 /* 389 * At present, there should only ever be the single player train ref present in ObjectViewer 390 * This may change at some point, but for the minute it's fixed.... 391 */ 392 return TrainManagerBase.PlayerTrain; 393 } 394 ClosestTrain(double TrackPosition)395 public override AbstractTrain ClosestTrain(double TrackPosition) 396 { 397 return TrainManagerBase.PlayerTrain; 398 } 399 Host()400 public Host() : base(HostApplication.ObjectViewer) 401 { 402 } 403 } 404 } 405