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