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 RouteManager2.MessageManager; 15 using TrainManager.Trains; 16 17 namespace RouteViewer 18 { 19 /// <summary>Represents the host application.</summary> 20 internal class Host : OpenBveApi.Hosts.HostInterface 21 { 22 /// <summary>Reports a problem to the host application.</summary> 23 /// <param name="type">The type of problem that is reported.</param> 24 /// <param name="text">The textual message that describes the problem.</param> ReportProblem(ProblemType type, string text)25 public override void ReportProblem(ProblemType type, string text) { 26 switch (type) 27 { 28 case ProblemType.DirectoryNotFound: 29 case ProblemType.FileNotFound: 30 case ProblemType.PathNotFound: 31 if (!MissingFiles.Contains(text)) 32 { 33 Interface.AddMessage(MessageType.Error, true, type + " : " + text); 34 } 35 break; 36 default: 37 Interface.AddMessage(MessageType.Error, false, type + " : " + text); 38 break; 39 } 40 } 41 AddMessage(MessageType type, bool FileNotFound, string text)42 public override void AddMessage(MessageType type, bool FileNotFound, string text) 43 { 44 Interface.AddMessage(type, FileNotFound, text); 45 } 46 AddMessage(object Message)47 public override void AddMessage(object Message) 48 { 49 MessageManager.AddMessage((AbstractMessage)Message); 50 } 51 52 // --- texture --- 53 54 /// <summary>Queries the dimensions of a texture.</summary> 55 /// <param name="path">The path to the file or folder that contains the texture.</param> 56 /// <param name="width">Receives the width of the texture.</param> 57 /// <param name="height">Receives the height of the texture.</param> 58 /// <returns>Whether querying the dimensions was successful.</returns> QueryTextureDimensions(string path, out int width, out int height)59 public override bool QueryTextureDimensions(string path, out int width, out int height) 60 { 61 if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path)) 62 { 63 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) 64 { 65 if (Program.CurrentHost.Plugins[i].Texture != null) 66 { 67 try 68 { 69 if (Program.CurrentHost.Plugins[i].Texture.CanLoadTexture(path)) 70 { 71 try 72 { 73 if (Program.CurrentHost.Plugins[i].Texture.QueryTextureDimensions(path, out width, out height)) 74 { 75 return true; 76 } 77 Interface.AddMessage(MessageType.Error, false, 78 "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at QueryTextureDimensions" 79 ); 80 } 81 catch (Exception ex) 82 { 83 Interface.AddMessage(MessageType.Error, false, 84 "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at QueryTextureDimensions:" + ex.Message 85 ); 86 } 87 } 88 } 89 catch (Exception ex) 90 { 91 Interface.AddMessage(MessageType.Error, false, 92 "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadTexture:" + ex.Message 93 ); 94 } 95 } 96 } 97 FileInfo f = new FileInfo(path); 98 if (f.Length == 0) 99 { 100 Interface.AddMessage(MessageType.Error, false, "Zero-byte texture file encountered at " + path); 101 } 102 else 103 { 104 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading texture " + path); 105 } 106 } 107 else 108 { 109 ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path); 110 } 111 width = 0; 112 height = 0; 113 return false; 114 } 115 116 /// <summary>Loads a texture and returns the texture data.</summary> 117 /// <param name="path">The path to the file or folder that contains the texture.</param> 118 /// <param name="parameters">The parameters that specify how to process the texture.</param> 119 /// <param name="texture">Receives the texture.</param> 120 /// <returns>Whether loading the texture was successful.</returns> LoadTexture(string path, OpenBveApi.Textures.TextureParameters parameters, out OpenBveApi.Textures.Texture texture)121 public override bool LoadTexture(string path, OpenBveApi.Textures.TextureParameters parameters, out OpenBveApi.Textures.Texture texture) 122 { 123 if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path)) 124 { 125 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) 126 { 127 if (Program.CurrentHost.Plugins[i].Texture != null) 128 { 129 try 130 { 131 if (Program.CurrentHost.Plugins[i].Texture.CanLoadTexture(path)) 132 { 133 try 134 { 135 if (Program.CurrentHost.Plugins[i].Texture.LoadTexture(path, out texture)) 136 { 137 //texture.CompatibleTransparencyMode = Interface.CurrentOptions.OldTransparencyMode; 138 texture = texture.ApplyParameters(parameters); 139 return true; 140 } 141 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadTexture"); 142 } 143 catch (Exception ex) 144 { 145 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadTexture:" + ex.Message); 146 } 147 } 148 } 149 catch (Exception ex) 150 { 151 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadTexture:" + ex.Message); 152 } 153 } 154 } 155 FileInfo f = new FileInfo(path); 156 if (f.Length == 0) 157 { 158 Interface.AddMessage(MessageType.Error, false, "Zero-byte texture file encountered at " + path); 159 } 160 else 161 { 162 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading texture " + path); 163 } 164 } 165 else 166 { 167 ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path); 168 } 169 texture = null; 170 return false; 171 } 172 LoadTexture(ref Texture Texture, OpenGlTextureWrapMode wrapMode)173 public override bool LoadTexture(ref Texture Texture, OpenGlTextureWrapMode wrapMode) 174 { 175 return Program.Renderer.TextureManager.LoadTexture(ref Texture, wrapMode, CPreciseTimer.GetClockTicks(), Interface.CurrentOptions.Interpolation, Interface.CurrentOptions.AnisotropicFilteringLevel); 176 } 177 RegisterTexture(string path, TextureParameters parameters, out Texture handle, bool loadTexture = false)178 public override bool RegisterTexture(string path, TextureParameters parameters, out Texture handle, bool loadTexture = false) { 179 if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path)) { 180 Texture data; 181 if (Program.Renderer.TextureManager.RegisterTexture(path, parameters, out data)) { 182 handle = data; 183 if (loadTexture) 184 { 185 LoadTexture(ref data, OpenGlTextureWrapMode.ClampClamp); 186 } 187 return true; 188 } 189 } else { 190 ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path); 191 } 192 handle = null; 193 return false; 194 } 195 196 /// <summary>Registers a texture and returns a handle to the texture.</summary> 197 /// <param name="texture">The texture data.</param> 198 /// <param name="parameters">The parameters that specify how to process the texture.</param> 199 /// <param name="handle">Receives the handle to the texture.</param> 200 /// <returns>Whether loading the texture was successful.</returns> RegisterTexture(Texture texture, TextureParameters parameters, out Texture handle)201 public override bool RegisterTexture(Texture texture, TextureParameters parameters, out Texture handle) { 202 texture = texture.ApplyParameters(parameters); 203 handle = Program.Renderer.TextureManager.RegisterTexture(texture); 204 return true; 205 } 206 RegisterTexture(Bitmap texture, TextureParameters parameters, out OpenBveApi.Textures.Texture handle)207 public override bool RegisterTexture(Bitmap texture, TextureParameters parameters, out OpenBveApi.Textures.Texture handle) 208 { 209 handle = new Texture(texture, parameters); 210 return true; 211 } 212 213 // --- sound --- 214 215 /// <summary>Loads a sound and returns the sound data.</summary> 216 /// <param name="path">The path to the file or folder that contains the sound.</param> 217 /// <param name="sound">Receives the sound.</param> 218 /// <returns>Whether loading the sound was successful.</returns> LoadSound(string path, out OpenBveApi.Sounds.Sound sound)219 public override bool LoadSound(string path, out OpenBveApi.Sounds.Sound sound) 220 { 221 if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path)) 222 { 223 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) 224 { 225 if (Program.CurrentHost.Plugins[i].Sound != null) 226 { 227 try 228 { 229 if (Program.CurrentHost.Plugins[i].Sound.CanLoadSound(path)) 230 { 231 try 232 { 233 if (Program.CurrentHost.Plugins[i].Sound.LoadSound(path, out sound)) 234 { 235 return true; 236 } 237 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadSound"); 238 } 239 catch (Exception ex) 240 { 241 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadSound:" + ex.Message); 242 } 243 } 244 } 245 catch (Exception ex) 246 { 247 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadSound:" + ex.Message); 248 } 249 } 250 } 251 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading sound " + path); 252 } 253 else 254 { 255 ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path); 256 } 257 sound = null; 258 return false; 259 } 260 261 /// <summary>Registers a sound and returns a handle to the sound.</summary> 262 /// <param name="path">The path to the file or folder that contains the sound.</param> 263 /// <param name="handle">Receives a handle to the sound.</param> 264 /// <returns>Whether loading the sound was successful.</returns> RegisterSound(string path, out OpenBveApi.Sounds.SoundHandle handle)265 public override bool RegisterSound(string path, out OpenBveApi.Sounds.SoundHandle handle) 266 { 267 if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path)) 268 { 269 handle = Program.Sounds.RegisterBuffer(path, 0.0); 270 } 271 else 272 { 273 ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path); 274 } 275 handle = null; 276 return false; 277 } 278 279 /// <summary>Registers a sound and returns a handle to the sound.</summary> 280 /// <param name="path">The path to the file or folder that contains the sound.</param> 281 /// /// <param name="radius">The sound radius</param> 282 /// <param name="handle">Receives a handle to the sound.</param> 283 /// <returns>Whether loading the sound was successful.</returns> RegisterSound(string path, double radius, out OpenBveApi.Sounds.SoundHandle handle)284 public override bool RegisterSound(string path, double radius, out OpenBveApi.Sounds.SoundHandle handle) 285 { 286 if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path)) 287 { 288 handle = Program.Sounds.RegisterBuffer(path, radius); 289 return true; 290 } 291 ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path); 292 handle = null; 293 return false; 294 } 295 296 /// <summary>Registers a sound and returns a handle to the sound.</summary> 297 /// <param name="sound">The sound data.</param> 298 /// <param name="handle">Receives a handle to the sound.</param> 299 /// <returns>Whether loading the sound was successful.</returns> RegisterSound(OpenBveApi.Sounds.Sound sound, out OpenBveApi.Sounds.SoundHandle handle)300 public override bool RegisterSound(OpenBveApi.Sounds.Sound sound, out OpenBveApi.Sounds.SoundHandle handle) 301 { 302 handle = Program.Sounds.RegisterBuffer(sound, 0.0); 303 return true; 304 } 305 LoadStaticObject(string path, System.Text.Encoding Encoding, bool PreserveVertices, out StaticObject Object)306 public override bool LoadStaticObject(string path, System.Text.Encoding Encoding, bool PreserveVertices, out StaticObject Object) 307 { 308 Encoding = TextEncoding.GetSystemEncodingFromFile(path, Encoding); 309 if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path)) { 310 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { 311 if (Program.CurrentHost.Plugins[i].Object != null) { 312 try { 313 if (Program.CurrentHost.Plugins[i].Object.CanLoadObject(path)) { 314 try { 315 UnifiedObject unifiedObject; 316 if (Program.CurrentHost.Plugins[i].Object.LoadObject(path, Encoding, out unifiedObject)) { 317 if (unifiedObject is StaticObject) 318 { 319 unifiedObject.OptimizeObject(PreserveVertices, Interface.CurrentOptions.ObjectOptimizationBasicThreshold, true); 320 Object = (StaticObject) unifiedObject; 321 return true; 322 } 323 Object = null; 324 Interface.AddMessage(MessageType.Error, false, "Attempted to load " + path + " which is an animated object where only static objects are allowed."); 325 } 326 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadObject"); 327 } catch (Exception ex) { 328 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadObject:" + ex.Message); 329 } 330 } 331 } catch (Exception ex) { 332 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadObject:" + ex.Message); 333 } 334 } 335 } 336 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading object " + path); 337 } else { 338 ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path); 339 } 340 Object = null; 341 return false; 342 } 343 LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject Object)344 public override bool LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject Object) 345 { 346 if (base.LoadObject(path, Encoding, out Object)) 347 { 348 return true; 349 } 350 351 if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path)) { 352 Encoding = TextEncoding.GetSystemEncodingFromFile(path, Encoding); 353 354 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { 355 if (Program.CurrentHost.Plugins[i].Object != null) { 356 try { 357 if (Program.CurrentHost.Plugins[i].Object.CanLoadObject(path)) { 358 try 359 { 360 UnifiedObject obj; 361 if (Program.CurrentHost.Plugins[i].Object.LoadObject(path, Encoding, out obj)) { 362 obj.OptimizeObject(false, Interface.CurrentOptions.ObjectOptimizationBasicThreshold, true); 363 Object = obj; 364 365 StaticObject staticObject = Object as StaticObject; 366 if (staticObject != null) 367 { 368 StaticObjectCache.Add(ValueTuple.Create(path, false), staticObject); 369 return true; 370 } 371 372 AnimatedObjectCollection aoc = Object as AnimatedObjectCollection; 373 if (aoc != null) 374 { 375 AnimatedObjectCollectionCache.Add(path, aoc); 376 } 377 378 return true; 379 } 380 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadObject"); 381 } catch (Exception ex) { 382 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadObject:" + ex.Message); 383 } 384 } 385 } catch (Exception ex) { 386 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadObject:" + ex.Message); 387 } 388 } 389 } 390 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading object " + path); 391 } else { 392 ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path); 393 } 394 Object = null; 395 return false; 396 } 397 ExecuteFunctionScript(OpenBveApi.FunctionScripting.FunctionScript functionScript, AbstractTrain train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState)398 public override void ExecuteFunctionScript(OpenBveApi.FunctionScripting.FunctionScript functionScript, AbstractTrain train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState) 399 { 400 FunctionScripts.ExecuteFunctionScript(functionScript, (TrainManager.Train)train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); 401 } 402 CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness)403 public override int CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness) 404 { 405 return Program.Renderer.CreateStaticObject(Prototype, Position, WorldTransformation, LocalTransformation, Program.CurrentRoute.AccurateObjectDisposal, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, Program.CurrentRoute.BlockLength, TrackPosition, Brightness); 406 } 407 CreateStaticObject(StaticObject Prototype, Transformation LocalTransformation, Matrix4D Rotate, Matrix4D Translate, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness)408 public override int CreateStaticObject(StaticObject Prototype, Transformation LocalTransformation, Matrix4D Rotate, Matrix4D Translate, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness) 409 { 410 return Program.Renderer.CreateStaticObject(Prototype, LocalTransformation, Rotate, Translate, Program.CurrentRoute.AccurateObjectDisposal, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, Program.CurrentRoute.BlockLength, TrackPosition, Brightness); 411 } 412 CreateDynamicObject(ref ObjectState internalObject)413 public override void CreateDynamicObject(ref ObjectState internalObject) 414 { 415 Program.Renderer.CreateDynamicObject(ref internalObject); 416 } 417 ShowObject(ObjectState objectToShow, ObjectType objectType)418 public override void ShowObject(ObjectState objectToShow, ObjectType objectType) 419 { 420 Program.Renderer.VisibleObjects.ShowObject(objectToShow, objectType); 421 } 422 HideObject(ObjectState objectToHide)423 public override void HideObject(ObjectState objectToHide) 424 { 425 Program.Renderer.VisibleObjects.HideObject(objectToHide); 426 } 427 428 public override int AnimatedWorldObjectsUsed 429 { 430 get 431 { 432 return ObjectManager.AnimatedWorldObjectsUsed; 433 } 434 set 435 { 436 int a = ObjectManager.AnimatedWorldObjectsUsed; 437 if (ObjectManager.AnimatedWorldObjects.Length -1 == a) 438 { 439 /* 440 * HACK: We cannot resize an array via an accessor property 441 * With this in mind, resize it via the indexer instead 442 */ 443 Array.Resize(ref ObjectManager.AnimatedWorldObjects, ObjectManager.AnimatedWorldObjects.Length << 1); 444 } 445 446 ObjectManager.AnimatedWorldObjectsUsed = value; 447 } 448 } 449 450 public override WorldObject[] AnimatedWorldObjects 451 { 452 get 453 { 454 return ObjectManager.AnimatedWorldObjects; 455 } 456 set 457 { 458 ObjectManager.AnimatedWorldObjects = value; 459 } 460 } 461 462 public override Dictionary<int, Track> Tracks 463 { 464 get 465 { 466 return Program.CurrentRoute.Tracks; 467 } 468 set 469 { 470 Program.CurrentRoute.Tracks = value; 471 } 472 } 473 ParseTrackFollowingObject(string objectPath, string tfoFile)474 public override AbstractTrain ParseTrackFollowingObject(string objectPath, string tfoFile) 475 { 476 Interface.AddMessage(MessageType.Warning, false, "Track Following Objects are not shown in Route Viewer. Please test using the main simulation."); 477 return null; 478 } 479 480 public override AbstractTrain[] Trains 481 { 482 get 483 { 484 // ReSharper disable once CoVariantArrayConversion 485 return Program.TrainManager.Trains; 486 } 487 } 488 ClosestTrain(AbstractTrain Train)489 public override AbstractTrain ClosestTrain(AbstractTrain Train) 490 { 491 TrainBase baseTrain = Train as TrainBase; 492 AbstractTrain closestTrain = null; 493 double bestLocation = double.MaxValue; 494 if(baseTrain != null) 495 { 496 for (int i = 0; i < Program.TrainManager.Trains.Length; i++) 497 { 498 if (Program.TrainManager.Trains[i] != baseTrain & Program.TrainManager.Trains[i].State == TrainState.Available & baseTrain.Cars.Length > 0) 499 { 500 int c = Program.TrainManager.Trains[i].Cars.Length - 1; 501 double z = Program.TrainManager.Trains[i].Cars[c].RearAxle.Follower.TrackPosition - Program.TrainManager.Trains[i].Cars[c].RearAxle.Position - 0.5 * Program.TrainManager.Trains[i].Cars[c].Length; 502 if (z >= baseTrain.FrontCarTrackPosition() & z < bestLocation) 503 { 504 bestLocation = z; 505 closestTrain = Program.TrainManager.Trains[i]; 506 } 507 } 508 } 509 } 510 return closestTrain; 511 } 512 ClosestTrain(double TrackPosition)513 public override AbstractTrain ClosestTrain(double TrackPosition) 514 { 515 AbstractTrain closestTrain = null; 516 double trainDistance = double.MaxValue; 517 for (int j = 0; j < Program.TrainManager.Trains.Length; j++) 518 { 519 if (Program.TrainManager.Trains[j].State == TrainState.Available) 520 { 521 double distance; 522 if (Program.TrainManager.Trains[j].Cars[0].FrontAxle.Follower.TrackPosition < TrackPosition) 523 { 524 distance = TrackPosition - Program.TrainManager.Trains[j].Cars[0].TrackPosition; 525 } 526 else if (Program.TrainManager.Trains[j].Cars[Program.TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition > TrackPosition) 527 { 528 distance = Program.TrainManager.Trains[j].Cars[Program.TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition - TrackPosition; 529 } 530 else 531 { 532 distance = 0; 533 } 534 if (distance < trainDistance) 535 { 536 closestTrain = Program.TrainManager.Trains[j]; 537 trainDistance = distance; 538 } 539 } 540 } 541 return closestTrain; 542 } 543 Host()544 public Host() : base(HostApplication.RouteViewer) 545 { 546 } 547 } 548 } 549