From 2556deebf027dd13623f1e2939266fcd68f1e5d6 Mon Sep 17 00:00:00 2001
From: adfriz <76892624+adfriz@users.noreply.github.com>
Date: Fri, 24 Apr 2026 20:00:28 +0700
Subject: [PATCH 1/9] Refactor librenderer2 to modular rendering pipeline and
state management Overhauled LibRender2 to use a structured pipeline
architecture.
- Split rendering logic into specialized passes (Geometry, Sky, Shadow, Overlay).
- Added SceneManager to decouple visibility logic from the renderer.
- Implemented GraphicsDevice for centralized OpenGL state caching.
- Introduced GpuResourceManager for managed resource lifecycles.
- Unified the rendering loop across all application modules.
---
source/LibRender2/BaseRenderer.cs | 691 +++---------------
source/LibRender2/Camera/Camera.cs | 2 +-
source/LibRender2/LibRender2.csproj | 10 +
source/LibRender2/Lighting/Lighting.cs | 5 +-
.../LibRender2/Managers/GpuResourceManager.cs | 96 +++
source/LibRender2/Managers/SceneManager.cs | 470 ++++++++++++
source/LibRender2/Objects/ObjectLibrary.cs | 4 +-
source/LibRender2/Passes/GeometryPass.cs | 129 ++++
source/LibRender2/Passes/OverlayPass.cs | 182 +++++
source/LibRender2/Passes/ShadowPass.cs | 148 ++++
source/LibRender2/Passes/SkyPass.cs | 38 +
source/LibRender2/Pipeline/GraphicsDevice.cs | 114 +++
source/LibRender2/Pipeline/IRenderPass.cs | 14 +
source/LibRender2/Pipeline/RenderContext.cs | 41 ++
source/LibRender2/Pipeline/RenderPipeline.cs | 43 ++
source/LibRender2/Primitives/Rectangle.cs | 4 +-
source/LibRender2/Smoke/ParticleSource.cs | 2 +-
source/LibRender2/openGL/IndexBufferObject.cs | 5 +-
source/LibRender2/openGL/VertexArrayObject.cs | 5 +-
.../LibRender2/openGL/VertexBufferObject.cs | 5 +-
source/ObjectViewer/Graphics/NewRendererS.cs | 115 +--
source/ObjectViewer/Options.cs | 5 +-
source/ObjectViewer/ProgramS.cs | 2 +-
source/ObjectViewer/formOptions.Designer.cs | 38 +
source/ObjectViewer/formOptions.cs | 2 +
source/OpenBVE/Graphics/NewRenderer.cs | 498 ++++---------
.../Graphics/Renderers/Overlays.Debug.cs | 2 +-
source/OpenBVE/Graphics/Renderers/Overlays.cs | 2 +-
source/OpenBVE/System/GameWindow.cs | 2 +-
source/RouteViewer/NewRendererR.cs | 136 +---
30 files changed, 1606 insertions(+), 1204 deletions(-)
create mode 100644 source/LibRender2/Managers/GpuResourceManager.cs
create mode 100644 source/LibRender2/Managers/SceneManager.cs
create mode 100644 source/LibRender2/Passes/GeometryPass.cs
create mode 100644 source/LibRender2/Passes/OverlayPass.cs
create mode 100644 source/LibRender2/Passes/ShadowPass.cs
create mode 100644 source/LibRender2/Passes/SkyPass.cs
create mode 100644 source/LibRender2/Pipeline/GraphicsDevice.cs
create mode 100644 source/LibRender2/Pipeline/IRenderPass.cs
create mode 100644 source/LibRender2/Pipeline/RenderContext.cs
create mode 100644 source/LibRender2/Pipeline/RenderPipeline.cs
diff --git a/source/LibRender2/BaseRenderer.cs b/source/LibRender2/BaseRenderer.cs
index b291bf5d33..3568eafcd0 100644
--- a/source/LibRender2/BaseRenderer.cs
+++ b/source/LibRender2/BaseRenderer.cs
@@ -15,6 +15,8 @@
using LibRender2.MotionBlurs;
using LibRender2.Objects;
using LibRender2.Overlays;
+using LibRender2.Managers;
+using LibRender2.Pipeline;
using LibRender2.Primitives;
using LibRender2.Screens;
using LibRender2.Shaders;
@@ -56,16 +58,11 @@ public abstract class BaseRenderer
internal FileSystem fileSystem;
/// Holds a reference to the current options
- internal BaseOptions currentOptions;
+ protected internal BaseOptions currentOptions;
- public List StaticObjectStates;
- public List DynamicObjectStates;
- public VisibleObjectLibrary VisibleObjects;
+ /// The scene manager.
+ public SceneManager Scene;
- protected int[] ObjectsSortedByStart;
- protected int[] ObjectsSortedByEnd;
- protected int ObjectsSortedByStartPointer;
- protected int ObjectsSortedByEndPointer;
protected internal double LastUpdatedTrackPosition;
/// Whether ReShade is in use
/// Don't use OpenGL error checking with ReShade, as this breaks
@@ -73,6 +70,12 @@ public abstract class BaseRenderer
/// A dummy VAO used when working with procedural data within the shader
public VertexArrayObject dummyVao;
+ /// The graphics device state manager.
+ public GraphicsDevice Device;
+
+ /// The render pipeline.
+ public RenderPipeline Pipeline;
+
public Screen Screen;
/// The track follower for the main camera
@@ -135,6 +138,46 @@ public Vector2 ScaleFactor
public MotionBlur MotionBlur;
public Fonts Fonts;
+ /// The GPU resource manager.
+ public LibRender2.Managers.GpuResourceManager ResourceManager;
+
+ public VisibleObjectLibrary VisibleObjects => Scene.VisibleObjects;
+ public object VisibilityUpdateLock => Scene.VisibilityUpdateLock;
+ public bool VisibilityThreadShouldRun
+ {
+ get => Scene.VisibilityThreadShouldRun;
+ set => Scene.VisibilityThreadShouldRun = value;
+ }
+
+ public void BindCSMToDefaultShader()
+ {
+ if (CSMShadowMaps == null || DefaultShader == null)
+ {
+ return;
+ }
+
+ Shader shader = DefaultShader as Shader;
+ if (shader == null) return;
+
+ shader.SetShadowEnabled(true);
+ shader.SetCascadeCount(CSMCaster.CascadeCount);
+
+ for (int i = 0; i < CSMCaster.CascadeCount; i++)
+ {
+ // Shadows use texture units 4, 5, 6, 7
+ GL.ActiveTexture(TextureUnit.Texture4 + i);
+ GL.BindTexture(TextureTarget.Texture2D, CSMShadowMaps.DepthTextures[i]);
+ shader.SetCascadeShadowMapUnit(i, 4 + i);
+ shader.SetCascadeLightSpaceMatrix(i, CSMCaster.LightSpaceMatrices[i]);
+ shader.SetCascadeFarDistance(i, (float)CSMCaster.CascadeFarDistances[i]);
+ }
+
+ shader.SetShadowStrength(Lighting.ShadowStrength);
+ GL.ActiveTexture(TextureUnit.Texture0);
+ }
+
+ public ConcurrentQueue RenderThreadJobs => Scene.RenderThreadJobs;
+
public Matrix4D CurrentProjectionMatrix;
public Matrix4D CurrentViewMatrix;
@@ -306,14 +349,6 @@ public bool LoadLogo()
return currentHost.LoadTexture(ref _programLogo, OpenGlTextureWrapMode.ClampClamp);
}
- /*
- * List of VBO and IBO to delete on the next frame pass
- * This needs to be done here as opposed to in the finalizer
- */
- internal static readonly List vaoToDelete = new List();
- internal static readonly List vboToDelete = new List();
- internal static readonly List iboToDelete = new List();
-
public Dictionary> CubesToDraw = new Dictionary>();
public bool AvailableNewRenderer => currentOptions != null && currentOptions.IsUseNewRenderer && !ForceLegacyOpenGL;
@@ -338,10 +373,11 @@ protected BaseRenderer(HostInterface CurrentHost, BaseOptions CurrentOptions, Fi
projectionMatrixList = new List();
viewMatrixList = new List();
+ Device = new GraphicsDevice();
+ Pipeline = new RenderPipeline();
+ Scene = new SceneManager(this);
+ ResourceManager = new LibRender2.Managers.GpuResourceManager();
Fonts = new Fonts(currentHost, this, currentOptions.Font);
- VisibilityThread = new Thread(RunVisibiliityThread);
- VisibilityThread.Start();
- RenderThreadJobs = new ConcurrentQueue();
}
~BaseRenderer()
@@ -417,9 +453,9 @@ public virtual void Initialize()
Keys = new Keys(this);
MotionBlur = new MotionBlur(this);
- StaticObjectStates = new List();
- DynamicObjectStates = new List();
- VisibleObjects = new VisibleObjectLibrary(this);
+ Scene.StaticObjectStates = new List();
+ Scene.DynamicObjectStates = new List();
+ Scene.VisibleObjects = new VisibleObjectLibrary(this);
whitePixel = new Texture(new Texture(1, 1, PixelFormat.RGBAlpha, new byte[] {255, 255, 255, 255}, null));
if (AvailableNewRenderer)
{
@@ -587,8 +623,7 @@ public void DeInitialize()
nullDepthMap = 0;
}
GameWindow?.Dispose();
- // terminate spinning thread
- VisibilityThreadShouldRun = false;
+ Scene?.DeInitialize();
}
/// Should be called when the OpenGL version is switched mid-game
@@ -608,172 +643,14 @@ public void SwitchOpenGLVersion()
}
///
- /// Performs the CSM shadow depth rendering pass for all opaque geometry.
+ /// Executes all registered render passes in the pipeline.
///
- protected void PerformCSMShadowPass()
+ /// The current rendering context.
+ public void ExecutePipeline(RenderContext context)
{
- if (!ShadowsEnabled || CSMShadowMaps == null || CSMCaster == null || ShadowDepthShaderProgram == null)
- return;
-
- // 1. Get light direction pointing FROM the sun TOWARD the scene
- // OptionLightPosition points to the sun, so we negate it for the shadow pass.
- // OpenBVE world space is Z-forward, so we also negate the final Z for OpenGL space.
- Vector3 lightDir = new Vector3(
- -Lighting.OptionLightPosition.X,
- -Lighting.OptionLightPosition.Y,
- Lighting.OptionLightPosition.Z // -(-Z) from previous code
- );
-
- // 2. Update cascade matrices
- // Use CurrentViewMatrix (Z-negated) so the frustum corners match the world space
- // that the shadow depth shader and shadow lookup shader both operate in.
- if (lightDir.IsNullVector())
- {
- return;
- }
- CSMCaster.Resolution = CSMShadowMaps.Resolution;
- if (currentOptions.ShadowDrawDistance == ShadowDistance.ViewingDistance)
- {
- CSMCaster.ShadowDistance = currentOptions.ViewingDistance;
- }
- CSMCaster.Update(lightDir, CurrentViewMatrix, CurrentProjectionMatrix, 0.1, Camera.VerticalViewingAngle, Screen.AspectRatio);
-
- // 3. Setup rendering state
- CurrentShader?.Deactivate();
- ShadowDepthShaderProgram.Activate();
- GL.Enable(EnableCap.DepthTest);
- GL.DepthFunc(DepthFunction.Less);
- GL.Disable(EnableCap.CullFace);
- GL.DepthMask(true); // Ensure depth writes are enabled before clearing
- ShadowDepthShaderProgram.SetTexture(0); // always use texture unit 0
-
- for (int cascade = 0; cascade < CSMCaster.CascadeCount; cascade++)
- {
- CSMShadowMaps.BindCascadeForWriting(cascade);
- GL.Clear(ClearBufferMask.DepthBufferBit);
- ShadowDepthShaderProgram.SetLightSpaceMatrix(CSMCaster.LightSpaceMatrices[cascade]);
-
- lock (VisibleObjects.LockObject)
- {
- int lastVAOHandle = -1;
-
- // Add a helper to render a collection of faces into the shadow pass also avoiding duplicate loops for opaque and alpha collections.
- Action> renderFaces = faces =>
- {
- foreach (var face in faces)
- {
- if (face.Object.Prototype.Mesh.VAO == null) continue;
- if (face.Object.DisableShadowCasting) continue;
-
- Matrix4D modelMatrix = face.Object.ModelMatrix * Camera.TranslationMatrix;
- ShadowDepthShaderProgram.SetModelMatrix(modelMatrix);
-
- // Bind texture for alpha scissoring if the face has one
- var material = face.Object.Prototype.Mesh.Materials[face.Face.Material];
- if (material.DaytimeTexture != null && currentHost.LoadTexture(ref material.DaytimeTexture, (OpenGlTextureWrapMode)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)))
- {
- GL.ActiveTexture(TextureUnit.Texture0);
- GL.BindTexture(TextureTarget.Texture2D,
- material.DaytimeTexture.OpenGlTextures[(int)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)].Name);
- ShadowDepthShaderProgram.SetHasTexture(true);
- }
- else
- {
- ShadowDepthShaderProgram.SetHasTexture(false);
- }
-
- // Set alpha cutoff + material alpha for all faces, so untextured semi-transparent
- // geometry (e.g. glass with Color,80,80,160,90) is also correctly discarded
- ShadowDepthShaderProgram.SetAlphaCutoff(0.5f);
- ShadowDepthShaderProgram.SetMaterialAlpha(material.Color.A / 255.0f);
- ShadowDepthShaderProgram.SetMaterialFlags(material.Flags);
-
-#pragma warning disable CS0618
- ObjectState state = face.Object;
- if (state.Matricies != null && state.Matricies.Length > 0)
- {
- ShadowDepthShaderProgram.SetCurrentAnimationMatricies(state);
- GL.BindBufferBase(BufferTarget.UniformBuffer, 0, state.MatrixBufferIndex);
- }
-#pragma warning restore CS0618
-
- VertexArrayObject vao = (VertexArrayObject)face.Object.Prototype.Mesh.VAO;
- if (vao.handle != lastVAOHandle)
- {
- vao.Bind();
- lastVAOHandle = vao.handle;
- }
- PrimitiveType drawMode = GetPrimitiveType(face.Face.Flags);
- vao.Draw(drawMode, face.Face.IboStartIndex, face.Face.Vertices.Length);
- }
- };
-
- // Render both opaque and alpha-tested geometry into the shadow map.
- // This ensures semi-transparent cutout objects (fences, trees, etc. using `transparent`)
- // cast proper silhouettes instead of being skipped.
- renderFaces(VisibleObjects.OpaqueFaces);
- renderFaces(VisibleObjects.AlphaFaces);
- }
- CSMShadowMaps.Unbind();
- }
-
- // 4. Restore state
- GL.DepthFunc(DepthFunction.Lequal);
- GL.CullFace(CullFaceMode.Front);
- GL.Viewport(0, 0, Screen.Width, Screen.Height);
-
- // Shadow pass corrupts the GL texture state without updating LastBoundTexture
- // Clear it here so the main pass is forced to rebind the correct texture or whitePixel.
- LastBoundTexture = null;
+ Pipeline.Execute(context);
}
- ///
- /// Binds cascading shadow data to the default shader.
- ///
- protected void BindCSMToDefaultShader()
- {
- if (!ShadowsEnabled || CSMShadowMaps == null || CSMCaster == null)
- {
- DefaultShader.SetShadowEnabled(false);
- // To satisfy strict OpenGL drivers (e.g. Apple/Intel), we must still bind a depth-compatible
- // texture even if shadows are disabled, as the shader contains sampler2DShadow uniforms.
- for (int i = 0; i < 4; i++)
- {
- GL.ActiveTexture(TextureUnit.Texture4 + i);
- GL.BindTexture(TextureTarget.Texture2D, nullDepthMap);
- }
- GL.ActiveTexture(TextureUnit.Texture0);
- return;
- }
-
- DefaultShader.Activate();
- DefaultShader.SetShadowEnabled(true);
-
- // Read strength from current options (supports runtime changes)
- DefaultShader.SetShadowStrength((float)currentOptions.ShadowStrength);
- DefaultShader.SetCurrentViewMatrix(CurrentViewMatrix);
-
- CSMShadowMaps.BindAllCascadesForReading(TextureUnit.Texture4);
-
- int cascadeCount = CSMCaster.CascadeCount;
- for (int i = 0; i < cascadeCount; i++)
- {
- DefaultShader.SetCascadeLightSpaceMatrix(i, CSMCaster.LightSpaceMatrices[i]);
- DefaultShader.SetCascadeShadowMapUnit(i, 4 + i);
- DefaultShader.SetCascadeFarDistance(i, (float)CSMCaster.CascadeFarDistances[i]);
- DefaultShader.SetCascadeBias(i, CSMCaster.CascadeBiases[i] + (float)currentOptions.ShadowBias);
- DefaultShader.SetNormalBias(i, (float)currentOptions.ShadowNormalBias);
- }
-
-
- // If fewer than max cascades, disable unused slots
- for (int i = cascadeCount; i < 4; i++)
- {
- DefaultShader.SetCascadeFarDistance(i, 0.0f);
- }
-
- DefaultShader.SetCascadeCount(cascadeCount);
- }
private PrimitiveType GetPrimitiveType(FaceFlags flags)
{
@@ -787,36 +664,10 @@ private PrimitiveType GetPrimitiveType(FaceFlags flags)
}
}
- /// Performs cleanup of disposed resources
+ /// Should be called at the start of each frame to release any GPU resources queued for deletion
public void ReleaseResources()
{
- //Must remember to lock on the lists as the destructor is in a different thread
- lock (vaoToDelete)
- {
- foreach (int VAO in vaoToDelete)
- {
- GL.DeleteVertexArray(VAO);
- }
- vaoToDelete.Clear();
- }
-
- lock (vboToDelete)
- {
- foreach (int VBO in vboToDelete)
- {
- GL.DeleteBuffer(VBO);
- }
- vboToDelete.Clear();
- }
-
- lock (iboToDelete)
- {
- foreach (int IBO in iboToDelete)
- {
- GL.DeleteBuffer(IBO);
- }
- iboToDelete.Clear();
- }
+ ResourceManager.ReleaseResources();
}
///
@@ -876,141 +727,22 @@ public void PopMatrix(MatrixMode Mode)
public void Reset()
{
- currentHost.AnimatedObjectCollectionCache.Clear();
- List> keys = currentHost.StaticObjectCache.Keys.ToList();
- for (int i = 0; i < keys.Count; i++)
- {
- if (!File.Exists(keys[i].Item1) || File.GetLastWriteTime(keys[i].Item1) != keys[i].Item3)
- {
- currentHost.StaticObjectCache.Remove(keys[i]);
- }
- }
- TextureManager.UnloadAllTextures(true);
- VisibleObjects.Clear();
+ Scene.Reset();
}
public int CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, ObjectDisposalMode AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, bool DisableShadowCasting)
{
- Matrix4D Translate = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z);
- Matrix4D Rotate = (Matrix4D)new Transformation(LocalTransformation, WorldTransformation);
- return CreateStaticObject(Position, Prototype, LocalTransformation, Rotate, Translate, AccurateObjectDisposal, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, BlockLength, TrackPosition, DisableShadowCasting);
+ return Scene.CreateStaticObject(Prototype, Position, WorldTransformation, LocalTransformation, AccurateObjectDisposal, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, BlockLength, TrackPosition, DisableShadowCasting);
}
public int CreateStaticObject(Vector3 Position, StaticObject Prototype, Transformation LocalTransformation, Matrix4D Rotate, Matrix4D Translate, ObjectDisposalMode AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, bool DisableShadowCasting = false)
{
- if (Prototype == null)
- {
- return -1;
- }
-
- if (Prototype.Mesh.Faces.Length == 0)
- {
- //Null object- Waste of time trying to calculate anything for these
- return -1;
- }
-
- float startingDistance = float.MaxValue;
- float endingDistance = float.MinValue;
-
- if (AccurateObjectDisposal == ObjectDisposalMode.Accurate)
- {
- foreach (VertexTemplate vertex in Prototype.Mesh.Vertices)
- {
- Vector3 Coordinates = new Vector3(vertex.Coordinates);
- Coordinates.Rotate(LocalTransformation);
-
- if (Coordinates.Z < startingDistance)
- {
- startingDistance = (float)Coordinates.Z;
- }
-
- if (Coordinates.Z > endingDistance)
- {
- endingDistance = (float)Coordinates.Z;
- }
- }
-
- startingDistance += (float)AccurateObjectDisposalZOffset;
- endingDistance += (float)AccurateObjectDisposalZOffset;
- }
-
- const double minBlockLength = 20.0;
-
- if (BlockLength < minBlockLength)
- {
- BlockLength *= Math.Ceiling(minBlockLength / BlockLength);
- }
-
- switch (AccurateObjectDisposal)
- {
- case ObjectDisposalMode.Accurate:
- startingDistance += (float)TrackPosition;
- endingDistance += (float)TrackPosition;
- double z = BlockLength * Math.Floor(TrackPosition / BlockLength);
- StartingDistance = Math.Min(z - BlockLength, startingDistance);
- EndingDistance = Math.Max(z + 2.0 * BlockLength, endingDistance);
- startingDistance = (float)(BlockLength * Math.Floor(StartingDistance / BlockLength));
- endingDistance = (float)(BlockLength * Math.Ceiling(EndingDistance / BlockLength));
- break;
- case ObjectDisposalMode.Legacy:
- startingDistance = (float)StartingDistance;
- endingDistance = (float)EndingDistance;
- break;
- case ObjectDisposalMode.Mechanik:
- startingDistance = (float) StartingDistance;
- endingDistance = (float) EndingDistance + 1500;
- if (startingDistance < 0)
- {
- startingDistance = 0;
- }
- break;
- }
- StaticObjectStates.Add(new ObjectState
- {
- Prototype = Prototype,
- Translation = Translate,
- Rotate = Rotate,
- StartingDistance = startingDistance,
- EndingDistance = endingDistance,
- WorldPosition = Position,
- DisableShadowCasting = DisableShadowCasting
- });
-
- foreach (MeshFace face in Prototype.Mesh.Faces)
- {
- switch (face.Flags & FaceFlags.FaceTypeMask)
- {
- case FaceFlags.Triangles:
- InfoTotalTriangles++;
- break;
- case FaceFlags.TriangleStrip:
- InfoTotalTriangleStrip++;
- break;
- case FaceFlags.Quads:
- InfoTotalQuads++;
- break;
- case FaceFlags.QuadStrip:
- InfoTotalQuadStrip++;
- break;
- case FaceFlags.Polygon:
- InfoTotalPolygon++;
- break;
- }
- }
-
- return StaticObjectStates.Count - 1;
+ return Scene.CreateStaticObject(Position, Prototype, LocalTransformation, Rotate, Translate, AccurateObjectDisposal, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, BlockLength, TrackPosition, DisableShadowCasting);
}
public void CreateDynamicObject(ref ObjectState internalObject)
{
- if (internalObject == null)
- {
- internalObject = new ObjectState( new StaticObject(currentHost));
- }
-
- internalObject.Prototype.Dynamic = true;
-
- DynamicObjectStates.Add(internalObject);
+ Scene.CreateDynamicObject(ref internalObject);
}
/// Initializes the visibility of all objects within the game world
@@ -1018,276 +750,17 @@ public void CreateDynamicObject(ref ObjectState internalObject)
/// the required VAO objects
public void InitializeVisibility()
{
- if (!ForceLegacyOpenGL) // as we might want to switch renderer types
- {
- for (int i = 0; i < StaticObjectStates.Count; i++)
- {
- VAOExtensions.CreateVAO(StaticObjectStates[i].Prototype.Mesh, false, DefaultShader.VertexLayout, this);
- /*
- * n.b.
- * Only create the actual matrix buffer at first frame render time
- * I can't find why at the minute, but Object Viewer otherwise doesn't show them, and attempting
- * to retrieve previously set matricies from the shader shows all zeros
- *
- * Probably a timing issue, but it works doing it that way :/
- */
- }
- for (int i = 0; i < DynamicObjectStates.Count; i++)
- {
- VAOExtensions.CreateVAO(DynamicObjectStates[i].Prototype.Mesh, false, DefaultShader.VertexLayout, this);
- }
- }
- ObjectsSortedByStart = StaticObjectStates.Select((x, i) => new { Index = i, Distance = x.StartingDistance }).OrderBy(x => x.Distance).Select(x => x.Index).ToArray();
- ObjectsSortedByEnd = StaticObjectStates.Select((x, i) => new { Index = i, Distance = x.EndingDistance }).OrderBy(x => x.Distance).Select(x => x.Index).ToArray();
- ObjectsSortedByStartPointer = 0;
- ObjectsSortedByEndPointer = 0;
-
- if (currentOptions.ObjectDisposalMode == ObjectDisposalMode.QuadTree)
- {
- foreach (ObjectState state in StaticObjectStates)
- {
- VisibleObjects.quadTree.Add(state, Orientation3.Default);
- }
- VisibleObjects.quadTree.Initialize(currentOptions.QuadTreeLeafSize);
- UpdateQuadTreeVisibility();
- }
- else
- {
- double p = CameraTrackFollower.TrackPosition + Camera.Alignment.Position.Z;
- foreach (ObjectState state in StaticObjectStates.Where(recipe => recipe.StartingDistance <= p + Camera.ForwardViewingDistance & recipe.EndingDistance >= p - Camera.BackwardViewingDistance))
- {
- VisibleObjects.ShowObject(state, ObjectType.Static);
- }
- }
- }
-
- private VisibilityUpdate updateVisibility;
- /// The lock to be held whilst visibility updates or loading operations are in progress
- public object VisibilityUpdateLock = new object();
-
- public bool VisibilityThreadShouldRun = true;
-
- public Thread VisibilityThread;
-
- private void RunVisibiliityThread()
- {
- while (VisibilityThreadShouldRun)
- {
- lock (VisibilityUpdateLock)
- {
- if (updateVisibility != VisibilityUpdate.None && CameraTrackFollower != null)
- {
- UpdateVisibility(CameraTrackFollower.TrackPosition + Camera.Alignment.Position.Z);
- }
- }
-
- if (updateVisibility == VisibilityUpdate.None)
- {
- Thread.Sleep(100);
- }
- }
+ Scene.InitializeVisibility();
}
public void UpdateVisibility(bool force)
{
- updateVisibility = force ? VisibilityUpdate.Force : VisibilityUpdate.Normal;
- }
-
- private void UpdateVisibility(double trackPosition)
- {
- if (currentOptions.ObjectDisposalMode == ObjectDisposalMode.QuadTree)
- {
- UpdateQuadTreeVisibility();
- }
- else
- {
- if (updateVisibility == VisibilityUpdate.Normal)
- {
- UpdateLegacyVisibility(trackPosition);
- }
- else
- {
- /*
- * The original visibility algorithm fails to handle correctly cases where the
- * camera angle is rotated, but the track position does not change
- *
- * Horrible kludge...
- */
- UpdateLegacyVisibility(trackPosition + 0.01);
- UpdateLegacyVisibility(trackPosition - 0.01);
- }
-
- }
-
- updateVisibility = VisibilityUpdate.None;
- }
-
- private void UpdateQuadTreeVisibility()
- {
- if (VisibleObjects == null || VisibleObjects.quadTree == null)
- {
- Thread.Sleep(10);
- return;
- }
- Camera.UpdateQuadTreeLeaf();
- }
-
- private void UpdateLegacyVisibility(double trackPosition)
- {
- if (ObjectsSortedByStart == null || ObjectsSortedByStart.Length == 0 || StaticObjectStates.Count == 0)
- {
- return;
- }
- double d = trackPosition - LastUpdatedTrackPosition;
- int n = ObjectsSortedByStart.Length;
- double p = CameraTrackFollower.TrackPosition + Camera.Alignment.Position.Z;
-
- if (d < 0.0)
- {
- if (ObjectsSortedByStartPointer >= n)
- {
- ObjectsSortedByStartPointer = n - 1;
- }
-
- if (ObjectsSortedByEndPointer >= n)
- {
- ObjectsSortedByEndPointer = n - 1;
- }
-
- // dispose
- while (ObjectsSortedByStartPointer >= 0)
- {
- int o = ObjectsSortedByStart[ObjectsSortedByStartPointer];
-
- if (StaticObjectStates[o].StartingDistance > p + Camera.ForwardViewingDistance)
- {
- VisibleObjects.HideObject(StaticObjectStates[o]);
- ObjectsSortedByStartPointer--;
- }
- else
- {
- break;
- }
- }
-
- // introduce
- while (ObjectsSortedByEndPointer >= 0)
- {
- int o = ObjectsSortedByEnd[ObjectsSortedByEndPointer];
-
- if (StaticObjectStates[o].EndingDistance >= p - Camera.BackwardViewingDistance)
- {
- if (StaticObjectStates[o].StartingDistance <= p + Camera.ForwardViewingDistance)
- {
- VisibleObjects.ShowObject(StaticObjectStates[o], ObjectType.Static);
- }
-
- ObjectsSortedByEndPointer--;
- }
- else
- {
- break;
- }
- }
- }
- else if (d > 0.0)
- {
- if (ObjectsSortedByStartPointer < 0)
- {
- ObjectsSortedByStartPointer = 0;
- }
-
- if (ObjectsSortedByEndPointer < 0)
- {
- ObjectsSortedByEndPointer = 0;
- }
-
- // dispose
- while (ObjectsSortedByEndPointer < n)
- {
- int o = ObjectsSortedByEnd[ObjectsSortedByEndPointer];
-
- if (StaticObjectStates[o].EndingDistance < p - Camera.BackwardViewingDistance)
- {
- VisibleObjects.HideObject(StaticObjectStates[o]);
- ObjectsSortedByEndPointer++;
- }
- else
- {
- break;
- }
- }
- n = ObjectsSortedByStart.Length;
-
- // introduce
- while (ObjectsSortedByStartPointer < n)
- {
- int o = ObjectsSortedByStart[ObjectsSortedByStartPointer];
-
- if (StaticObjectStates[o].StartingDistance <= p + Camera.ForwardViewingDistance)
- {
- if (StaticObjectStates[o].EndingDistance >= p - Camera.BackwardViewingDistance)
- {
- VisibleObjects.ShowObject(StaticObjectStates[o], ObjectType.Static);
- }
-
- ObjectsSortedByStartPointer++;
- }
- else
- {
- break;
- }
- }
- }
-
- LastUpdatedTrackPosition = trackPosition;
+ Scene.UpdateVisibility(force);
}
public void UpdateViewingDistances(double backgroundImageDistance)
{
- double f = Math.Atan2(CameraTrackFollower.WorldDirection.Z, CameraTrackFollower.WorldDirection.X);
- double c = Math.Atan2(Camera.AbsoluteDirection.Z, Camera.AbsoluteDirection.X) - f;
- if (c < -Math.PI)
- {
- c += 2.0 * Math.PI;
- }
- else if (c > Math.PI)
- {
- c -= 2.0 * Math.PI;
- }
-
- double a0 = c - 0.5 * Camera.HorizontalViewingAngle;
- double a1 = c + 0.5 * Camera.HorizontalViewingAngle;
- double max;
- if (a0 <= 0.0 & a1 >= 0.0)
- {
- max = 1.0;
- }
- else
- {
- double c0 = Math.Cos(a0);
- double c1 = Math.Cos(a1);
- max = c0 > c1 ? c0 : c1;
- if (max < 0.0) max = 0.0;
- }
-
- double min;
- if (a0 <= -Math.PI | a1 >= Math.PI)
- {
- min = -1.0;
- }
- else
- {
- double c0 = Math.Cos(a0);
- double c1 = Math.Cos(a1);
- min = c0 < c1 ? c0 : c1;
- if (min > 0.0) min = 0.0;
- }
-
- double d = backgroundImageDistance + Camera.ExtraViewingDistance;
- Camera.ForwardViewingDistance = d * max;
- Camera.BackwardViewingDistance = -d * min;
- updateVisibility = VisibilityUpdate.Force;
+ Scene.UpdateViewingDistances(backgroundImageDistance);
}
/// Determines the maximum Anisotropic filtering level the system supports
@@ -1711,8 +1184,7 @@ public void RenderFace(Shader shader, ObjectState state, MeshFace face, bool deb
{
//Additive blending- Full brightness
factor = 1.0f;
- GL.Enable(EnableCap.Blend);
- GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
+ SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
shader.SetFog(false);
}
else if (material.NighttimeTexture == null || material.NighttimeTexture == material.DaytimeTexture)
@@ -1750,7 +1222,7 @@ public void RenderFace(Shader shader, ObjectState state, MeshFace face, bool deb
}
- GL.Enable(EnableCap.Blend);
+ Device.SetBlend(true);
// alpha test
shader.SetAlphaTest(true);
@@ -1939,8 +1411,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
if (material.BlendMode == MeshMaterialBlendMode.Additive)
{
factor = 1.0f;
- GL.Enable(EnableCap.Blend);
- GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
+ SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
GL.Disable(EnableCap.Fog);
}
else if (material.NighttimeTexture == null)
@@ -2001,7 +1472,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
LastBoundTexture = material.NighttimeTexture.OpenGlTextures[(int)material.WrapMode];
}
- GL.Enable(EnableCap.Blend);
+ Device.SetBlend(true);
// alpha test
GL.Enable(EnableCap.AlphaTest);
@@ -2110,7 +1581,15 @@ public void SetWindowSize(int width, int height)
}
}
- public ConcurrentQueue RenderThreadJobs;
+ public void ShowObject(ObjectState Object, ObjectType Type)
+ {
+ Scene.ShowObject(Object, Type);
+ }
+
+ public void HideObject(ObjectState Object)
+ {
+ Scene.HideObject(Object);
+ }
/// This method is used during loading to run commands requiring an OpenGL context in the main render loop
/// The OpenGL command
diff --git a/source/LibRender2/Camera/Camera.cs b/source/LibRender2/Camera/Camera.cs
index c27811fd64..aec15b4447 100644
--- a/source/LibRender2/Camera/Camera.cs
+++ b/source/LibRender2/Camera/Camera.cs
@@ -61,7 +61,7 @@ public CameraAlignment AlignmentDirection
get => alignmentDirection;
set
{
- Renderer.UpdateVisibility(true);
+ Renderer.Scene.UpdateVisibility(true);
alignmentDirection = value;
}
}
diff --git a/source/LibRender2/LibRender2.csproj b/source/LibRender2/LibRender2.csproj
index c2a425c03c..34443aecfb 100644
--- a/source/LibRender2/LibRender2.csproj
+++ b/source/LibRender2/LibRender2.csproj
@@ -120,6 +120,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/source/LibRender2/Lighting/Lighting.cs b/source/LibRender2/Lighting/Lighting.cs
index 1ad677db87..de7850ccfc 100644
--- a/source/LibRender2/Lighting/Lighting.cs
+++ b/source/LibRender2/Lighting/Lighting.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using OpenBveApi.Colors;
using OpenBveApi.Math;
using OpenBveApi.Routes;
@@ -17,6 +17,9 @@ public class Lighting
/// The current dynamic cab brightness
public double DynamicCabBrightness = 255;
+ /// The strength of the shadows (0.0 to 1.0)
+ public float ShadowStrength = 1.0f;
+
/// The current ambient light color
public Color24 OptionAmbientColor = Color24.LightGrey;
diff --git a/source/LibRender2/Managers/GpuResourceManager.cs b/source/LibRender2/Managers/GpuResourceManager.cs
new file mode 100644
index 0000000000..039e1a602c
--- /dev/null
+++ b/source/LibRender2/Managers/GpuResourceManager.cs
@@ -0,0 +1,96 @@
+using System.Collections.Generic;
+using OpenTK.Graphics.OpenGL;
+
+namespace LibRender2.Managers
+{
+ ///
+ /// Manages the lifecycle of GPU resources to prevent leaks.
+ ///
+ public class GpuResourceManager
+ {
+ private static readonly List vaosToDelete = new List();
+ private static readonly List vbosToDelete = new List();
+ private static readonly List ibosToDelete = new List();
+
+ ///
+ /// Queues a Vertex Array Object for deletion.
+ ///
+ public static void QueueVaoForDeletion(int handle)
+ {
+ if (handle <= 0) return;
+ lock (vaosToDelete)
+ {
+ vaosToDelete.Add(handle);
+ }
+ }
+
+ ///
+ /// Queues a Vertex Buffer Object for deletion.
+ ///
+ public static void QueueVboForDeletion(int handle)
+ {
+ if (handle <= 0) return;
+ lock (vbosToDelete)
+ {
+ vbosToDelete.Add(handle);
+ }
+ }
+
+ ///
+ /// Queues an Index Buffer Object for deletion.
+ ///
+ public static void QueueIboForDeletion(int handle)
+ {
+ if (handle <= 0) return;
+ lock (ibosToDelete)
+ {
+ ibosToDelete.Add(handle);
+ }
+ }
+
+ ///
+ /// Deletes all queued resources. Must be called from a thread with a valid OpenGL context.
+ ///
+ public void ReleaseResources()
+ {
+ lock (vaosToDelete)
+ {
+ if (vaosToDelete.Count > 0)
+ {
+ foreach (int handle in vaosToDelete)
+ {
+ int h = handle;
+ GL.DeleteVertexArrays(1, ref h);
+ }
+ vaosToDelete.Clear();
+ }
+ }
+
+ lock (vbosToDelete)
+ {
+ if (vbosToDelete.Count > 0)
+ {
+ foreach (int handle in vbosToDelete)
+ {
+ int h = handle;
+ GL.DeleteBuffers(1, ref h);
+ }
+ vbosToDelete.Clear();
+ }
+ }
+
+ lock (ibosToDelete)
+ {
+ if (ibosToDelete.Count > 0)
+ {
+ foreach (int handle in ibosToDelete)
+ {
+ int h = handle;
+ GL.DeleteBuffers(1, ref h);
+ }
+ ibosToDelete.Clear();
+ }
+ }
+ }
+ }
+}
diff --git a/source/LibRender2/Managers/SceneManager.cs b/source/LibRender2/Managers/SceneManager.cs
new file mode 100644
index 0000000000..598ecef523
--- /dev/null
+++ b/source/LibRender2/Managers/SceneManager.cs
@@ -0,0 +1,470 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using LibRender2.Objects;
+using OpenBveApi.Math;
+using OpenBveApi.Objects;
+using OpenBveApi.Routes;
+using OpenBveApi.World;
+
+namespace LibRender2.Managers
+{
+ ///
+ /// Manages the objects within the scene, including visibility and dynamic object updates.
+ ///
+ public class SceneManager
+ {
+ private readonly BaseRenderer renderer;
+
+ /// The list of static object states in the scene.
+ public List StaticObjectStates = new List();
+
+ /// The list of dynamic object states in the scene.
+ public List DynamicObjectStates = new List();
+
+ /// The library of currently visible objects.
+ public VisibleObjectLibrary VisibleObjects;
+
+ public int[] ObjectsSortedByStart;
+ public int[] ObjectsSortedByEnd;
+ public int ObjectsSortedByStartPointer;
+ public int ObjectsSortedByEndPointer;
+ public double LastUpdatedTrackPosition;
+
+ /// Whether the visibility update thread should continue running.
+ public bool VisibilityThreadShouldRun = true;
+
+ /// The lock to be held whilst visibility updates or loading operations are in progress
+ public readonly object VisibilityUpdateLock = new object();
+
+ private readonly object LockObject = new object();
+
+ private VisibilityUpdate updateVisibility;
+ private Thread visibilityThread;
+
+ public void ShowObject(ObjectState Object, ObjectType Type)
+ {
+ VisibleObjects.ShowObject(Object, Type);
+ }
+
+ public void HideObject(ObjectState Object)
+ {
+ VisibleObjects.HideObject(Object);
+ }
+
+ /// A queue of jobs to be executed on the render thread (often related to object creation/disposal)
+ public readonly ConcurrentQueue RenderThreadJobs;
+
+ public SceneManager(BaseRenderer renderer)
+ {
+ this.renderer = renderer;
+ StaticObjectStates = new List();
+ DynamicObjectStates = new List();
+ VisibleObjects = new VisibleObjectLibrary(renderer);
+ RenderThreadJobs = new ConcurrentQueue();
+
+ visibilityThread = new Thread(RunVisibilityThread)
+ {
+ IsBackground = true,
+ Name = "VisibilityThread"
+ };
+ visibilityThread.Start();
+ }
+
+ ///
+ /// Deinitializes the scene manager and stops the visibility thread.
+ ///
+ public void DeInitialize()
+ {
+ VisibilityThreadShouldRun = false;
+ }
+
+ private void RunVisibilityThread()
+ {
+ while (VisibilityThreadShouldRun)
+ {
+ lock (VisibilityUpdateLock)
+ {
+ if (updateVisibility != VisibilityUpdate.None && renderer.CameraTrackFollower != null)
+ {
+ UpdateVisibility(renderer.CameraTrackFollower.TrackPosition + renderer.Camera.Alignment.Position.Z);
+ }
+ }
+
+ if (updateVisibility == VisibilityUpdate.None)
+ {
+ Thread.Sleep(100);
+ }
+ }
+ }
+
+ public void UpdateVisibility(bool force)
+ {
+ updateVisibility = force ? VisibilityUpdate.Force : VisibilityUpdate.Normal;
+ }
+
+ private void UpdateVisibility(double trackPosition)
+ {
+ if (renderer.currentOptions.ObjectDisposalMode == ObjectDisposalMode.QuadTree)
+ {
+ UpdateQuadTreeVisibility();
+ }
+ else
+ {
+ if (updateVisibility == VisibilityUpdate.Normal)
+ {
+ UpdateLegacyVisibility(trackPosition);
+ }
+ else
+ {
+ UpdateLegacyVisibility(trackPosition + 0.01);
+ UpdateLegacyVisibility(trackPosition - 0.01);
+ }
+ }
+
+ updateVisibility = VisibilityUpdate.None;
+ }
+
+ private void UpdateQuadTreeVisibility()
+ {
+ if (VisibleObjects == null || VisibleObjects.quadTree == null)
+ {
+ Thread.Sleep(10);
+ return;
+ }
+ renderer.Camera.UpdateQuadTreeLeaf();
+ }
+
+ private void UpdateLegacyVisibility(double trackPosition)
+ {
+ if (ObjectsSortedByStart == null || ObjectsSortedByStart.Length == 0 || StaticObjectStates.Count == 0)
+ {
+ return;
+ }
+
+ double d = trackPosition - LastUpdatedTrackPosition;
+ int n = ObjectsSortedByStart.Length;
+ double p = renderer.CameraTrackFollower.TrackPosition + renderer.Camera.Alignment.Position.Z;
+
+ if (d < 0.0)
+ {
+ if (ObjectsSortedByStartPointer >= n)
+ {
+ ObjectsSortedByStartPointer = n - 1;
+ }
+
+ if (ObjectsSortedByEndPointer >= n)
+ {
+ ObjectsSortedByEndPointer = n - 1;
+ }
+
+ while (ObjectsSortedByStartPointer >= 0)
+ {
+ int o = ObjectsSortedByStart[ObjectsSortedByStartPointer];
+
+ if (StaticObjectStates[o].StartingDistance > p + renderer.Camera.ForwardViewingDistance)
+ {
+ VisibleObjects.HideObject(StaticObjectStates[o]);
+ ObjectsSortedByStartPointer--;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ while (ObjectsSortedByEndPointer >= 0)
+ {
+ int o = ObjectsSortedByEnd[ObjectsSortedByEndPointer];
+
+ if (StaticObjectStates[o].EndingDistance >= p - renderer.Camera.BackwardViewingDistance)
+ {
+ if (StaticObjectStates[o].StartingDistance <= p + renderer.Camera.ForwardViewingDistance)
+ {
+ VisibleObjects.ShowObject(StaticObjectStates[o], ObjectType.Static);
+ }
+
+ ObjectsSortedByEndPointer--;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else if (d > 0.0)
+ {
+ if (ObjectsSortedByStartPointer < 0)
+ {
+ ObjectsSortedByStartPointer = 0;
+ }
+
+ if (ObjectsSortedByEndPointer < 0)
+ {
+ ObjectsSortedByEndPointer = 0;
+ }
+
+ while (ObjectsSortedByEndPointer < n)
+ {
+ int o = ObjectsSortedByEnd[ObjectsSortedByEndPointer];
+
+ if (StaticObjectStates[o].EndingDistance < p - renderer.Camera.BackwardViewingDistance)
+ {
+ VisibleObjects.HideObject(StaticObjectStates[o]);
+ ObjectsSortedByEndPointer++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ while (ObjectsSortedByStartPointer < n)
+ {
+ int o = ObjectsSortedByStart[ObjectsSortedByStartPointer];
+
+ if (StaticObjectStates[o].StartingDistance <= p + renderer.Camera.ForwardViewingDistance)
+ {
+ if (StaticObjectStates[o].EndingDistance >= p - renderer.Camera.BackwardViewingDistance)
+ {
+ VisibleObjects.ShowObject(StaticObjectStates[o], ObjectType.Static);
+ }
+
+ ObjectsSortedByStartPointer++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ LastUpdatedTrackPosition = trackPosition;
+ }
+
+ public void UpdateViewingDistances(double backgroundImageDistance)
+ {
+ double f = Math.Atan2(renderer.CameraTrackFollower.WorldDirection.Z, renderer.CameraTrackFollower.WorldDirection.X);
+ double c = Math.Atan2(renderer.Camera.AbsoluteDirection.Z, renderer.Camera.AbsoluteDirection.X) - f;
+ if (c < -Math.PI)
+ {
+ c += 2.0 * Math.PI;
+ }
+ else if (c > Math.PI)
+ {
+ c -= 2.0 * Math.PI;
+ }
+
+ double a0 = c - 0.5 * renderer.Camera.HorizontalViewingAngle;
+ double a1 = c + 0.5 * renderer.Camera.HorizontalViewingAngle;
+ double max;
+ if (a0 <= 0.0 & a1 >= 0.0)
+ {
+ max = 1.0;
+ }
+ else
+ {
+ double c0 = Math.Cos(a0);
+ double c1 = Math.Cos(a1);
+ max = c0 > c1 ? c0 : c1;
+ if (max < 0.0) max = 0.0;
+ }
+
+ double min;
+ if (a0 <= -Math.PI | a1 >= Math.PI)
+ {
+ min = -1.0;
+ }
+ else
+ {
+ double c0 = Math.Cos(a0);
+ double c1 = Math.Cos(a1);
+ min = c0 < c1 ? c0 : c1;
+ if (min > 0.0) min = 0.0;
+ }
+
+ double d = Math.Max(backgroundImageDistance, renderer.currentOptions.ViewingDistance) + renderer.Camera.ExtraViewingDistance;
+ renderer.Camera.ForwardViewingDistance = d * max;
+ renderer.Camera.BackwardViewingDistance = -d * min;
+ updateVisibility = VisibilityUpdate.Force;
+ }
+
+ public int CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, ObjectDisposalMode AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, bool DisableShadowCasting)
+ {
+ Matrix4D Translate = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z);
+ Matrix4D Rotate = (Matrix4D)new Transformation(LocalTransformation, WorldTransformation);
+ return CreateStaticObject(Position, Prototype, LocalTransformation, Rotate, Translate, AccurateObjectDisposal, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, BlockLength, TrackPosition, DisableShadowCasting);
+ }
+
+ public int CreateStaticObject(Vector3 Position, StaticObject Prototype, Transformation LocalTransformation, Matrix4D Rotate, Matrix4D Translate, ObjectDisposalMode AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, bool DisableShadowCasting = false)
+ {
+ if (Prototype == null)
+ {
+ return -1;
+ }
+
+ if (Prototype.Mesh.Faces.Length == 0)
+ {
+ //Null object- Waste of time trying to calculate anything for these
+ return -1;
+ }
+
+ float startingDistance = float.MaxValue;
+ float endingDistance = float.MinValue;
+
+ if (AccurateObjectDisposal == ObjectDisposalMode.Accurate)
+ {
+ foreach (VertexTemplate vertex in Prototype.Mesh.Vertices)
+ {
+ Vector3 Coordinates = new Vector3(vertex.Coordinates);
+ Coordinates.Rotate(LocalTransformation);
+
+ if (Coordinates.Z < startingDistance)
+ {
+ startingDistance = (float)Coordinates.Z;
+ }
+
+ if (Coordinates.Z > endingDistance)
+ {
+ endingDistance = (float)Coordinates.Z;
+ }
+ }
+
+ startingDistance += (float)AccurateObjectDisposalZOffset;
+ endingDistance += (float)AccurateObjectDisposalZOffset;
+ }
+
+ const double minBlockLength = 20.0;
+
+ if (BlockLength < minBlockLength)
+ {
+ BlockLength *= Math.Ceiling(minBlockLength / BlockLength);
+ }
+
+ switch (AccurateObjectDisposal)
+ {
+ case ObjectDisposalMode.Accurate:
+ startingDistance += (float)TrackPosition;
+ endingDistance += (float)TrackPosition;
+ double z = BlockLength * Math.Floor(TrackPosition / BlockLength);
+ StartingDistance = Math.Min(z - BlockLength, startingDistance);
+ EndingDistance = Math.Max(z + 2.0 * BlockLength, endingDistance);
+ startingDistance = (float)(BlockLength * Math.Floor(StartingDistance / BlockLength));
+ endingDistance = (float)(BlockLength * Math.Ceiling(EndingDistance / BlockLength));
+ break;
+ case ObjectDisposalMode.Legacy:
+ startingDistance = (float)StartingDistance;
+ endingDistance = (float)EndingDistance;
+ break;
+ case ObjectDisposalMode.Mechanik:
+ startingDistance = (float)StartingDistance;
+ endingDistance = (float)EndingDistance + 1500;
+ if (startingDistance < 0)
+ {
+ startingDistance = 0;
+ }
+ break;
+ }
+ StaticObjectStates.Add(new ObjectState
+ {
+ Prototype = Prototype,
+ Translation = Translate,
+ Rotate = Rotate,
+ StartingDistance = startingDistance,
+ EndingDistance = endingDistance,
+ WorldPosition = Position,
+ DisableShadowCasting = DisableShadowCasting
+ });
+
+ foreach (MeshFace face in Prototype.Mesh.Faces)
+ {
+ switch (face.Flags & FaceFlags.FaceTypeMask)
+ {
+ case FaceFlags.Triangles:
+ renderer.InfoTotalTriangles++;
+ break;
+ case FaceFlags.TriangleStrip:
+ renderer.InfoTotalTriangleStrip++;
+ break;
+ case FaceFlags.Quads:
+ renderer.InfoTotalQuads++;
+ break;
+ case FaceFlags.QuadStrip:
+ renderer.InfoTotalQuadStrip++;
+ break;
+ case FaceFlags.Polygon:
+ renderer.InfoTotalPolygon++;
+ break;
+ }
+ }
+
+ return StaticObjectStates.Count - 1;
+ }
+
+ public void CreateDynamicObject(ref ObjectState internalObject)
+ {
+ if (internalObject == null)
+ {
+ internalObject = new ObjectState(new StaticObject(renderer.currentHost));
+ }
+
+ internalObject.Prototype.Dynamic = true;
+
+ DynamicObjectStates.Add(internalObject);
+ }
+
+ public void InitializeVisibility()
+ {
+ if (!renderer.ForceLegacyOpenGL) // as we might want to switch renderer types
+ {
+ for (int i = 0; i < StaticObjectStates.Count; i++)
+ {
+ VAOExtensions.CreateVAO(StaticObjectStates[i].Prototype.Mesh, false, renderer.DefaultShader.VertexLayout, renderer);
+ }
+ for (int i = 0; i < DynamicObjectStates.Count; i++)
+ {
+ VAOExtensions.CreateVAO(DynamicObjectStates[i].Prototype.Mesh, false, renderer.DefaultShader.VertexLayout, renderer);
+ }
+ }
+ ObjectsSortedByStart = StaticObjectStates.Select((x, i) => new { Index = i, Distance = x.StartingDistance }).OrderBy(x => x.Distance).Select(x => x.Index).ToArray();
+ ObjectsSortedByEnd = StaticObjectStates.Select((x, i) => new { Index = i, Distance = x.EndingDistance }).OrderBy(x => x.Distance).Select(x => x.Index).ToArray();
+ ObjectsSortedByStartPointer = 0;
+ ObjectsSortedByEndPointer = 0;
+
+ if (renderer.currentOptions.ObjectDisposalMode == ObjectDisposalMode.QuadTree)
+ {
+ foreach (ObjectState state in StaticObjectStates)
+ {
+ VisibleObjects.quadTree.Add(state, Orientation3.Default);
+ }
+ VisibleObjects.quadTree.Initialize(renderer.currentOptions.QuadTreeLeafSize);
+ UpdateQuadTreeVisibility();
+ }
+ else
+ {
+ double p = renderer.CameraTrackFollower.TrackPosition + renderer.Camera.Alignment.Position.Z;
+ foreach (ObjectState state in StaticObjectStates.Where(recipe => recipe.StartingDistance <= p + renderer.Camera.ForwardViewingDistance & recipe.EndingDistance >= p - renderer.Camera.BackwardViewingDistance))
+ {
+ VisibleObjects.ShowObject(state, ObjectType.Static);
+ }
+ }
+ }
+
+ public void Reset()
+ {
+ renderer.currentHost.AnimatedObjectCollectionCache.Clear();
+ List> keys = renderer.currentHost.StaticObjectCache.Keys.ToList();
+ for (int i = 0; i < keys.Count; i++)
+ {
+ if (!System.IO.File.Exists(keys[i].Item1) || System.IO.File.GetLastWriteTime(keys[i].Item1) != keys[i].Item3)
+ {
+ renderer.currentHost.StaticObjectCache.Remove(keys[i]);
+ }
+ }
+ renderer.TextureManager.UnloadAllTextures(true);
+ VisibleObjects.Clear();
+ }
+ }
+}
diff --git a/source/LibRender2/Objects/ObjectLibrary.cs b/source/LibRender2/Objects/ObjectLibrary.cs
index a0d5dfc02e..a3b487bcea 100644
--- a/source/LibRender2/Objects/ObjectLibrary.cs
+++ b/source/LibRender2/Objects/ObjectLibrary.cs
@@ -83,8 +83,8 @@ public void Clear()
myAlphaFaces.Clear();
myOverlayOpaqueFaces.Clear();
myOverlayAlphaFaces.Clear();
- renderer.StaticObjectStates.Clear();
- renderer.DynamicObjectStates.Clear();
+ renderer.Scene.StaticObjectStates = new List();
+ renderer.Scene.DynamicObjectStates = new List();
}
}
diff --git a/source/LibRender2/Passes/GeometryPass.cs b/source/LibRender2/Passes/GeometryPass.cs
new file mode 100644
index 0000000000..1f55eb364d
--- /dev/null
+++ b/source/LibRender2/Passes/GeometryPass.cs
@@ -0,0 +1,129 @@
+using System.Collections.Generic;
+using System.Linq;
+using LibRender2.Objects;
+using LibRender2.Pipeline;
+using OpenBveApi.Graphics;
+using OpenBveApi.Interface;
+using OpenBveApi.Objects;
+using OpenTK.Graphics.OpenGL;
+
+namespace LibRender2.Passes
+{
+ ///
+ /// Renders the opaque and alpha-tested world geometry.
+ ///
+ public class GeometryPass : IRenderPass
+ {
+ public void Execute(RenderContext context)
+ {
+ BaseRenderer renderer = context.Renderer;
+
+ // 1. Setup lighting and fog for world geometry
+ if (renderer.AvailableNewRenderer)
+ {
+ if (renderer.OptionLighting)
+ {
+ renderer.DefaultShader.SetIsLight(true);
+ renderer.DefaultShader.SetLightPosition(renderer.TransformedLightPosition);
+ renderer.DefaultShader.SetLightAmbient(renderer.Lighting.OptionAmbientColor);
+ renderer.DefaultShader.SetLightDiffuse(renderer.Lighting.OptionDiffuseColor);
+ renderer.DefaultShader.SetLightSpecular(renderer.Lighting.OptionSpecularColor);
+ renderer.DefaultShader.SetLightModel(renderer.Lighting.LightModel);
+ }
+ renderer.Fog.Set();
+ renderer.DefaultShader.SetTexture(0);
+ renderer.DefaultShader.SetCurrentProjectionMatrix(context.ProjectionMatrix);
+ renderer.BindCSMToDefaultShader();
+ }
+
+ renderer.ResetOpenGlState();
+
+ if (renderer.OptionWireFrame)
+ {
+ GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
+ }
+
+ List opaqueFaces, alphaFaces;
+ lock (renderer.Scene.VisibleObjects.LockObject)
+ {
+ opaqueFaces = renderer.Scene.VisibleObjects.OpaqueFaces.ToList();
+ alphaFaces = renderer.Scene.VisibleObjects.GetSortedPolygons();
+ }
+
+ // 2. Render Opaque Faces
+ foreach (FaceState face in opaqueFaces)
+ {
+ face.Draw();
+ }
+
+ // 3. Render Alpha Faces
+ renderer.ResetOpenGlState();
+
+ if (renderer.currentOptions.TransparencyMode == TransparencyMode.Performance)
+ {
+ renderer.SetBlendFunc();
+ renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
+ renderer.Device.SetDepthMask(false);
+
+ foreach (FaceState face in alphaFaces)
+ {
+ face.Draw();
+ }
+ }
+ else
+ {
+ // Quality Transparency Mode
+ renderer.UnsetBlendFunc();
+ renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
+ renderer.Device.SetDepthMask(true);
+
+ foreach (FaceState face in alphaFaces)
+ {
+ var material = face.Object.Prototype.Mesh.Materials[face.Face.Material];
+ if (material.BlendMode == MeshMaterialBlendMode.Normal && material.GlowAttenuationData == 0)
+ {
+ if (material.Color.A == 255)
+ {
+ face.Draw();
+ }
+ }
+ }
+
+ renderer.SetBlendFunc();
+ renderer.SetAlphaFunc(AlphaFunction.Less, 1.0f);
+ renderer.Device.SetDepthMask(false);
+ bool additive = false;
+
+ foreach (FaceState face in alphaFaces)
+ {
+ var material = face.Object.Prototype.Mesh.Materials[face.Face.Material];
+ if (material.BlendMode == MeshMaterialBlendMode.Additive)
+ {
+ if (!additive)
+ {
+ renderer.UnsetAlphaFunc();
+ additive = true;
+ }
+ }
+ else
+ {
+ if (additive)
+ {
+ renderer.SetAlphaFunc();
+ additive = false;
+ }
+ }
+ face.Draw();
+ }
+ }
+
+ // Restore default depth mask
+ renderer.Device.SetDepthMask(true);
+
+ if (renderer.OptionWireFrame)
+ {
+ GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
+ }
+ }
+ }
+}
diff --git a/source/LibRender2/Passes/OverlayPass.cs b/source/LibRender2/Passes/OverlayPass.cs
new file mode 100644
index 0000000000..c193220f02
--- /dev/null
+++ b/source/LibRender2/Passes/OverlayPass.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using LibRender2.Cameras;
+using LibRender2.Objects;
+using LibRender2.Pipeline;
+using LibRender2.Viewports;
+using OpenBveApi.Colors;
+using OpenBveApi.Graphics;
+using OpenBveApi.Interface;
+using OpenBveApi.Math;
+using OpenBveApi.Objects;
+using OpenTK.Graphics.OpenGL;
+
+namespace LibRender2.Passes
+{
+ ///
+ /// Renders the overlays, including the train cab (2D/3D) and the user interface.
+ ///
+ public class OverlayPass : IRenderPass
+ {
+ private readonly Action renderUiAction;
+
+ ///
+ /// Initializes a new OverlayPass.
+ ///
+ /// A callback to render the application-specific UI.
+ public OverlayPass(Action renderUiAction)
+ {
+ this.renderUiAction = renderUiAction;
+ }
+
+ public void Execute(RenderContext context)
+ {
+ BaseRenderer renderer = context.Renderer;
+
+ // 1. Setup for Cab/Interior layer
+ renderer.Fog.Enabled = false;
+ renderer.UpdateViewport(ViewportChangeMode.ChangeToCab);
+
+ if (renderer.AvailableNewRenderer)
+ {
+ renderer.DefaultShader.Activate();
+ renderer.ResetShader(renderer.DefaultShader);
+ renderer.DefaultShader.SetCurrentProjectionMatrix(renderer.CurrentProjectionMatrix);
+ }
+
+ context.ViewMatrix = Matrix4D.LookAt(Vector3.Zero, new Vector3(context.Camera.AbsoluteDirection.X, context.Camera.AbsoluteDirection.Y, -context.Camera.AbsoluteDirection.Z), new Vector3(context.Camera.AbsoluteUp.X, context.Camera.AbsoluteUp.Y, -context.Camera.AbsoluteUp.Z));
+
+ List overlayOpaqueFaces, overlayAlphaFaces;
+ lock (renderer.Scene.VisibleObjects.LockObject)
+ {
+ overlayOpaqueFaces = renderer.Scene.VisibleObjects.OverlayOpaqueFaces.ToList();
+ overlayAlphaFaces = renderer.Scene.VisibleObjects.GetSortedPolygons(true);
+ }
+
+ if (context.Camera.CurrentRestriction == CameraRestrictionMode.NotAvailable || context.Camera.CurrentRestriction == CameraRestrictionMode.Restricted3D)
+ {
+ // 3D Cab Rendering
+ renderer.ResetOpenGlState();
+ GL.Clear(ClearBufferMask.DepthBufferBit);
+ renderer.OptionLighting = true;
+
+ Color24 prevOptionAmbientColor = renderer.Lighting.OptionAmbientColor;
+ Color24 prevOptionDiffuseColor = renderer.Lighting.OptionDiffuseColor;
+ renderer.Lighting.OptionAmbientColor = Color24.LightGrey;
+ renderer.Lighting.OptionDiffuseColor = Color24.LightGrey;
+
+ if (renderer.AvailableNewRenderer)
+ {
+ renderer.DefaultShader.SetIsLight(true);
+ Vector3 lightPos = new Vector3(renderer.Lighting.OptionLightPosition.X, renderer.Lighting.OptionLightPosition.Y, -renderer.Lighting.OptionLightPosition.Z);
+ renderer.DefaultShader.SetLightPosition(lightPos);
+ renderer.DefaultShader.SetLightAmbient(renderer.Lighting.OptionAmbientColor);
+ renderer.DefaultShader.SetLightDiffuse(renderer.Lighting.OptionDiffuseColor);
+ renderer.DefaultShader.SetLightSpecular(renderer.Lighting.OptionSpecularColor);
+ renderer.DefaultShader.SetLightModel(renderer.Lighting.LightModel);
+ }
+
+ // Render opaque faces
+ foreach (FaceState face in overlayOpaqueFaces)
+ {
+ face.Draw();
+ }
+
+ // Render alpha faces
+ renderer.ResetOpenGlState();
+ if (renderer.currentOptions.TransparencyMode == TransparencyMode.Performance)
+ {
+ renderer.SetBlendFunc();
+ renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
+ renderer.Device.SetDepthMask(false);
+
+ foreach (FaceState face in overlayAlphaFaces)
+ {
+ face.Draw();
+ }
+ }
+ else
+ {
+ renderer.UnsetBlendFunc();
+ renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
+ renderer.Device.SetDepthMask(true);
+
+ foreach (FaceState face in overlayAlphaFaces)
+ {
+ var material = face.Object.Prototype.Mesh.Materials[face.Face.Material];
+ if (material.BlendMode == MeshMaterialBlendMode.Normal && material.GlowAttenuationData == 0)
+ {
+ if (material.Color.A == 255)
+ {
+ face.Draw();
+ }
+ }
+ }
+
+ renderer.SetBlendFunc();
+ renderer.SetAlphaFunc(AlphaFunction.Less, 1.0f);
+ renderer.Device.SetDepthMask(false);
+ bool additive = false;
+
+ foreach (FaceState face in overlayAlphaFaces)
+ {
+ var material = face.Object.Prototype.Mesh.Materials[face.Face.Material];
+ if (material.BlendMode == MeshMaterialBlendMode.Additive)
+ {
+ if (!additive)
+ {
+ renderer.UnsetAlphaFunc();
+ additive = true;
+ }
+ }
+ else
+ {
+ if (additive)
+ {
+ renderer.SetAlphaFunc();
+ additive = false;
+ }
+ }
+ face.Draw();
+ }
+ }
+
+ renderer.Lighting.OptionAmbientColor = prevOptionAmbientColor;
+ renderer.Lighting.OptionDiffuseColor = prevOptionDiffuseColor;
+ renderer.Lighting.Initialize();
+ }
+ else
+ {
+ // 2D Cab Rendering
+ renderer.ResetOpenGlState();
+ renderer.OptionLighting = false;
+ if (renderer.AvailableNewRenderer)
+ {
+ renderer.DefaultShader.SetIsLight(false);
+ }
+
+ renderer.SetBlendFunc();
+ renderer.UnsetAlphaFunc();
+ renderer.Device.SetDepthTest(false);
+ renderer.Device.SetDepthMask(false);
+
+ foreach (FaceState face in overlayAlphaFaces)
+ {
+ face.Draw();
+ }
+ }
+
+ // 2. Render UI and other overlays
+ renderer.OptionLighting = false;
+ renderer.ResetOpenGlState();
+ renderer.UnsetAlphaFunc();
+ renderer.SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
+ renderer.Device.SetDepthTest(false);
+
+ renderUiAction?.Invoke(context);
+
+ renderer.OptionLighting = true;
+ }
+ }
+}
diff --git a/source/LibRender2/Passes/ShadowPass.cs b/source/LibRender2/Passes/ShadowPass.cs
new file mode 100644
index 0000000000..afb3a800c3
--- /dev/null
+++ b/source/LibRender2/Passes/ShadowPass.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Collections.Generic;
+using LibRender2.Objects;
+using LibRender2.Pipeline;
+using LibRender2.Shaders;
+using OpenBveApi.Graphics;
+using OpenBveApi.Interface;
+using OpenBveApi.Math;
+using OpenBveApi.Objects;
+using OpenBveApi.Textures;
+using OpenTK.Graphics.OpenGL;
+
+namespace LibRender2.Passes
+{
+ ///
+ /// Performs the Cascaded Shadow Map (CSM) shadow depth rendering pass.
+ ///
+ public class ShadowPass : IRenderPass
+ {
+ public void Execute(RenderContext context)
+ {
+ BaseRenderer renderer = context.Renderer;
+
+ if (!renderer.ShadowsEnabled || renderer.CSMShadowMaps == null || renderer.CSMCaster == null || renderer.ShadowDepthShaderProgram == null)
+ return;
+
+ // 1. Get light direction pointing FROM the sun TOWARD the scene
+ Vector3 lightDir = new Vector3(
+ -renderer.Lighting.OptionLightPosition.X,
+ -renderer.Lighting.OptionLightPosition.Y,
+ renderer.Lighting.OptionLightPosition.Z
+ );
+
+ if (lightDir.IsNullVector())
+ {
+ return;
+ }
+
+ // 2. Update cascade matrices
+ renderer.CSMCaster.Resolution = renderer.CSMShadowMaps.Resolution;
+ if (renderer.currentOptions.ShadowDrawDistance == ShadowDistance.ViewingDistance)
+ {
+ renderer.CSMCaster.ShadowDistance = renderer.currentOptions.ViewingDistance;
+ }
+ else
+ {
+ renderer.CSMCaster.ShadowDistance = (double)renderer.currentOptions.ShadowDrawDistance;
+ }
+ renderer.CSMCaster.Update(lightDir, context.ViewMatrix, context.ProjectionMatrix, 0.1, context.Camera.VerticalViewingAngle, renderer.Screen.AspectRatio);
+
+ // 3. Setup rendering state
+ renderer.CurrentShader?.Deactivate();
+ renderer.ShadowDepthShaderProgram.Activate();
+
+ renderer.Device.SetDepthTest(true, DepthFunction.Less);
+ renderer.Device.SetCullFace(false);
+ renderer.Device.SetDepthMask(true);
+
+ renderer.ShadowDepthShaderProgram.SetTexture(0); // always use texture unit 0
+
+ for (int cascade = 0; cascade < renderer.CSMCaster.CascadeCount; cascade++)
+ {
+ renderer.CSMShadowMaps.BindCascadeForWriting(cascade);
+ GL.Clear(ClearBufferMask.DepthBufferBit);
+ renderer.ShadowDepthShaderProgram.SetLightSpaceMatrix(renderer.CSMCaster.LightSpaceMatrices[cascade]);
+
+ lock (renderer.Scene.VisibilityUpdateLock)
+ {
+ int lastVAOHandle = -1;
+
+ Action> renderFaces = faces =>
+ {
+ foreach (var face in faces)
+ {
+ if (face.Object.Prototype.Mesh.VAO == null) continue;
+ if (face.Object.DisableShadowCasting) continue;
+
+ Matrix4D modelMatrix = face.Object.ModelMatrix * context.Camera.TranslationMatrix;
+ renderer.ShadowDepthShaderProgram.SetModelMatrix(modelMatrix);
+
+ // Bind texture for alpha scissoring if the face has one
+ var material = face.Object.Prototype.Mesh.Materials[face.Face.Material];
+ if (material.DaytimeTexture != null && renderer.currentHost.LoadTexture(ref material.DaytimeTexture, (OpenGlTextureWrapMode)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)))
+ {
+ GL.ActiveTexture(TextureUnit.Texture0);
+ GL.BindTexture(TextureTarget.Texture2D,
+ material.DaytimeTexture.OpenGlTextures[(int)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)].Name);
+ renderer.ShadowDepthShaderProgram.SetHasTexture(true);
+ }
+ else
+ {
+ renderer.ShadowDepthShaderProgram.SetHasTexture(false);
+ }
+
+ renderer.ShadowDepthShaderProgram.SetAlphaCutoff(0.5f);
+ renderer.ShadowDepthShaderProgram.SetMaterialAlpha(material.Color.A / 255.0f);
+ renderer.ShadowDepthShaderProgram.SetMaterialFlags(material.Flags);
+
+#pragma warning disable CS0618
+ ObjectState state = face.Object;
+ if (state.Matricies != null && state.Matricies.Length > 0)
+ {
+ renderer.ShadowDepthShaderProgram.SetCurrentAnimationMatricies(state);
+ GL.BindBufferBase(BufferTarget.UniformBuffer, 0, state.MatrixBufferIndex);
+ }
+#pragma warning restore CS0618
+
+ VertexArrayObject vao = (VertexArrayObject)face.Object.Prototype.Mesh.VAO;
+ if (vao.handle != lastVAOHandle)
+ {
+ vao.Bind();
+ lastVAOHandle = vao.handle;
+ }
+
+ // We need GetPrimitiveType, but it's protected in BaseRenderer.
+ // For now, I'll copy the logic or we should move it to a helper.
+ PrimitiveType drawMode = GetPrimitiveType(face.Face.Flags);
+ vao.Draw(drawMode, face.Face.IboStartIndex, face.Face.Vertices.Length);
+ }
+ };
+
+ renderFaces(renderer.Scene.VisibleObjects.OpaqueFaces);
+ renderFaces(renderer.Scene.VisibleObjects.AlphaFaces);
+ }
+ renderer.CSMShadowMaps.Unbind();
+ }
+
+ // 4. Restore state
+ renderer.Device.SetDepthTest(true, DepthFunction.Lequal);
+ renderer.Device.SetCullFace(true, CullFaceMode.Front);
+ GL.Viewport(0, 0, renderer.Screen.Width, renderer.Screen.Height);
+
+ renderer.LastBoundTexture = null;
+ }
+
+ private PrimitiveType GetPrimitiveType(FaceFlags flags)
+ {
+ switch (flags & FaceFlags.FaceTypeMask)
+ {
+ case FaceFlags.Triangles: return PrimitiveType.Triangles;
+ case FaceFlags.TriangleStrip: return PrimitiveType.TriangleStrip;
+ case FaceFlags.Quads: return PrimitiveType.Quads;
+ case FaceFlags.QuadStrip: return PrimitiveType.QuadStrip;
+ default: return PrimitiveType.Polygon;
+ }
+ }
+ }
+}
diff --git a/source/LibRender2/Passes/SkyPass.cs b/source/LibRender2/Passes/SkyPass.cs
new file mode 100644
index 0000000000..6ba7d9f265
--- /dev/null
+++ b/source/LibRender2/Passes/SkyPass.cs
@@ -0,0 +1,38 @@
+using System;
+using LibRender2.Pipeline;
+using OpenTK.Graphics.OpenGL;
+
+namespace LibRender2.Passes
+{
+ ///
+ /// Renders the background/sky.
+ ///
+ public class SkyPass : IRenderPass
+ {
+ private readonly Action updateBackgroundAction;
+
+ ///
+ /// Initializes a new SkyPass.
+ ///
+ /// A callback to update and render the background.
+ /// This is usually handled by the application-specific route data.
+ public SkyPass(Action updateBackgroundAction)
+ {
+ this.updateBackgroundAction = updateBackgroundAction;
+ }
+
+ public void Execute(RenderContext context)
+ {
+ BaseRenderer renderer = context.Renderer;
+
+ // Background must be rendered with depth testing disabled and no shadow mapping
+ renderer.Device.SetDepthTest(false);
+ renderer.DefaultShader.SetShadowEnabled(false);
+
+ updateBackgroundAction?.Invoke(context);
+
+ renderer.DefaultShader.SetShadowEnabled(renderer.ShadowsEnabled);
+ renderer.Device.SetDepthTest(true);
+ }
+ }
+}
diff --git a/source/LibRender2/Pipeline/GraphicsDevice.cs b/source/LibRender2/Pipeline/GraphicsDevice.cs
new file mode 100644
index 0000000000..b717ef3c79
--- /dev/null
+++ b/source/LibRender2/Pipeline/GraphicsDevice.cs
@@ -0,0 +1,114 @@
+using OpenTK.Graphics.OpenGL;
+
+namespace LibRender2.Pipeline
+{
+ ///
+ /// Manages and caches the OpenGL state to prevent redundant API calls.
+ ///
+ public class GraphicsDevice
+ {
+ private bool blendEnabled;
+ private BlendingFactor blendSrcFactor;
+ private BlendingFactor blendDestFactor;
+
+ private bool depthTestEnabled = true;
+ private DepthFunction depthFunction = DepthFunction.Lequal;
+ private bool depthMask = true;
+
+ private bool cullFaceEnabled = true;
+ private CullFaceMode cullFaceMode = CullFaceMode.Front;
+
+ ///
+ /// Sets the blending state.
+ ///
+ public void SetBlend(bool enabled, BlendingFactor src = BlendingFactor.SrcAlpha, BlendingFactor dest = BlendingFactor.OneMinusSrcAlpha)
+ {
+ if (blendEnabled != enabled)
+ {
+ blendEnabled = enabled;
+ if (enabled) GL.Enable(EnableCap.Blend);
+ else GL.Disable(EnableCap.Blend);
+ }
+
+ if (enabled && (blendSrcFactor != src || blendDestFactor != dest))
+ {
+ blendSrcFactor = src;
+ blendDestFactor = dest;
+ GL.BlendFunc(src, dest);
+ }
+ }
+
+ ///
+ /// Sets the depth test state.
+ ///
+ public void SetDepthTest(bool enabled, DepthFunction function = DepthFunction.Lequal)
+ {
+ if (depthTestEnabled != enabled)
+ {
+ depthTestEnabled = enabled;
+ if (enabled) GL.Enable(EnableCap.DepthTest);
+ else GL.Disable(EnableCap.DepthTest);
+ }
+
+ if (enabled && depthFunction != function)
+ {
+ depthFunction = function;
+ GL.DepthFunc(function);
+ }
+ }
+
+ ///
+ /// Sets whether depth writing is enabled.
+ ///
+ public void SetDepthMask(bool enabled)
+ {
+ if (depthMask != enabled)
+ {
+ depthMask = enabled;
+ GL.DepthMask(enabled);
+ }
+ }
+
+ ///
+ /// Sets the face culling state.
+ ///
+ public void SetCullFace(bool enabled, CullFaceMode mode = CullFaceMode.Front)
+ {
+ if (cullFaceEnabled != enabled)
+ {
+ cullFaceEnabled = enabled;
+ if (enabled) GL.Enable(EnableCap.CullFace);
+ else GL.Disable(EnableCap.CullFace);
+ }
+
+ if (enabled && cullFaceMode != mode)
+ {
+ cullFaceMode = mode;
+ GL.CullFace(mode);
+ }
+ }
+
+ ///
+ /// Resets the cached state to match the current OpenGL defaults or a known state.
+ ///
+ public void Reset()
+ {
+ // Reset to OpenGL defaults
+ GL.Disable(EnableCap.Blend);
+ blendEnabled = false;
+
+ GL.Enable(EnableCap.DepthTest);
+ depthTestEnabled = true;
+ GL.DepthFunc(DepthFunction.Less);
+ depthFunction = DepthFunction.Less;
+
+ GL.DepthMask(true);
+ depthMask = true;
+
+ GL.Enable(EnableCap.CullFace);
+ cullFaceEnabled = true;
+ GL.CullFace(CullFaceMode.Back);
+ cullFaceMode = CullFaceMode.Back;
+ }
+ }
+}
diff --git a/source/LibRender2/Pipeline/IRenderPass.cs b/source/LibRender2/Pipeline/IRenderPass.cs
new file mode 100644
index 0000000000..96518fb55e
--- /dev/null
+++ b/source/LibRender2/Pipeline/IRenderPass.cs
@@ -0,0 +1,14 @@
+namespace LibRender2.Pipeline
+{
+ ///
+ /// Represents a single stage in the rendering pipeline.
+ ///
+ public interface IRenderPass
+ {
+ ///
+ /// Executes the rendering logic for this pass.
+ ///
+ /// The current rendering context.
+ void Execute(RenderContext context);
+ }
+}
diff --git a/source/LibRender2/Pipeline/RenderContext.cs b/source/LibRender2/Pipeline/RenderContext.cs
new file mode 100644
index 0000000000..b8eb47a415
--- /dev/null
+++ b/source/LibRender2/Pipeline/RenderContext.cs
@@ -0,0 +1,41 @@
+using OpenBveApi.Math;
+using OpenBveApi.Objects;
+using LibRender2.Cameras;
+using LibRender2.Lightings;
+using LibRender2.Passes;
+
+namespace LibRender2.Pipeline
+{
+ ///
+ /// Contains all necessary information for a single frame rendering pass.
+ ///
+ public class RenderContext
+ {
+ /// The current projection matrix.
+ public Matrix4D ProjectionMatrix;
+
+ /// The current view matrix.
+ public Matrix4D ViewMatrix;
+
+ /// The current camera properties.
+ public CameraProperties Camera;
+
+ /// The current lighting properties.
+ public Lighting Lighting;
+
+ /// The time elapsed since the last frame in seconds.
+ public double TimeElapsed;
+
+ /// The real-time elapsed since the last frame in seconds.
+ public double RealTimeElapsed;
+
+ /// The renderer instance.
+ public BaseRenderer Renderer;
+
+ public RenderContext(BaseRenderer renderer, double timeElapsed)
+ {
+ Renderer = renderer;
+ TimeElapsed = timeElapsed;
+ }
+ }
+}
diff --git a/source/LibRender2/Pipeline/RenderPipeline.cs b/source/LibRender2/Pipeline/RenderPipeline.cs
new file mode 100644
index 0000000000..0303de430c
--- /dev/null
+++ b/source/LibRender2/Pipeline/RenderPipeline.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+
+namespace LibRender2.Pipeline
+{
+ ///
+ /// Orchestrates the execution of multiple rendering passes.
+ ///
+ public class RenderPipeline
+ {
+ ///
+ /// The list of passes in this pipeline, executed in order.
+ ///
+ public readonly List Passes = new List();
+
+ ///
+ /// Executes all registered passes in the pipeline.
+ ///
+ /// The current rendering context.
+ public void Execute(RenderContext context)
+ {
+ foreach (var pass in Passes)
+ {
+ pass.Execute(context);
+ }
+ }
+
+ ///
+ /// Adds a pass to the end of the pipeline.
+ ///
+ public void AddPass(IRenderPass pass)
+ {
+ Passes.Add(pass);
+ }
+
+ ///
+ /// Clears all passes from the pipeline.
+ ///
+ public void Clear()
+ {
+ Passes.Clear();
+ }
+ }
+}
diff --git a/source/LibRender2/Primitives/Rectangle.cs b/source/LibRender2/Primitives/Rectangle.cs
index 93f0965064..fec60ae9c7 100644
--- a/source/LibRender2/Primitives/Rectangle.cs
+++ b/source/LibRender2/Primitives/Rectangle.cs
@@ -86,11 +86,11 @@ public void DrawAlpha(Texture texture, Vector2 point, Color128? color = null, Ve
}
renderer.UnsetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
- GL.DepthMask(true);
+ renderer.Device.SetDepthMask(true);
Draw(texture, point, texture.Size, color, textureCoordinates);
renderer.SetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Less, 1.0f);
- GL.DepthMask(false);
+ renderer.Device.SetDepthMask(false);
Draw(texture, point, texture.Size, color, textureCoordinates);
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
}
diff --git a/source/LibRender2/Smoke/ParticleSource.cs b/source/LibRender2/Smoke/ParticleSource.cs
index feef0566be..542b5f2841 100644
--- a/source/LibRender2/Smoke/ParticleSource.cs
+++ b/source/LibRender2/Smoke/ParticleSource.cs
@@ -1,4 +1,4 @@
-//Simplified BSD License (BSD-2-Clause)
+//Simplified BSD License (BSD-2-Clause)
//
//Copyright (c) 2025, The OpenBVE Project
//
diff --git a/source/LibRender2/openGL/IndexBufferObject.cs b/source/LibRender2/openGL/IndexBufferObject.cs
index 0fde7825e1..288fe6bd0e 100644
--- a/source/LibRender2/openGL/IndexBufferObject.cs
+++ b/source/LibRender2/openGL/IndexBufferObject.cs
@@ -71,10 +71,7 @@ public void Dispose()
return;
}
- lock (BaseRenderer.iboToDelete)
- {
- BaseRenderer.iboToDelete.Add(handle);
- }
+ Managers.GpuResourceManager.QueueIboForDeletion(handle);
}
}
diff --git a/source/LibRender2/openGL/VertexArrayObject.cs b/source/LibRender2/openGL/VertexArrayObject.cs
index 24784cc690..06cb1e83ae 100644
--- a/source/LibRender2/openGL/VertexArrayObject.cs
+++ b/source/LibRender2/openGL/VertexArrayObject.cs
@@ -153,10 +153,7 @@ public void Dispose()
return;
}
- lock (BaseRenderer.vaoToDelete)
- {
- BaseRenderer.vaoToDelete.Add(handle);
- }
+ Managers.GpuResourceManager.QueueVaoForDeletion(handle);
}
}
diff --git a/source/LibRender2/openGL/VertexBufferObject.cs b/source/LibRender2/openGL/VertexBufferObject.cs
index 490d085936..fe7e5225da 100644
--- a/source/LibRender2/openGL/VertexBufferObject.cs
+++ b/source/LibRender2/openGL/VertexBufferObject.cs
@@ -172,10 +172,7 @@ public void Dispose()
return;
}
- lock (BaseRenderer.vboToDelete)
- {
- BaseRenderer.vboToDelete.Add(handle);
- }
+ Managers.GpuResourceManager.QueueVboForDeletion(handle);
}
}
}
diff --git a/source/ObjectViewer/Graphics/NewRendererS.cs b/source/ObjectViewer/Graphics/NewRendererS.cs
index bccff7d620..4731dfe460 100644
--- a/source/ObjectViewer/Graphics/NewRendererS.cs
+++ b/source/ObjectViewer/Graphics/NewRendererS.cs
@@ -4,6 +4,8 @@
using System.Linq;
using System.Windows.Forms;
using LibRender2;
+using LibRender2.Pipeline;
+using LibRender2.Passes;
using LibRender2.Objects;
using LibRender2.Primitives;
using LibRender2.Screens;
@@ -51,6 +53,16 @@ public override void Initialize()
greenAxisVAO = new Cube(this, Color128.Green);
blueAxisVAO = new Cube(this, Color128.Blue);
}
+
+ // Initialize Pipeline
+ Pipeline.Clear();
+ Pipeline.AddPass(new ShadowPass());
+ Pipeline.AddPass(new GeometryPass());
+ Pipeline.AddPass(new OverlayPass(ctx => RenderOverlays(ctx.TimeElapsed)));
+
+ // Set the viewing distance for ObjectViewer from options
+ Camera.ForwardViewingDistance = currentOptions.ViewingDistance;
+ Camera.BackwardViewingDistance = currentOptions.ViewingDistance;
}
internal string GetBackgroundColorName()
@@ -144,105 +156,10 @@ internal void RenderScene(double timeElapsed)
Cube.Draw(Vector3.Zero, Vector3.Forward, Vector3.Down, Vector3.Right, new Vector3(0.01, 0.01, 100.0), Camera.AbsolutePosition, null);
}
}
- // opaque face
- if (AvailableNewRenderer)
- {
- PerformCSMShadowPass();
- //Setup the shader for rendering the scene
- DefaultShader.Activate();
- BindCSMToDefaultShader();
- if (OptionLighting)
- {
- DefaultShader.SetIsLight(true);
- DefaultShader.SetLightPosition(TransformedLightPosition);
- DefaultShader.SetLightAmbient(Lighting.OptionAmbientColor);
- DefaultShader.SetLightDiffuse(Lighting.OptionDiffuseColor);
- DefaultShader.SetLightSpecular(Lighting.OptionSpecularColor);
- DefaultShader.SetLightModel(Lighting.LightModel);
- }
- DefaultShader.SetTexture(0);
- DefaultShader.SetCurrentProjectionMatrix(CurrentProjectionMatrix);
- }
- ResetOpenGlState();
- List opaqueFaces, alphaFaces;
- lock (VisibleObjects.LockObject)
- {
- opaqueFaces = VisibleObjects.OpaqueFaces.ToList();
- alphaFaces = VisibleObjects.GetSortedPolygons();
- }
-
- foreach (FaceState face in opaqueFaces)
- {
- face.Draw();
- }
-
- // alpha face
- ResetOpenGlState();
-
- if (Interface.CurrentOptions.TransparencyMode == TransparencyMode.Performance)
- {
- SetBlendFunc();
- SetAlphaFunc(AlphaFunction.Greater, 0.0f);
- GL.DepthMask(false);
-
- foreach (FaceState face in alphaFaces)
- {
- face.Draw();
- }
- }
- else
- {
- UnsetBlendFunc();
- SetAlphaFunc(AlphaFunction.Equal, 1.0f);
- GL.DepthMask(true);
-
- foreach (FaceState face in alphaFaces)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].BlendMode == MeshMaterialBlendMode.Normal && face.Object.Prototype.Mesh.Materials[face.Face.Material].GlowAttenuationData == 0)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].Color.A == 255)
- {
- face.Draw();
- }
- }
- }
-
- SetBlendFunc();
- SetAlphaFunc(AlphaFunction.Less, 1.0f);
- GL.DepthMask(false);
- bool additive = false;
-
- foreach (FaceState face in alphaFaces)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].BlendMode == MeshMaterialBlendMode.Additive)
- {
- if (!additive)
- {
- UnsetAlphaFunc();
- additive = true;
- }
-
- face.Draw();
- }
- else
- {
- if (additive)
- {
- SetAlphaFunc();
- additive = false;
- }
-
- face.Draw();
- }
- }
- }
-
- if (AvailableNewRenderer)
- {
- DefaultShader.Deactivate();
- lastVAO = -1;
- }
+ // Execute Pipeline
+ RenderContext context = new RenderContext(this, timeElapsed);
+ ExecutePipeline(context);
// render overlays
ResetOpenGlState();
@@ -270,7 +187,7 @@ private void RenderOverlays(double timeElapsed)
{
string[][] keys;
int objectCount, animatedObjectsUsed, opaqueFaces, alphaFaces;
- lock (VisibilityUpdateLock)
+ lock (Scene.VisibilityUpdateLock)
{
objectCount = VisibleObjects.Objects.Count;
animatedObjectsUsed = ObjectManager.AnimatedWorldObjectsUsed;
diff --git a/source/ObjectViewer/Options.cs b/source/ObjectViewer/Options.cs
index e8c69be319..35db07a558 100644
--- a/source/ObjectViewer/Options.cs
+++ b/source/ObjectViewer/Options.cs
@@ -95,6 +95,7 @@ public override void Save(string fileName)
Builder.AppendLine("shadownormalbias = " + ShadowNormalBias.ToString("0.00", Culture));
Builder.AppendLine("lightazimuth = " + LightAzimuth.ToString(Culture));
Builder.AppendLine("lightelevation = " + LightElevation.ToString(Culture));
+ Builder.AppendLine("viewingDistance = " + ViewingDistance.ToString(Culture));
Builder.AppendLine();
Builder.AppendLine("[Parsers]");
Builder.AppendLine("xObject = " + CurrentXParser);
@@ -125,7 +126,7 @@ internal static void LoadOptions()
{
Interface.CurrentOptions = new Options
{
- ViewingDistance = 1000, // fixed
+ ViewingDistance = 1000,
CameraMoveLeft = Key.A,
CameraMoveRight = Key.D,
CameraMoveUp = Key.W,
@@ -167,6 +168,7 @@ internal static void LoadOptions()
block.TryGetValue(OptionsKey.WindowHeight, ref Interface.CurrentOptions.WindowHeight, NumberRange.Positive);
block.GetValue(OptionsKey.IsUseNewRenderer, out Interface.CurrentOptions.IsUseNewRenderer);
block.GetValue(OptionsKey.AutoReloadObjects, out Interface.CurrentOptions.AutoReloadObjects);
+ block.TryGetValue(OptionsKey.ViewingDistance, ref Interface.CurrentOptions.ViewingDistance, NumberRange.Positive);
break;
case OptionsSection.Quality:
block.GetEnumValue(OptionsKey.Interpolation, out Interface.CurrentOptions.Interpolation);
@@ -181,6 +183,7 @@ internal static void LoadOptions()
block.TryGetValue(OptionsKey.ShadowNormalBias, ref Interface.CurrentOptions.ShadowNormalBias);
block.TryGetValue(OptionsKey.LightAzimuth, ref Interface.CurrentOptions.LightAzimuth);
block.TryGetValue(OptionsKey.LightElevation, ref Interface.CurrentOptions.LightElevation);
+ block.TryGetValue(OptionsKey.ViewingDistance, ref Interface.CurrentOptions.ViewingDistance, NumberRange.Positive);
break;
case OptionsSection.Parsers:
block.GetEnumValue(OptionsKey.XObject, out Interface.CurrentOptions.CurrentXParser);
diff --git a/source/ObjectViewer/ProgramS.cs b/source/ObjectViewer/ProgramS.cs
index b6d73b84c2..dacef61306 100644
--- a/source/ObjectViewer/ProgramS.cs
+++ b/source/ObjectViewer/ProgramS.cs
@@ -441,7 +441,7 @@ internal static void RefreshObjects(bool autoReload = false)
formTrain.Instance?.EnableUI();
Renderer.InitializeVisibility();
- Renderer.UpdateViewingDistances(600);
+ Renderer.UpdateViewingDistances(Interface.CurrentOptions.ViewingDistance);
Renderer.UpdateVisibility(true);
ObjectManager.UpdateAnimatedWorldObjects(0.01, true);
Program.TrainManager.UpdateTrainObjects(0.0, true);
diff --git a/source/ObjectViewer/formOptions.Designer.cs b/source/ObjectViewer/formOptions.Designer.cs
index f1be27bf12..92f23eab7d 100644
--- a/source/ObjectViewer/formOptions.Designer.cs
+++ b/source/ObjectViewer/formOptions.Designer.cs
@@ -51,6 +51,8 @@ private void InitializeComponent()
this.labelInterpolationMode = new System.Windows.Forms.Label();
this.labelInterpolationSettings = new System.Windows.Forms.Label();
this.InterpolationMode = new System.Windows.Forms.ComboBox();
+ this.labelViewingDistance = new System.Windows.Forms.Label();
+ this.numericUpDownViewingDistance = new System.Windows.Forms.NumericUpDown();
this.tabPageKeys = new System.Windows.Forms.TabPage();
this.labelControls = new System.Windows.Forms.Label();
this.comboBoxBackwards = new System.Windows.Forms.ComboBox();
@@ -140,6 +142,8 @@ private void InitializeComponent()
this.tabPageOptions.Controls.Add(this.labelInterpolationMode);
this.tabPageOptions.Controls.Add(this.labelInterpolationSettings);
this.tabPageOptions.Controls.Add(this.InterpolationMode);
+ this.tabPageOptions.Controls.Add(this.labelViewingDistance);
+ this.tabPageOptions.Controls.Add(this.numericUpDownViewingDistance);
this.tabPageOptions.AutoScroll = true;
this.tabPageOptions.Location = new System.Drawing.Point(4, 22);
this.tabPageOptions.Name = "tabPageOptions";
@@ -375,6 +379,37 @@ private void InitializeComponent()
this.labelInterpolationSettings.TabIndex = 27;
this.labelInterpolationSettings.Text = "Interpolation Settings";
//
+ // labelViewingDistance
+ //
+ this.labelViewingDistance.AutoSize = true;
+ this.labelViewingDistance.Location = new System.Drawing.Point(6, 131);
+ this.labelViewingDistance.Name = "labelViewingDistance";
+ this.labelViewingDistance.Size = new System.Drawing.Size(92, 13);
+ this.labelViewingDistance.TabIndex = 50;
+ this.labelViewingDistance.Text = "Viewing Distance:";
+ //
+ // numericUpDownViewingDistance
+ //
+ this.numericUpDownViewingDistance.Location = new System.Drawing.Point(160, 131);
+ this.numericUpDownViewingDistance.Maximum = new decimal(new int[] {
+ 100000,
+ 0,
+ 0,
+ 0});
+ this.numericUpDownViewingDistance.Minimum = new decimal(new int[] {
+ 10,
+ 0,
+ 0,
+ 0});
+ this.numericUpDownViewingDistance.Name = "numericUpDownViewingDistance";
+ this.numericUpDownViewingDistance.Size = new System.Drawing.Size(120, 20);
+ this.numericUpDownViewingDistance.TabIndex = 51;
+ this.numericUpDownViewingDistance.Value = new decimal(new int[] {
+ 600,
+ 0,
+ 0,
+ 0});
+ //
// InterpolationMode
//
this.InterpolationMode.FormattingEnabled = true;
@@ -811,6 +846,7 @@ private void InitializeComponent()
((System.ComponentModel.ISupportInitialize)(this.trackBarSunElevation)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDownShadowBias)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDownShadowNormalBias)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.numericUpDownViewingDistance)).EndInit();
this.tabPageKeys.ResumeLayout(false);
this.tabPageKeys.PerformLayout();
this.ResumeLayout(false);
@@ -879,5 +915,7 @@ private void InitializeComponent()
private System.Windows.Forms.NumericUpDown numericUpDownShadowNormalBias;
private System.Windows.Forms.CheckBox checkBoxAutoReload;
private System.Windows.Forms.Label labelAutoReloadChanged;
+ private System.Windows.Forms.Label labelViewingDistance;
+ private System.Windows.Forms.NumericUpDown numericUpDownViewingDistance;
}
}
diff --git a/source/ObjectViewer/formOptions.cs b/source/ObjectViewer/formOptions.cs
index e49b5b3750..71d73ec882 100644
--- a/source/ObjectViewer/formOptions.cs
+++ b/source/ObjectViewer/formOptions.cs
@@ -59,6 +59,7 @@ private formOptions()
numericUpDownShadowStrength.Value = (decimal)(Interface.CurrentOptions.ShadowStrength * 100.0);
numericUpDownShadowBias.Value = (decimal)Interface.CurrentOptions.ShadowBias;
numericUpDownShadowNormalBias.Value = (decimal)Interface.CurrentOptions.ShadowNormalBias;
+ numericUpDownViewingDistance.Value = (decimal)Interface.CurrentOptions.ViewingDistance;
if (numericUpDownShadowBias.Value == 0)
{
numericUpDownShadowBias.Value = 0.000050m;
@@ -271,6 +272,7 @@ private void CloseButton_Click(object sender, EventArgs e)
Interface.CurrentOptions.ShadowStrength = (double)numericUpDownShadowStrength.Value / 100.0;
Interface.CurrentOptions.ShadowBias = (double)numericUpDownShadowBias.Value;
Interface.CurrentOptions.ShadowNormalBias = (double)numericUpDownShadowNormalBias.Value;
+ Interface.CurrentOptions.ViewingDistance = (int)numericUpDownViewingDistance.Value;
Interface.CurrentOptions.Save(Path.CombineFile(Program.FileSystem.SettingsFolder, "1.5.0/options_ov.cfg"));
Program.RefreshObjects();
diff --git a/source/OpenBVE/Graphics/NewRenderer.cs b/source/OpenBVE/Graphics/NewRenderer.cs
index 5df189497c..20a027bf22 100644
--- a/source/OpenBVE/Graphics/NewRenderer.cs
+++ b/source/OpenBVE/Graphics/NewRenderer.cs
@@ -5,6 +5,8 @@
using LibRender2.Screens;
using LibRender2.Shaders;
using LibRender2.Viewports;
+using LibRender2.Pipeline;
+using LibRender2.Passes;
using OpenBve.Graphics.Renderers;
using OpenBveApi;
using OpenBveApi.Colors;
@@ -41,6 +43,10 @@ internal class NewRenderer : BaseRenderer
private Overlays overlays;
internal Touch Touch;
+ public NewRenderer(HostInterface currentHost, BaseOptions currentOptions, FileSystem fileSystem) : base(currentHost, currentOptions, fileSystem)
+ {
+ }
+
public override void Initialize()
{
base.Initialize();
@@ -67,13 +73,95 @@ public override void Initialize()
events = new Events(this);
overlays = new Overlays(this);
Touch = new Touch(this);
- ObjectsSortedByStart = new int[] { };
- ObjectsSortedByEnd = new int[] { };
-
-
+
+ // Initialize Pipeline
+ Pipeline.Clear();
+ Pipeline.AddPass(new ShadowPass());
+ Pipeline.AddPass(new SkyPass(UpdateBackground));
+ Pipeline.AddPass(new GeometryPass());
+ Pipeline.AddPass(new MotionBlurPass(this));
+ Pipeline.AddPass(new OverlayPass(RenderUI));
+ Pipeline.AddPass(new TouchPickingPass(this));
+
Program.FileSystem.AppendToLogFile("Renderer initialised successfully.");
}
-
+
+ private void UpdateBackground(RenderContext context)
+ {
+ Program.CurrentRoute.UpdateBackground(context.TimeElapsed, Program.Renderer.CurrentInterface != InterfaceType.Normal);
+
+ // fog setup
+ float aa = Program.CurrentRoute.CurrentFog.Start;
+ float bb = Program.CurrentRoute.CurrentFog.End;
+
+ if (aa < bb & aa < Program.CurrentRoute.CurrentBackground.BackgroundImageDistance)
+ {
+ Fog.Enabled = true;
+ Fog.Start = aa;
+ Fog.End = bb;
+ Fog.Color = Program.CurrentRoute.CurrentFog.Color;
+ Fog.Density = Program.CurrentRoute.CurrentFog.Density;
+ Fog.IsLinear = Program.CurrentRoute.CurrentFog.IsLinear;
+ Fog.Set();
+ }
+ else
+ {
+ Fog.Enabled = false;
+ }
+ }
+
+ private void RenderUI(RenderContext context)
+ {
+ // particle sources
+ if (CurrentInterface != InterfaceType.GLMainMenu)
+ {
+ foreach (TrainBase train in Program.TrainManager.Trains)
+ {
+ train.UpdateParticleSources(context.TimeElapsed);
+ }
+
+ foreach (ScriptedTrain scriptedTrain in Program.TrainManager.TFOs)
+ {
+ scriptedTrain.UpdateParticleSources(context.TimeElapsed);
+ }
+ }
+
+ if (Interface.CurrentOptions.ShowEvents)
+ {
+ if (Math.Abs(CameraTrackFollower.TrackPosition - events.LastTrackPosition) > 50)
+ {
+ events.LastTrackPosition = CameraTrackFollower.TrackPosition;
+ CubesToDraw.Clear();
+ for (int i = 0; i < Program.CurrentRoute.Tracks.Count; i++)
+ {
+ int railIndex = Program.CurrentRoute.Tracks.ElementAt(i).Key;
+ events.FindEvents(railIndex);
+ }
+ }
+
+ for (int i = 0; i < CubesToDraw.Count; i++)
+ {
+ Texture T = CubesToDraw.ElementAt(i).Key;
+ foreach (Vector3 v in CubesToDraw[T])
+ {
+ Cube.Draw(v, Camera.AbsoluteDirection, Camera.AbsoluteUp, Camera.AbsoluteSide, 0.2, Camera.AbsolutePosition, T);
+ }
+ }
+ }
+
+ overlays.Render(context.RealTimeElapsed);
+ switch (CurrentInterface)
+ {
+ case InterfaceType.Menu:
+ case InterfaceType.GLMainMenu:
+ Game.Menu.Draw(context.TimeElapsed);
+ break;
+ case InterfaceType.SwitchChangeMap:
+ Game.SwitchChangeDialog.Draw();
+ break;
+ }
+ }
+
internal int CreateStaticObject(UnifiedObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, ObjectDisposalMode AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition)
{
if (!(Prototype is StaticObject obj))
@@ -98,6 +186,7 @@ protected override void UpdateViewport(int width, int height)
{
case ViewportMode.Scenery:
double cd = Program.CurrentRoute.CurrentBackground is BackgroundObject b ? Math.Max(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance, b.ClipDistance) : Program.CurrentRoute.CurrentBackground.BackgroundImageDistance;
+ cd = Math.Max(cd, currentOptions.ViewingDistance);
CurrentProjectionMatrix = Matrix4D.CreatePerspectiveFieldOfView(Camera.VerticalViewingAngle, Screen.AspectRatio, 0.5, cd);
break;
case ViewportMode.Cab:
@@ -107,11 +196,17 @@ protected override void UpdateViewport(int width, int height)
Touch.UpdateViewport();
}
-
+
internal void RenderScene(double TimeElapsed, double RealTimeElapsed)
{
+ if (GameWindow != null && !Screen.Minimized)
+ {
+ Screen.Width = GameWindow.Width;
+ Screen.Height = GameWindow.Height;
+ }
+ UpdateViewport(ViewportChangeMode.ChangeToScenery);
+ UpdateViewingDistances(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance);
ReleaseResources();
- // initialize
ResetOpenGlState();
if (OptionWireFrame)
@@ -136,39 +231,30 @@ internal void RenderScene(double TimeElapsed, double RealTimeElapsed)
}
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
-
- // set up camera and lighting early for shadows
- CurrentViewMatrix = Matrix4D.LookAt(Vector3.Zero, new Vector3(Camera.AbsoluteDirection.X, Camera.AbsoluteDirection.Y, -Camera.AbsoluteDirection.Z), new Vector3(Camera.AbsoluteUp.X, Camera.AbsoluteUp.Y, -Camera.AbsoluteUp.Z));
- TransformedLightPosition = new Vector3(Lighting.OptionLightPosition.X, Lighting.OptionLightPosition.Y, -Lighting.OptionLightPosition.Z);
- TransformedLightPosition.Transform(CurrentViewMatrix);
-
- UpdateViewport(ViewportChangeMode.ChangeToScenery);
- if (AvailableNewRenderer)
+ // Setup Render Context
+ RenderContext context = new RenderContext(this, TimeElapsed)
{
- PerformCSMShadowPass();
- }
+ RealTimeElapsed = RealTimeElapsed,
+ Camera = Camera,
+ ProjectionMatrix = CurrentProjectionMatrix
+ };
+
+ // Update View Matrix
+ CurrentViewMatrix = Matrix4D.LookAt(Vector3.Zero, new Vector3(Camera.AbsoluteDirection.X, Camera.AbsoluteDirection.Y, -Camera.AbsoluteDirection.Z), new Vector3(Camera.AbsoluteUp.X, Camera.AbsoluteUp.Y, -Camera.AbsoluteUp.Z));
+ context.ViewMatrix = CurrentViewMatrix;
if (Lighting.ShouldInitialize)
{
Lighting.Initialize();
Lighting.ShouldInitialize = false;
}
-
- if (!AvailableNewRenderer)
- {
- GL.Light(LightName.Light0, LightParameter.Position, new[] { (float)TransformedLightPosition.X, (float)TransformedLightPosition.Y, (float)TransformedLightPosition.Z, 0.0f });
- }
Lighting.OptionLightingResultingAmount = (Lighting.OptionAmbientColor.R + Lighting.OptionAmbientColor.G + Lighting.OptionAmbientColor.B) / 480.0f;
+ if (Lighting.OptionLightingResultingAmount > 1.0f) Lighting.OptionLightingResultingAmount = 1.0f;
- if (Lighting.OptionLightingResultingAmount > 1.0f)
- {
- Lighting.OptionLightingResultingAmount = 1.0f;
- }
- // fog
+ // Fog track interpolation
double fd = Program.CurrentRoute.NextFog.TrackPosition - Program.CurrentRoute.PreviousFog.TrackPosition;
-
if (fd != 0.0)
{
float fr = (float)((CameraTrackFollower.TrackPosition - Program.CurrentRoute.PreviousFog.TrackPosition) / fd);
@@ -188,342 +274,50 @@ internal void RenderScene(double TimeElapsed, double RealTimeElapsed)
Program.CurrentRoute.CurrentFog = Program.CurrentRoute.PreviousFog;
}
- if (AvailableNewRenderer)
- {
- DefaultShader.Activate();
- BindCSMToDefaultShader();
- }
-
- // render background
- // n.b. must disable shadows
- GL.Disable(EnableCap.DepthTest);
- DefaultShader.SetShadowEnabled(false);
- Program.CurrentRoute.UpdateBackground(TimeElapsed, Program.Renderer.CurrentInterface != InterfaceType.Normal);
- DefaultShader.SetShadowEnabled(ShadowsEnabled);
-
- // fog
- float aa = Program.CurrentRoute.CurrentFog.Start;
- float bb = Program.CurrentRoute.CurrentFog.End;
-
- if (aa < bb & aa < Program.CurrentRoute.CurrentBackground.BackgroundImageDistance)
- {
- Fog.Enabled = true;
- Fog.Start = aa;
- Fog.End = bb;
- Fog.Color = Program.CurrentRoute.CurrentFog.Color;
- Fog.Density = Program.CurrentRoute.CurrentFog.Density;
- Fog.IsLinear = Program.CurrentRoute.CurrentFog.IsLinear;
- Fog.Set();
- }
- else
- {
- Fog.Enabled = false;
- }
-
- // world layer
- // opaque face
- if (AvailableNewRenderer)
- {
- //Setup the shader for rendering the scene
- if (OptionLighting)
- {
- DefaultShader.SetIsLight(true);
- DefaultShader.SetLightPosition(TransformedLightPosition);
- DefaultShader.SetLightAmbient(Lighting.OptionAmbientColor);
- DefaultShader.SetLightDiffuse(Lighting.OptionDiffuseColor);
- DefaultShader.SetLightSpecular(Lighting.OptionSpecularColor);
- DefaultShader.SetLightModel(Lighting.LightModel);
- }
- Fog.Set();
- DefaultShader.SetTexture(0);
- DefaultShader.SetCurrentProjectionMatrix(CurrentProjectionMatrix);
- }
- ResetOpenGlState();
- List opaqueFaces, alphaFaces, overlayOpaqueFaces, overlayAlphaFaces;
- lock (VisibleObjects.LockObject)
- {
- opaqueFaces = VisibleObjects.OpaqueFaces.ToList();
- alphaFaces = VisibleObjects.GetSortedPolygons();
- overlayOpaqueFaces = VisibleObjects.OverlayOpaqueFaces.ToList();
- overlayAlphaFaces = VisibleObjects.GetSortedPolygons(true);
- }
-
- foreach (FaceState face in opaqueFaces)
- {
- face.Draw();
- }
-
- // alpha face
- ResetOpenGlState();
-
- if (Interface.CurrentOptions.TransparencyMode == TransparencyMode.Performance)
- {
- SetBlendFunc();
- SetAlphaFunc(AlphaFunction.Greater, 0.0f);
- GL.DepthMask(false);
-
- foreach (FaceState face in alphaFaces)
- {
- face.Draw();
- }
- }
- else
- {
- UnsetBlendFunc();
- SetAlphaFunc(AlphaFunction.Equal, 1.0f);
- GL.DepthMask(true);
-
- foreach (FaceState face in alphaFaces)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].BlendMode == MeshMaterialBlendMode.Normal && face.Object.Prototype.Mesh.Materials[face.Face.Material].GlowAttenuationData == 0)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].Color.A == 255)
- {
- face.Draw();
- }
- }
- }
-
- SetBlendFunc();
- SetAlphaFunc(AlphaFunction.Less, 1.0f);
- GL.DepthMask(false);
- bool additive = false;
-
- foreach (FaceState face in alphaFaces)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].BlendMode == MeshMaterialBlendMode.Additive)
- {
- if (!additive)
- {
- UnsetAlphaFunc();
- additive = true;
- }
- }
- else
- {
- if (additive)
- {
- SetAlphaFunc();
- additive = false;
- }
- }
- face.Draw();
- }
- }
+ TransformedLightPosition = new Vector3(Lighting.OptionLightPosition.X, Lighting.OptionLightPosition.Y, -Lighting.OptionLightPosition.Z);
+ TransformedLightPosition.Transform(CurrentViewMatrix);
- // motion blur
- ResetOpenGlState();
- SetAlphaFunc(AlphaFunction.Greater, 0.0f);
+ // Execute Pipeline
+ ExecutePipeline(context);
+ }
+ }
+ internal class MotionBlurPass : IRenderPass
+ {
+ private readonly NewRenderer renderer;
+ internal MotionBlurPass(NewRenderer renderer)
+ {
+ this.renderer = renderer;
+ }
+ public void Execute(RenderContext context)
+ {
+ renderer.ResetOpenGlState();
+ renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
GL.Disable(EnableCap.DepthTest);
GL.DepthMask(false);
- OptionLighting = false;
+ renderer.OptionLighting = false;
if (Interface.CurrentOptions.MotionBlur != MotionBlurMode.None)
{
- if (AvailableNewRenderer)
- {
- DefaultShader.Deactivate();
- }
- MotionBlur.RenderFullscreen(Interface.CurrentOptions.MotionBlur, FrameRate, Math.Abs(Camera.CurrentSpeed));
- }
-
- // particle sources
- SetBlendFunc();
- SetAlphaFunc(AlphaFunction.Greater, 0.0f);
- if(CurrentInterface != InterfaceType.GLMainMenu)
- {
- foreach (TrainBase train in Program.TrainManager.Trains)
- {
- train.UpdateParticleSources(TimeElapsed);
- }
-
- // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop
- foreach (ScriptedTrain scriptedTrain in Program.TrainManager.TFOs)
+ if (renderer.AvailableNewRenderer)
{
- scriptedTrain.UpdateParticleSources(TimeElapsed);
+ renderer.DefaultShader.Deactivate();
}
-
+ renderer.MotionBlur.RenderFullscreen(Interface.CurrentOptions.MotionBlur, renderer.FrameRate, Math.Abs(renderer.Camera.CurrentSpeed));
}
-
- if (Interface.CurrentOptions.ShowEvents)
- {
- if (Math.Abs(CameraTrackFollower.TrackPosition - events.LastTrackPosition) > 50)
- {
- events.LastTrackPosition = CameraTrackFollower.TrackPosition;
- CubesToDraw.Clear();
- for (int i = 0; i < Program.CurrentRoute.Tracks.Count; i++)
- {
- int railIndex = Program.CurrentRoute.Tracks.ElementAt(i).Key;
- events.FindEvents(railIndex);
- }
- }
-
- for (int i = 0; i < CubesToDraw.Count; i++)
- {
- Texture T = CubesToDraw.ElementAt(i).Key;
- foreach (Vector3 v in CubesToDraw[T])
- {
- Cube.Draw(v, Camera.AbsoluteDirection, Camera.AbsoluteUp, Camera.AbsoluteSide, 0.2, Camera.AbsolutePosition, T);
- }
- }
- }
-
- // overlay (cab / interior) layer
- Fog.Enabled = false;
- UpdateViewport(ViewportChangeMode.ChangeToCab);
-
- if (AvailableNewRenderer)
- {
- /*
- * We must reset the shader between overlay and world layers for correct lighting results.
- * Additionally, the viewport change updates the projection matrix
- */
- DefaultShader.Activate();
- ResetShader(DefaultShader);
- DefaultShader.SetCurrentProjectionMatrix(CurrentProjectionMatrix);
- }
- CurrentViewMatrix = Matrix4D.LookAt(Vector3.Zero, new Vector3(Camera.AbsoluteDirection.X, Camera.AbsoluteDirection.Y, -Camera.AbsoluteDirection.Z), new Vector3(Camera.AbsoluteUp.X, Camera.AbsoluteUp.Y, -Camera.AbsoluteUp.Z));
-
- if (Camera.CurrentRestriction == CameraRestrictionMode.NotAvailable || Camera.CurrentRestriction == CameraRestrictionMode.Restricted3D)
- {
- ResetOpenGlState(); // TODO: inserted
- GL.Clear(ClearBufferMask.DepthBufferBit);
- OptionLighting = true;
- Color24 prevOptionAmbientColor = Lighting.OptionAmbientColor;
- Color24 prevOptionDiffuseColor = Lighting.OptionDiffuseColor;
- Lighting.OptionAmbientColor = Color24.LightGrey;
- Lighting.OptionDiffuseColor = Color24.LightGrey;
- if (AvailableNewRenderer)
- {
- DefaultShader.SetIsLight(true);
- TransformedLightPosition = new Vector3(Lighting.OptionLightPosition.X, Lighting.OptionLightPosition.Y, -Lighting.OptionLightPosition.Z);
- DefaultShader.SetLightPosition(TransformedLightPosition);
- DefaultShader.SetLightAmbient(Lighting.OptionAmbientColor);
- DefaultShader.SetLightDiffuse(Lighting.OptionDiffuseColor);
- DefaultShader.SetLightSpecular(Lighting.OptionSpecularColor);
- DefaultShader.SetLightModel(Lighting.LightModel);
- }
- else
- {
- GL.Light(LightName.Light0, LightParameter.Ambient, new[] { inv255 * 178, inv255 * 178, inv255 * 178, 1.0f });
- GL.Light(LightName.Light0, LightParameter.Diffuse, new[] { inv255 * 178, inv255 * 178, inv255 * 178, 1.0f });
- }
-
-
- // overlay opaque face
- foreach (FaceState face in overlayOpaqueFaces)
- {
- face.Draw();
- }
-
- // overlay alpha face
- ResetOpenGlState();
- if (Interface.CurrentOptions.TransparencyMode == TransparencyMode.Performance)
- {
- SetBlendFunc();
- SetAlphaFunc(AlphaFunction.Greater, 0.0f);
- GL.DepthMask(false);
-
- foreach (FaceState face in overlayAlphaFaces)
- {
- face.Draw();
- }
- }
- else
- {
- UnsetBlendFunc();
- SetAlphaFunc(AlphaFunction.Equal, 1.0f);
- GL.DepthMask(true);
-
- foreach (FaceState face in overlayAlphaFaces)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].BlendMode == MeshMaterialBlendMode.Normal && face.Object.Prototype.Mesh.Materials[face.Face.Material].GlowAttenuationData == 0)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].Color.A == 255)
- {
- face.Draw();
- }
- }
- }
-
- SetBlendFunc();
- SetAlphaFunc(AlphaFunction.Less, 1.0f);
- GL.DepthMask(false);
- bool additive = false;
-
- foreach (FaceState face in overlayAlphaFaces)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].BlendMode == MeshMaterialBlendMode.Additive)
- {
- if (!additive)
- {
- UnsetAlphaFunc();
- additive = true;
- }
- }
- else
- {
- if (additive)
- {
- SetAlphaFunc();
- additive = false;
- }
- }
- face.Draw();
- }
- }
-
- Lighting.OptionAmbientColor = prevOptionAmbientColor;
- Lighting.OptionDiffuseColor = prevOptionDiffuseColor;
- Lighting.Initialize();
- }
- else
- {
- /*
- * Render 2D Cab
- * This is actually an animated object generated on the fly and held in memory
- */
- ResetOpenGlState();
- OptionLighting = false;
- if (AvailableNewRenderer)
- {
- DefaultShader.SetIsLight(false);
- }
-
- SetBlendFunc();
- UnsetAlphaFunc();
- GL.Disable(EnableCap.DepthTest);
- GL.DepthMask(false);
- foreach (FaceState face in overlayAlphaFaces)
- {
- face.Draw();
- }
- }
- // render touch
- OptionLighting = false;
- Touch.RenderScene();
-
- // render overlays
- ResetOpenGlState();
- UnsetAlphaFunc();
- SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); //FIXME: Remove when text switches between two renderer types
- GL.Disable(EnableCap.DepthTest);
- overlays.Render(RealTimeElapsed);
- switch (CurrentInterface)
- {
- case InterfaceType.Menu:
- case InterfaceType.GLMainMenu:
- Game.Menu.Draw(TimeElapsed);
- break;
- case InterfaceType.SwitchChangeMap:
- Game.SwitchChangeDialog.Draw();
- break;
- }
- OptionLighting = true;
}
+ }
- public NewRenderer(HostInterface currentHost, BaseOptions currentOptions, FileSystem fileSystem) : base(currentHost, currentOptions, fileSystem)
+ internal class TouchPickingPass : IRenderPass
+ {
+ private readonly NewRenderer renderer;
+ internal TouchPickingPass(NewRenderer renderer)
+ {
+ this.renderer = renderer;
+ }
+ public void Execute(RenderContext context)
{
+ renderer.OptionLighting = false;
+ renderer.Touch.RenderScene();
}
}
}
diff --git a/source/OpenBVE/Graphics/Renderers/Overlays.Debug.cs b/source/OpenBVE/Graphics/Renderers/Overlays.Debug.cs
index d41412abd2..880999e00a 100644
--- a/source/OpenBVE/Graphics/Renderers/Overlays.Debug.cs
+++ b/source/OpenBVE/Graphics/Renderers/Overlays.Debug.cs
@@ -187,7 +187,7 @@ private void RenderDebugOverlays()
"=route",
"track limit: " + (TrainManager.PlayerTrain.CurrentRouteLimit == double.PositiveInfinity ? "unlimited" : ((TrainManager.PlayerTrain.CurrentRouteLimit * 3.6).ToString("0.0", Culture) + " km/h")),
"signal limit: " + (TrainManager.PlayerTrain.CurrentSectionLimit == double.PositiveInfinity ? "unlimited" : ((TrainManager.PlayerTrain.CurrentSectionLimit * 3.6).ToString("0.0", Culture) + " km/h")),
- "total static objects: " + (Program.Renderer.StaticObjectStates.Count + Program.Renderer.DynamicObjectStates.Count).ToString(Culture),
+ "total static objects: " + (Program.Renderer.Scene.StaticObjectStates.Count + Program.Renderer.Scene.DynamicObjectStates.Count).ToString(Culture),
"total static GL_TRIANGLES: " + Program.Renderer.InfoTotalTriangles.ToString(Culture),
"total static GL_TRIANGLE_STRIP: " + Program.Renderer.InfoTotalTriangleStrip.ToString(Culture),
"total static GL_QUADS: " + Program.Renderer.InfoTotalQuads.ToString(Culture),
diff --git a/source/OpenBVE/Graphics/Renderers/Overlays.cs b/source/OpenBVE/Graphics/Renderers/Overlays.cs
index eb0f25d707..b141cf4f66 100644
--- a/source/OpenBVE/Graphics/Renderers/Overlays.cs
+++ b/source/OpenBVE/Graphics/Renderers/Overlays.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using DavyKager;
using LibRender2.Overlays;
using LibRender2.Screens;
diff --git a/source/OpenBVE/System/GameWindow.cs b/source/OpenBVE/System/GameWindow.cs
index c175103363..337f5eed4c 100644
--- a/source/OpenBVE/System/GameWindow.cs
+++ b/source/OpenBVE/System/GameWindow.cs
@@ -492,7 +492,7 @@ protected override void OnClosing(CancelEventArgs e)
}
}
Program.Renderer.TextureManager.UnloadAllTextures(false);
- Program.Renderer.VisibilityThreadShouldRun = false;
+ Program.Renderer.Scene.VisibilityThreadShouldRun = false;
for (int i = 0; i < InputDevicePlugin.AvailablePluginInfos.Count; i++)
{
InputDevicePlugin.CallPluginUnload(i);
diff --git a/source/RouteViewer/NewRendererR.cs b/source/RouteViewer/NewRendererR.cs
index d1d888a460..e7b94c2227 100644
--- a/source/RouteViewer/NewRendererR.cs
+++ b/source/RouteViewer/NewRendererR.cs
@@ -4,6 +4,8 @@
using System.Linq;
using System.Windows.Forms;
using LibRender2;
+using LibRender2.Pipeline;
+using LibRender2.Passes;
using LibRender2.Objects;
using LibRender2.Screens;
using OpenBveApi;
@@ -70,11 +72,19 @@ public override void Initialize()
TextureManager.RegisterTexture(Path.CombineFile(Folder, "runsound.png"), out RunSoundTexture);
TextureManager.RegisterTexture(Path.CombineFile(Folder, "lighting.png"), out LightingEventTexture);
TextureManager.RegisterTexture(Path.CombineFile(Folder, "weather.png"), out WeatherEventTexture);
+
+ // Initialize Pipeline
+ Pipeline.Clear();
+ Pipeline.AddPass(new ShadowPass());
+ Pipeline.AddPass(new SkyPass(ctx => Program.CurrentRoute.UpdateBackground(ctx.TimeElapsed, false)));
+ Pipeline.AddPass(new GeometryPass());
+ Pipeline.AddPass(new OverlayPass(ctx => RenderOverlays(ctx.TimeElapsed)));
}
// render scene
internal void RenderScene(double timeElapsed)
{
+ UpdateViewingDistances(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance);
lastObjectState = null;
ReleaseResources();
// initialize
@@ -147,129 +157,9 @@ internal void RenderScene(double timeElapsed)
Program.CurrentRoute.CurrentFog = Program.CurrentRoute.PreviousFog;
}
- if (AvailableNewRenderer)
- {
- PerformCSMShadowPass();
- DefaultShader.Activate();
- BindCSMToDefaultShader();
- }
-
-
- // render background
- GL.Disable(EnableCap.DepthTest);
- DefaultShader.SetShadowEnabled(false);
- Program.CurrentRoute.UpdateBackground(timeElapsed, false);
- DefaultShader.SetShadowEnabled(ShadowsEnabled);
-
- // fog
- float aa = Program.CurrentRoute.CurrentFog.Start;
- float bb = Program.CurrentRoute.CurrentFog.End;
-
- if (aa < bb & aa < Program.CurrentRoute.CurrentBackground.BackgroundImageDistance)
- {
- Fog.Enabled = true;
- Fog.Start = aa;
- Fog.End = bb;
- Fog.Color = Program.CurrentRoute.CurrentFog.Color;
- Fog.Density = Program.CurrentRoute.CurrentFog.Density;
- Fog.IsLinear = Program.CurrentRoute.CurrentFog.IsLinear;
- Fog.Set();
- }
- else
- {
- Fog.Enabled = false;
- }
-
- // world layer
- // opaque face
-
-
- if (AvailableNewRenderer)
- {
- //Setup the shader for rendering the scene
- if (OptionLighting)
- {
- DefaultShader.SetIsLight(true);
- DefaultShader.SetLightPosition(TransformedLightPosition);
- DefaultShader.SetLightAmbient(Lighting.OptionAmbientColor);
- DefaultShader.SetLightDiffuse(Lighting.OptionDiffuseColor);
- DefaultShader.SetLightSpecular(Lighting.OptionSpecularColor);
- DefaultShader.SetLightModel(Lighting.LightModel);
- }
- Fog.Set();
- DefaultShader.SetTexture(0);
- DefaultShader.SetCurrentProjectionMatrix(CurrentProjectionMatrix);
- }
- ResetOpenGlState();
- List opaqueFaces, alphaFaces;
- lock (VisibleObjects.LockObject)
- {
- opaqueFaces = VisibleObjects.OpaqueFaces.ToList();
- alphaFaces = VisibleObjects.GetSortedPolygons();
- }
-
- foreach (FaceState face in opaqueFaces)
- {
- face.Draw();
- }
-
- // alpha face
- ResetOpenGlState();
-
- if (Interface.CurrentOptions.TransparencyMode == TransparencyMode.Performance)
- {
- SetBlendFunc();
- SetAlphaFunc(AlphaFunction.Greater, 0.0f);
- GL.DepthMask(false);
-
- foreach (FaceState face in alphaFaces)
- {
- face.Draw();
- }
- }
- else
- {
- UnsetBlendFunc();
- SetAlphaFunc(AlphaFunction.Equal, 1.0f);
- GL.DepthMask(true);
-
- foreach (FaceState face in alphaFaces)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].BlendMode == MeshMaterialBlendMode.Normal && face.Object.Prototype.Mesh.Materials[face.Face.Material].GlowAttenuationData == 0)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].Color.A == 255)
- {
- face.Draw();
- }
- }
- }
-
- SetBlendFunc();
- SetAlphaFunc(AlphaFunction.Less, 1.0f);
- GL.DepthMask(false);
- bool additive = false;
-
- foreach (FaceState face in alphaFaces)
- {
- if (face.Object.Prototype.Mesh.Materials[face.Face.Material].BlendMode == MeshMaterialBlendMode.Additive)
- {
- if (!additive)
- {
- UnsetAlphaFunc();
- additive = true;
- }
- }
- else
- {
- if (additive)
- {
- SetAlphaFunc();
- additive = false;
- }
- }
- face.Draw();
- }
- }
+ // Execute Pipeline
+ RenderContext context = new RenderContext(this, timeElapsed);
+ ExecutePipeline(context);
if (OptionPaths)
{
From c6043d9b91b880d4dab54e4fb4d43ba2ee88c3b6 Mon Sep 17 00:00:00 2001
From: adfriz <76892624+adfriz@users.noreply.github.com>
Date: Fri, 24 Apr 2026 20:17:23 +0700
Subject: [PATCH 2/9] fix nearclip and sync with upstream master
---
source/OpenBVE/Graphics/NewRenderer.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/source/OpenBVE/Graphics/NewRenderer.cs b/source/OpenBVE/Graphics/NewRenderer.cs
index 20a027bf22..885800bfb5 100644
--- a/source/OpenBVE/Graphics/NewRenderer.cs
+++ b/source/OpenBVE/Graphics/NewRenderer.cs
@@ -187,10 +187,10 @@ protected override void UpdateViewport(int width, int height)
case ViewportMode.Scenery:
double cd = Program.CurrentRoute.CurrentBackground is BackgroundObject b ? Math.Max(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance, b.ClipDistance) : Program.CurrentRoute.CurrentBackground.BackgroundImageDistance;
cd = Math.Max(cd, currentOptions.ViewingDistance);
- CurrentProjectionMatrix = Matrix4D.CreatePerspectiveFieldOfView(Camera.VerticalViewingAngle, Screen.AspectRatio, 0.5, cd);
+ CurrentProjectionMatrix = Matrix4D.CreatePerspectiveFieldOfView(Camera.VerticalViewingAngle, Screen.AspectRatio, currentOptions.NearClipScenery, cd);
break;
case ViewportMode.Cab:
- CurrentProjectionMatrix = Matrix4D.CreatePerspectiveFieldOfView(Camera.VerticalViewingAngle, Screen.AspectRatio, 0.025, 50.0);
+ CurrentProjectionMatrix = Matrix4D.CreatePerspectiveFieldOfView(Camera.VerticalViewingAngle, Screen.AspectRatio, currentOptions.NearClipCab, 50.0);
break;
}
From 03dd64bd092e01a08be1729792b66080dc73f791 Mon Sep 17 00:00:00 2001
From: adfriz <76892624+adfriz@users.noreply.github.com>
Date: Fri, 24 Apr 2026 23:08:29 +0700
Subject: [PATCH 3/9] update
- Replace direct OpenGL calls (GL.DepthMask, GL.Enable, GL.BlendFunc, etc.) with GraphicsDevice cached state methods across LibRender2 and OpenBVE renderer.
- Add null-safety checks to Transformation constructors and Vector3 transformation operations to prevent NullReferenceExceptions.
- Ensure proper renderer de-initialization in GameWindow during application shutdown.
- Update Transformation constructors to use default vectors (Right, Down, Forward) when the input transformation is null.
---
source/LibRender2/Backgrounds/Background.cs | 24 ++--
source/LibRender2/BaseRenderer.cs | 110 ++++++-------------
source/LibRender2/Managers/SceneManager.cs | 2 +-
source/LibRender2/MotionBlur/MotionBlur.cs | 6 +-
source/LibRender2/Pipeline/GraphicsDevice.cs | 87 ++++++++++++++-
source/LibRender2/Primitives/Cube.cs | 10 +-
source/LibRender2/Primitives/Particle.cs | 12 +-
source/LibRender2/Primitives/Picturebox.cs | 2 +-
source/LibRender2/Primitives/Rectangle.cs | 10 +-
source/LibRender2/Smoke/ParticleSource.cs | 6 +-
source/LibRender2/Text/OpenGlString.cs | 12 +-
source/OpenBVE/Graphics/NewRenderer.cs | 5 +-
source/OpenBVE/System/GameWindow.cs | 1 +
source/OpenBveApi/Math/Vectors/Vector3.cs | 8 ++
source/OpenBveApi/World/Transformations.cs | 15 +--
15 files changed, 182 insertions(+), 128 deletions(-)
diff --git a/source/LibRender2/Backgrounds/Background.cs b/source/LibRender2/Backgrounds/Background.cs
index ee0d16b0d0..5567c92f54 100644
--- a/source/LibRender2/Backgrounds/Background.cs
+++ b/source/LibRender2/Backgrounds/Background.cs
@@ -124,11 +124,11 @@ private void RenderStaticBackgroundRetained(StaticBackground data, float alpha,
renderer.LastBoundTexture = t.OpenGlTextures[(int)OpenGlTextureWrapMode.RepeatClamp];
if (alpha == 1.0f)
{
- GL.Disable(EnableCap.Blend);
+ renderer.Device.SetBlend(false);
}
else
{
- GL.Enable(EnableCap.Blend);
+ renderer.Device.SetBlend(true);
}
if (data.VAO == null)
@@ -201,15 +201,15 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadMatrix(ref lookat);
- GL.Disable(EnableCap.Lighting);
- GL.Enable(EnableCap.Texture2D);
+ renderer.Device.SetLighting(false);
+ renderer.Device.SetTexture2D(true);
if (alpha == 1.0f)
{
- GL.Disable(EnableCap.Blend);
+ renderer.Device.SetBlend(false);
}
else
{
- GL.Enable(EnableCap.Blend);
+ renderer.Device.SetBlend(true);
renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
}
GL.BindTexture(TextureTarget.Texture2D, t.OpenGlTextures[(int)OpenGlTextureWrapMode.RepeatClamp].Name);
@@ -217,13 +217,13 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
GL.Color4(1.0f, 1.0f, 1.0f, alpha);
if (renderer.Fog.Enabled)
{
- GL.Enable(EnableCap.Fog);
+ renderer.Device.SetFog(true);
}
if (data.DisplayList > 0)
{
GL.CallList(data.DisplayList);
- GL.Disable(EnableCap.Texture2D);
- GL.Enable(EnableCap.Blend);
+ renderer.Device.SetTexture2D(false);
+ renderer.Device.SetBlend(true);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
@@ -300,8 +300,8 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
}
GL.EndList();
GL.CallList(data.DisplayList);
- GL.Disable(EnableCap.Texture2D);
- GL.Enable(EnableCap.Blend);
+ renderer.Device.SetTexture2D(false);
+ renderer.Device.SetBlend(true);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
@@ -312,7 +312,7 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
/// The background object
private void RenderBackgroundObject(BackgroundObject data)
{
- GL.Enable(EnableCap.Blend);
+ renderer.Device.SetBlend(true);
// alpha test
renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
if (renderer.AvailableNewRenderer)
diff --git a/source/LibRender2/BaseRenderer.cs b/source/LibRender2/BaseRenderer.cs
index d35640fb51..96bc9d5d9d 100644
--- a/source/LibRender2/BaseRenderer.cs
+++ b/source/LibRender2/BaseRenderer.cs
@@ -258,11 +258,11 @@ public void BindCSMToDefaultShader()
public double FrameRate = 1.0;
/// Whether Blend is enabled in openGL
- private bool blendEnabled;
+ public bool BlendEnabled => Device.BlendEnabled;
- private BlendingFactor blendSrcFactor;
+ private BlendingFactor blendSrcFactor = BlendingFactor.SrcAlpha;
- private BlendingFactor blendDestFactor;
+ private BlendingFactor blendDestFactor = BlendingFactor.OneMinusSrcAlpha;
/// Whether Alpha Testing is enabled in openGL
private bool alphaTestEnabled;
@@ -465,8 +465,7 @@ public virtual void Initialize()
}
GL.ClearColor(0.67f, 0.67f, 0.67f, 1.0f);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
- GL.Enable(EnableCap.DepthTest);
- GL.DepthFunc(DepthFunction.Lequal);
+ Device.SetDepthTest(true, DepthFunction.Lequal);
SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
if (currentOptions.ForceForwardsCompatibleContext == false)
{
@@ -474,20 +473,19 @@ public virtual void Initialize()
GL.Hint(HintTarget.FogHint, HintMode.Fastest);
GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Fastest);
GL.Hint(HintTarget.GenerateMipmapHint, HintMode.Nicest);
- GL.Disable(EnableCap.Lighting);
- GL.Disable(EnableCap.Fog);
+ Device.SetLighting(false);
+ Device.SetFog(false);
GL.Hint(HintTarget.LineSmoothHint, HintMode.Fastest);
GL.Hint(HintTarget.PointSmoothHint, HintMode.Fastest);
GL.Hint(HintTarget.PolygonSmoothHint, HintMode.Fastest);
}
- GL.Enable(EnableCap.CullFace);
- GL.CullFace(CullFaceMode.Front);
+ Device.SetCullFace(true, CullFaceMode.Front);
GL.Disable(EnableCap.Dither);
if (!AvailableNewRenderer)
{
- GL.Disable(EnableCap.Texture2D);
+ Device.SetTexture2D(false);
GL.Fog(FogParameter.FogMode, (int)FogMode.Linear);
}
@@ -667,21 +665,19 @@ public void ReleaseResources()
///
public virtual void ResetOpenGlState()
{
- GL.Enable(EnableCap.CullFace);
- GL.CullFace(CullFaceMode.Front);
+ Device.SetCullFace(true, CullFaceMode.Front);
if (!AvailableNewRenderer)
{
- GL.Disable(EnableCap.Lighting);
- GL.Disable(EnableCap.Fog);
- GL.Disable(EnableCap.Texture2D);
+ Device.SetLighting(false);
+ Device.SetFog(false);
+ Device.SetTexture2D(false);
}
SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
UnsetBlendFunc();
- GL.Enable(EnableCap.DepthTest);
- GL.DepthFunc(DepthFunction.Lequal);
+ Device.SetDepthTest(true, DepthFunction.Lequal);
GL.Disable(EnableCap.DepthClamp);
- GL.DepthMask(true);
+ Device.SetDepthMask(true);
SetAlphaFunc(AlphaFunction.Greater, 0.9f);
}
@@ -885,35 +881,24 @@ public void ResetShader(Shader shader)
public void SetBlendFunc()
{
- SetBlendFunc(blendSrcFactor, blendDestFactor);
+ Device.SetBlend(true, blendSrcFactor, blendDestFactor);
}
public void SetBlendFunc(BlendingFactor srcFactor, BlendingFactor destFactor)
{
- blendEnabled = true;
blendSrcFactor = srcFactor;
blendDestFactor = destFactor;
- GL.Enable(EnableCap.Blend);
- GL.BlendFunc(srcFactor, destFactor);
+ Device.SetBlend(true, srcFactor, destFactor);
}
public void UnsetBlendFunc()
{
- blendEnabled = false;
- GL.Disable(EnableCap.Blend);
+ Device.SetBlend(false);
}
public void RestoreBlendFunc()
{
- if (blendEnabled)
- {
- GL.Enable(EnableCap.Blend);
- GL.BlendFunc(blendSrcFactor, blendDestFactor);
- }
- else
- {
- GL.Disable(EnableCap.Blend);
- }
+ Device.SetBlend(Device.BlendEnabled, blendSrcFactor, blendDestFactor);
}
/// Specifies the OpenGL alpha function to perform
@@ -935,12 +920,7 @@ public void SetAlphaFunc(AlphaFunction comparison, float value)
CurrentShader.SetAlphaTest(true);
CurrentShader.SetAlphaFunction(comparison, value);
}
- else
- {
- GL.Enable(EnableCap.AlphaTest);
- GL.AlphaFunc(comparison, value);
- }
-
+ Device.SetAlphaTest(true, comparison, value);
}
/// Disables OpenGL alpha testing
@@ -951,11 +931,7 @@ public void UnsetAlphaFunc()
{
CurrentShader.SetAlphaTest(false);
}
- else
- {
- GL.Disable(EnableCap.AlphaTest);
- }
-
+ Device.SetAlphaTest(false);
}
/// Restores the OpenGL alpha function to it's previous state
@@ -963,28 +939,11 @@ public void RestoreAlphaFunc()
{
if (alphaTestEnabled)
{
- if (AvailableNewRenderer)
- {
- CurrentShader.SetAlphaTest(true);
- CurrentShader.SetAlphaFunction(alphaFuncComparison, alphaFuncValue);
- }
- else
- {
- GL.Enable(EnableCap.AlphaTest);
- GL.AlphaFunc(alphaFuncComparison, alphaFuncValue);
- }
-
+ SetAlphaFunc(alphaFuncComparison, alphaFuncValue);
}
else
{
- if (AvailableNewRenderer)
- {
- CurrentShader.SetAlphaTest(false);
- }
- else
- {
- GL.Disable(EnableCap.AlphaTest);
- }
+ UnsetAlphaFunc();
}
}
@@ -1048,13 +1007,13 @@ public void RenderFace(Shader shader, ObjectState state, MeshFace face, bool deb
if (!OptionBackFaceCulling || (face.Flags & FaceFlags.Face2Mask) != 0)
{
- GL.Disable(EnableCap.CullFace);
+ Device.SetCullFace(false);
}
else if (OptionBackFaceCulling)
{
if ((face.Flags & FaceFlags.Face2Mask) == 0)
{
- GL.Enable(EnableCap.CullFace);
+ Device.SetCullFace(true);
}
}
@@ -1273,13 +1232,13 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
if (!OptionBackFaceCulling || (face.Flags & FaceFlags.Face2Mask) != 0)
{
- GL.Disable(EnableCap.CullFace);
+ Device.SetCullFace(false);
}
else if (OptionBackFaceCulling)
{
if ((face.Flags & FaceFlags.Face2Mask) == 0)
{
- GL.Enable(EnableCap.CullFace);
+ Device.SetCullFace(true);
}
}
@@ -1323,7 +1282,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
{
if (OptionLighting)
{
- GL.Enable(EnableCap.Lighting);
+ Device.SetLighting(true);
}
}
@@ -1332,7 +1291,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
// fog
if (Fog.Enabled)
{
- GL.Enable(EnableCap.Fog);
+ Device.SetFog(true);
}
PrimitiveType drawMode;
@@ -1381,7 +1340,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
// ReSharper disable once PossibleInvalidOperationException
if (currentHost.LoadTexture(ref material.DaytimeTexture, (OpenGlTextureWrapMode)material.WrapMode))
{
- GL.Enable(EnableCap.Texture2D);
+ Device.SetTexture2D(true);
if (LastBoundTexture != material.DaytimeTexture.OpenGlTextures[(int)material.WrapMode])
{
GL.BindTexture(TextureTarget.Texture2D, material.DaytimeTexture.OpenGlTextures[(int)material.WrapMode].Name);
@@ -1396,7 +1355,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
{
factor = 1.0f;
SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
- GL.Disable(EnableCap.Fog);
+ Device.SetFog(false);
}
else if (material.NighttimeTexture == null)
{
@@ -1409,7 +1368,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
if ((material.Flags & MaterialFlags.DisableLighting) != 0)
{
- GL.Disable(EnableCap.Lighting);
+ Device.SetLighting(false);
}
float alphaFactor = distanceFactor;
@@ -1449,7 +1408,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
if (blendFactor != 0 && material.NighttimeTexture != null && currentHost.LoadTexture(ref material.NighttimeTexture, (OpenGlTextureWrapMode)material.WrapMode))
{
// texture
- GL.Enable(EnableCap.Texture2D);
+ Device.SetTexture2D(true);
if (LastBoundTexture != material.NighttimeTexture.OpenGlTextures[(int)material.WrapMode])
{
GL.BindTexture(TextureTarget.Texture2D, material.NighttimeTexture.OpenGlTextures[(int)material.WrapMode].Name);
@@ -1459,8 +1418,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
Device.SetBlend(true);
// alpha test
- GL.Enable(EnableCap.AlphaTest);
- GL.AlphaFunc(AlphaFunction.Greater, 0.0f);
+ Device.SetAlphaTest(true, AlphaFunction.Greater, 0.0f);
// blend mode
float alphaFactor = distanceFactor * blendFactor;
@@ -1494,7 +1452,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
RestoreAlphaFunc();
}
- GL.Disable(EnableCap.Texture2D);
+ Device.SetTexture2D(false);
// normals
if (OptionNormals)
diff --git a/source/LibRender2/Managers/SceneManager.cs b/source/LibRender2/Managers/SceneManager.cs
index 8144716da2..8aa4ffb328 100644
--- a/source/LibRender2/Managers/SceneManager.cs
+++ b/source/LibRender2/Managers/SceneManager.cs
@@ -294,7 +294,7 @@ public void UpdateViewingDistances(double backgroundImageDistance)
public int CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, ObjectDisposalMode AccurateObjectDisposal, ObjectCreationParameters Parameters, double BlockLength)
{
Matrix4D Translate = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z);
- Matrix4D Rotate = (Matrix4D)new Transformation(LocalTransformation, WorldTransformation);
+ Matrix4D Rotate = (Matrix4D)new Transformation(LocalTransformation ?? Transformation.NullTransformation, WorldTransformation ?? Transformation.NullTransformation);
return CreateStaticObject(Position, Prototype, LocalTransformation, Rotate, Translate, AccurateObjectDisposal, Parameters, BlockLength);
}
diff --git a/source/LibRender2/MotionBlur/MotionBlur.cs b/source/LibRender2/MotionBlur/MotionBlur.cs
index 5c431e6aad..da460cd5d2 100644
--- a/source/LibRender2/MotionBlur/MotionBlur.cs
+++ b/source/LibRender2/MotionBlur/MotionBlur.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using OpenTK.Graphics.OpenGL;
namespace LibRender2.MotionBlurs
@@ -55,7 +55,7 @@ public void RenderFullscreen(MotionBlurMode mode, double frameRate, double speed
return;
}
renderer.LastBoundTexture = null;
- GL.Enable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(true);
// render
if (PixelBufferOpenGlTextureIndex >= 0)
@@ -120,7 +120,7 @@ public void RenderFullscreen(MotionBlurMode mode, double frameRate, double speed
GL.BindTexture(TextureTarget.Texture2D, PixelBufferOpenGlTextureIndex);
GL.CopyTexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgb8, 0, 0, renderer.Screen.Width, renderer.Screen.Height, 0);
}
- GL.Disable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(false);
}
}
}
diff --git a/source/LibRender2/Pipeline/GraphicsDevice.cs b/source/LibRender2/Pipeline/GraphicsDevice.cs
index b717ef3c79..1bb615b219 100644
--- a/source/LibRender2/Pipeline/GraphicsDevice.cs
+++ b/source/LibRender2/Pipeline/GraphicsDevice.cs
@@ -8,16 +8,28 @@ namespace LibRender2.Pipeline
public class GraphicsDevice
{
private bool blendEnabled;
+ public bool BlendEnabled => blendEnabled;
private BlendingFactor blendSrcFactor;
private BlendingFactor blendDestFactor;
private bool depthTestEnabled = true;
- private DepthFunction depthFunction = DepthFunction.Lequal;
+ private DepthFunction depthFunction = DepthFunction.Lequal; // less than or equal to
private bool depthMask = true;
private bool cullFaceEnabled = true;
private CullFaceMode cullFaceMode = CullFaceMode.Front;
+ private bool lightingEnabled;
+ private bool fogEnabled;
+ private bool texture2DEnabled;
+
+ private bool alphaTestEnabled;
+ public bool AlphaTestEnabled => alphaTestEnabled;
+ private AlphaFunction alphaTestFunction = AlphaFunction.Greater;
+ public AlphaFunction AlphaTestFunction => alphaTestFunction;
+ private float alphaTestThreshold;
+ public float AlphaTestThreshold => alphaTestThreshold;
+
///
/// Sets the blending state.
///
@@ -88,6 +100,65 @@ public void SetCullFace(bool enabled, CullFaceMode mode = CullFaceMode.Front)
}
}
+ ///
+ /// Sets the lighting state.
+ ///
+ public void SetLighting(bool enabled)
+ {
+ if (lightingEnabled != enabled)
+ {
+ lightingEnabled = enabled;
+ if (enabled) GL.Enable(EnableCap.Lighting);
+ else GL.Disable(EnableCap.Lighting);
+ }
+ }
+
+ ///
+ /// Sets the fog state.
+ ///
+ public void SetFog(bool enabled)
+ {
+ if (fogEnabled != enabled)
+ {
+ fogEnabled = enabled;
+ if (enabled) GL.Enable(EnableCap.Fog);
+ else GL.Disable(EnableCap.Fog);
+ }
+ }
+
+ ///
+ /// Sets the texture 2D state.
+ ///
+ public void SetTexture2D(bool enabled)
+ {
+ if (texture2DEnabled != enabled)
+ {
+ texture2DEnabled = enabled;
+ if (enabled) GL.Enable(EnableCap.Texture2D);
+ else GL.Disable(EnableCap.Texture2D);
+ }
+ }
+
+ ///
+ /// Sets the alpha test state.
+ ///
+ public void SetAlphaTest(bool enabled, AlphaFunction function = AlphaFunction.Greater, float threshold = 0.0f)
+ {
+ if (alphaTestEnabled != enabled)
+ {
+ alphaTestEnabled = enabled;
+ if (enabled) GL.Enable(EnableCap.AlphaTest);
+ else GL.Disable(EnableCap.AlphaTest);
+ }
+
+ if (enabled && (alphaTestFunction != function || alphaTestThreshold != threshold))
+ {
+ alphaTestFunction = function;
+ alphaTestThreshold = threshold;
+ GL.AlphaFunc(function, threshold);
+ }
+ }
+
///
/// Resets the cached state to match the current OpenGL defaults or a known state.
///
@@ -109,6 +180,20 @@ public void Reset()
cullFaceEnabled = true;
GL.CullFace(CullFaceMode.Back);
cullFaceMode = CullFaceMode.Back;
+
+ GL.Disable(EnableCap.Lighting);
+ lightingEnabled = false;
+
+ GL.Disable(EnableCap.Fog);
+ fogEnabled = false;
+
+ GL.Disable(EnableCap.Texture2D);
+ texture2DEnabled = false;
+
+ GL.Disable(EnableCap.AlphaTest);
+ alphaTestEnabled = false;
+ alphaTestFunction = AlphaFunction.Greater;
+ alphaTestThreshold = 0.0f;
}
}
}
diff --git a/source/LibRender2/Primitives/Cube.cs b/source/LibRender2/Primitives/Cube.cs
index a32142556e..f405ca2753 100644
--- a/source/LibRender2/Primitives/Cube.cs
+++ b/source/LibRender2/Primitives/Cube.cs
@@ -359,18 +359,18 @@ private void DrawRetained(VertexArrayObject VAO, Vector3 Position, Vector3 Direc
// texture
if (TextureIndex != null && renderer.currentHost.LoadTexture(ref TextureIndex, OpenGlTextureWrapMode.ClampClamp))
{
- GL.Enable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(true);
GL.BindTexture(TextureTarget.Texture2D, TextureIndex.OpenGlTextures[(int)OpenGlTextureWrapMode.ClampClamp].Name);
}
else
{
- GL.Disable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(false);
}
// render polygon
VAO.Bind();
VAO.Draw(PrimitiveType.Triangles);
- GL.Disable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(false);
}
/// Draws a 3D cube in immediate mode
@@ -422,7 +422,7 @@ private void DrawImmediate(Vector3 Position, Vector3 Direction, Vector3 Up, Vect
Faces[5] = new[] { 6, 2, 1, 5 };
if (TextureIndex == null || !renderer.currentHost.LoadTexture(ref TextureIndex, OpenGlTextureWrapMode.ClampClamp))
{
- GL.Disable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(false);
for (int i = 0; i < 6; i++)
{
GL.Begin(PrimitiveType.Quads);
@@ -438,7 +438,7 @@ private void DrawImmediate(Vector3 Position, Vector3 Direction, Vector3 Up, Vect
GL.PopMatrix();
return;
}
- GL.Enable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(true);
GL.BindTexture(TextureTarget.Texture2D, TextureIndex.OpenGlTextures[(int)OpenGlTextureWrapMode.ClampClamp].Name);
Vector2[][] t = new Vector2[6][];
t[0] = new[] { new Vector2(1.0, 0.0), new Vector2(1.0, 1.0), new Vector2(0.0, 1.0), new Vector2(0.0, 0.0) };
diff --git a/source/LibRender2/Primitives/Particle.cs b/source/LibRender2/Primitives/Particle.cs
index 7907cf29ce..5129ad3c02 100644
--- a/source/LibRender2/Primitives/Particle.cs
+++ b/source/LibRender2/Primitives/Particle.cs
@@ -1,4 +1,4 @@
-//Simplified BSD License (BSD-2-Clause)
+//Simplified BSD License (BSD-2-Clause)
//
//Copyright (c) 2025, The OpenBVE Project
//
@@ -109,11 +109,11 @@ public void Draw(int particleIndex, Vector3 worldPosition, Vector3 worldDirectio
{
renderer.UnsetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
- GL.DepthMask(true);
+ renderer.Device.SetDepthMask(true);
DrawRetained(particleIndex, worldPosition, worldDirection, worldUp, worldSide, size, texture, opacity);
renderer.SetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Less, 1.0f);
- GL.DepthMask(false);
+ renderer.Device.SetDepthMask(false);
DrawRetained(particleIndex, worldPosition, worldDirection, worldUp, worldSide, size, texture, opacity);
}
}
@@ -134,17 +134,17 @@ private void DrawRetained(int particleIndex, Vector3 worldPosition, Vector3 worl
// texture
if (texture != null && renderer.currentHost.LoadTexture(ref texture, OpenGlTextureWrapMode.ClampClamp))
{
- GL.Enable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(true);
GL.BindTexture(TextureTarget.Texture2D, texture.OpenGlTextures[(int)OpenGlTextureWrapMode.ClampClamp].Name);
}
else
{
- GL.Disable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(false);
}
particlesVAO[particleIndex].Bind();
particlesVAO[particleIndex].Draw(PrimitiveType.Quads);
- GL.Disable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(false);
}
diff --git a/source/LibRender2/Primitives/Picturebox.cs b/source/LibRender2/Primitives/Picturebox.cs
index 986db85fe6..3e91d223ef 100644
--- a/source/LibRender2/Primitives/Picturebox.cs
+++ b/source/LibRender2/Primitives/Picturebox.cs
@@ -25,7 +25,7 @@ public override void Draw()
return;
}
- GL.DepthMask(true);
+ Renderer.Device.SetDepthMask(true);
Vector2 newSize;
switch (SizeMode)
{
diff --git a/source/LibRender2/Primitives/Rectangle.cs b/source/LibRender2/Primitives/Rectangle.cs
index fec60ae9c7..fbc461b6ea 100644
--- a/source/LibRender2/Primitives/Rectangle.cs
+++ b/source/LibRender2/Primitives/Rectangle.cs
@@ -64,11 +64,11 @@ public void DrawAlpha(Texture texture, Vector2 point, Vector2 size, Color128? co
{
renderer.UnsetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
- GL.DepthMask(true);
+ renderer.Device.SetDepthMask(true);
Draw(texture, point, size, color, textureCoordinates, wrapMode);
renderer.SetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Less, 1.0f);
- GL.DepthMask(false);
+ renderer.Device.SetDepthMask(false);
Draw(texture, point, size, color, textureCoordinates, wrapMode);
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
}
@@ -176,7 +176,7 @@ private void DrawImmediate(Texture texture, Vector2 point, Vector2 size, Color12
}
if (texture == null || !renderer.currentHost.LoadTexture(ref texture, (OpenGlTextureWrapMode)wrapMode))
{
- GL.Disable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(false);
if (color.HasValue)
{
@@ -192,7 +192,7 @@ private void DrawImmediate(Texture texture, Vector2 point, Vector2 size, Color12
}
else
{
- GL.Enable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(true);
GL.BindTexture(TextureTarget.Texture2D, texture.OpenGlTextures[(int)wrapMode].Name);
if (color.HasValue)
@@ -225,7 +225,7 @@ private void DrawImmediate(Texture texture, Vector2 point, Vector2 size, Color12
GL.Vertex2(point.X, point.Y + size.Y);
}
GL.End();
- GL.Disable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(false);
}
GL.PopMatrix();
diff --git a/source/LibRender2/Smoke/ParticleSource.cs b/source/LibRender2/Smoke/ParticleSource.cs
index 542b5f2841..5a93da0fc9 100644
--- a/source/LibRender2/Smoke/ParticleSource.cs
+++ b/source/LibRender2/Smoke/ParticleSource.cs
@@ -242,9 +242,9 @@ public void Update(double timeElapsed, bool currentlyVisible)
return;
}
- GL.Enable(EnableCap.CullFace);
- GL.Enable(EnableCap.DepthTest);
- GL.DepthMask(true);
+ Renderer.Device.SetCullFace(true);
+ Renderer.Device.SetDepthTest(true);
+ Renderer.Device.SetDepthMask(true);
if (ParticleTexture == null)
{
diff --git a/source/LibRender2/Text/OpenGlString.cs b/source/LibRender2/Text/OpenGlString.cs
index 85af581ca3..b85fb427d9 100644
--- a/source/LibRender2/Text/OpenGlString.cs
+++ b/source/LibRender2/Text/OpenGlString.cs
@@ -120,7 +120,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
/*
* Render the string.
* */
- GL.Enable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(true);
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
@@ -153,7 +153,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
/*
* In the first pass, mask off the background with pure black.
* */
- GL.BlendFunc(BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
+ renderer.Device.SetBlend(true, BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
GL.Begin(PrimitiveType.Quads);
GL.Color4(color.A, color.A, color.A, 1.0f);
GL.TexCoord2(data.TextureCoordinates.X, data.TextureCoordinates.Y);
@@ -169,7 +169,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
/*
* In the second pass, add the character onto the background.
* */
- GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
+ renderer.Device.SetBlend(true, BlendingFactor.SrcAlpha, BlendingFactor.One);
GL.Begin(PrimitiveType.Quads);
GL.Color4(color.R, color.G, color.B, color.A);
GL.TexCoord2(data.TextureCoordinates.X, data.TextureCoordinates.Y);
@@ -187,7 +187,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
}
renderer.RestoreBlendFunc();
- GL.Disable(EnableCap.Texture2D);
+ renderer.Device.SetTexture2D(false);
GL.PopMatrix();
@@ -215,7 +215,7 @@ private void DrawWithShader(string text, OpenGlFont font, double left, double to
/*
* In the first pass, mask off the background with pure black.
*/
- GL.BlendFunc(BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
+ renderer.Device.SetBlend(true, BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
Shader.SetColor(new Color128(color.A, color.A, color.A, 1.0f));
Shader.SetPoint(new Vector2(x, y));
Shader.SetSize(data.PhysicalSize);
@@ -226,7 +226,7 @@ private void DrawWithShader(string text, OpenGlFont font, double left, double to
*/
renderer.dummyVao.Bind();
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 6);
- GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
+ renderer.Device.SetBlend(true, BlendingFactor.SrcAlpha, BlendingFactor.One);
Shader.SetColor(color);
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 6);
}
diff --git a/source/OpenBVE/Graphics/NewRenderer.cs b/source/OpenBVE/Graphics/NewRenderer.cs
index 7d423fb7df..4b483f82ad 100644
--- a/source/OpenBVE/Graphics/NewRenderer.cs
+++ b/source/OpenBVE/Graphics/NewRenderer.cs
@@ -18,6 +18,7 @@
using OpenBveApi.Objects;
using OpenBveApi.Routes;
using OpenBveApi.Textures;
+using OpenBveApi.World;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
@@ -292,8 +293,8 @@ public void Execute(RenderContext context)
{
renderer.ResetOpenGlState();
renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
- GL.Disable(EnableCap.DepthTest);
- GL.DepthMask(false);
+ renderer.Device.SetDepthTest(false);
+ renderer.Device.SetDepthMask(false);
renderer.OptionLighting = false;
if (Interface.CurrentOptions.MotionBlur != MotionBlurMode.None)
diff --git a/source/OpenBVE/System/GameWindow.cs b/source/OpenBVE/System/GameWindow.cs
index 41e931bf0b..01d526e403 100644
--- a/source/OpenBVE/System/GameWindow.cs
+++ b/source/OpenBVE/System/GameWindow.cs
@@ -493,6 +493,7 @@ protected override void OnClosing(CancelEventArgs e)
}
Program.Renderer.TextureManager.UnloadAllTextures(false);
Program.Renderer.Scene.VisibilityThreadShouldRun = false;
+ Program.Renderer.DeInitialize();
for (int i = 0; i < InputDevicePlugin.AvailablePluginInfos.Count; i++)
{
InputDevicePlugin.CallPluginUnload(i);
diff --git a/source/OpenBveApi/Math/Vectors/Vector3.cs b/source/OpenBveApi/Math/Vectors/Vector3.cs
index d8c270f4e9..9d9b5a98dd 100644
--- a/source/OpenBveApi/Math/Vectors/Vector3.cs
+++ b/source/OpenBveApi/Math/Vectors/Vector3.cs
@@ -322,6 +322,10 @@ public static implicit operator Vector3f(Vector3 v)
/// The multiplied vector
public static Vector3 operator *(Vector3 v, Transformation t)
{
+ if (t == null)
+ {
+ return v;
+ }
v = t.X * v.X + t.Y * v.Y + t.Z * v.Z;
return v;
}
@@ -498,6 +502,10 @@ public void Rotate(Orientation3 orientation) {
/// The transformation
public void Rotate(Transformation transformation)
{
+ if (transformation == null)
+ {
+ return;
+ }
double x = transformation.X.X * X + transformation.Y.X * Y + transformation.Z.X * Z;
double y = transformation.X.Y * X + transformation.Y.Y * Y + transformation.Z.Y * Z;
double z = transformation.X.Z * X + transformation.Y.Z * Y + transformation.Z.Z * Z;
diff --git a/source/OpenBveApi/World/Transformations.cs b/source/OpenBveApi/World/Transformations.cs
index 0f3a786d0e..34b68b6db4 100644
--- a/source/OpenBveApi/World/Transformations.cs
+++ b/source/OpenBveApi/World/Transformations.cs
@@ -1,4 +1,4 @@
-using OpenBveApi.Math;
+using OpenBveApi.Math;
namespace OpenBveApi.World
{
@@ -81,9 +81,9 @@ public Transformation(double Yaw, double Pitch, double Roll)
///
public Transformation(Transformation Transformation, double Yaw, double Pitch, double Roll)
{
- X = new Vector3(Transformation.X);
- Y = new Vector3(Transformation.Y);
- Z = new Vector3(Transformation.Z);
+ X = new Vector3(Transformation?.X ?? Vector3.Right);
+ Y = new Vector3(Transformation?.Y ?? Vector3.Down);
+ Z = new Vector3(Transformation?.Z ?? Vector3.Forward);
X.Rotate(Y, Yaw);
Z.Rotate(Y, Yaw);
// In the left-handed coordinate system, the clock-wise rotation is positive when the origin is viewed from the positive direction of the axis.
@@ -99,9 +99,10 @@ public Transformation(Transformation Transformation, double Yaw, double Pitch, d
/// The transformation to apply second
public Transformation(Transformation firstTransformation, Transformation secondTransformation)
{
- X = new Vector3(firstTransformation.X);
- Y = new Vector3(firstTransformation.Y);
- Z = new Vector3(firstTransformation.Z);
+ X = new Vector3(firstTransformation?.X ?? Vector3.Right);
+ Y = new Vector3(firstTransformation?.Y ?? Vector3.Down);
+ Z = new Vector3(firstTransformation?.Z ?? Vector3.Forward);
+ secondTransformation = secondTransformation ?? NullTransformation;
X.Rotate(secondTransformation);
Y.Rotate(secondTransformation);
Z.Rotate(secondTransformation);
From 9d05072e874b4b1a8667b85535454dc0df2f1f44 Mon Sep 17 00:00:00 2001
From: adfriz <76892624+adfriz@users.noreply.github.com>
Date: Sun, 26 Apr 2026 20:55:39 +0700
Subject: [PATCH 4/9] Revert "update"
This reverts commit 03dd64bd092e01a08be1729792b66080dc73f791.
---
source/LibRender2/Backgrounds/Background.cs | 24 ++--
source/LibRender2/BaseRenderer.cs | 110 +++++++++++++------
source/LibRender2/Managers/SceneManager.cs | 2 +-
source/LibRender2/MotionBlur/MotionBlur.cs | 6 +-
source/LibRender2/Pipeline/GraphicsDevice.cs | 87 +--------------
source/LibRender2/Primitives/Cube.cs | 10 +-
source/LibRender2/Primitives/Particle.cs | 12 +-
source/LibRender2/Primitives/Picturebox.cs | 2 +-
source/LibRender2/Primitives/Rectangle.cs | 10 +-
source/LibRender2/Smoke/ParticleSource.cs | 6 +-
source/LibRender2/Text/OpenGlString.cs | 12 +-
source/OpenBVE/Graphics/NewRenderer.cs | 5 +-
source/OpenBVE/System/GameWindow.cs | 1 -
source/OpenBveApi/Math/Vectors/Vector3.cs | 8 --
source/OpenBveApi/World/Transformations.cs | 15 ++-
15 files changed, 128 insertions(+), 182 deletions(-)
diff --git a/source/LibRender2/Backgrounds/Background.cs b/source/LibRender2/Backgrounds/Background.cs
index 5567c92f54..ee0d16b0d0 100644
--- a/source/LibRender2/Backgrounds/Background.cs
+++ b/source/LibRender2/Backgrounds/Background.cs
@@ -124,11 +124,11 @@ private void RenderStaticBackgroundRetained(StaticBackground data, float alpha,
renderer.LastBoundTexture = t.OpenGlTextures[(int)OpenGlTextureWrapMode.RepeatClamp];
if (alpha == 1.0f)
{
- renderer.Device.SetBlend(false);
+ GL.Disable(EnableCap.Blend);
}
else
{
- renderer.Device.SetBlend(true);
+ GL.Enable(EnableCap.Blend);
}
if (data.VAO == null)
@@ -201,15 +201,15 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadMatrix(ref lookat);
- renderer.Device.SetLighting(false);
- renderer.Device.SetTexture2D(true);
+ GL.Disable(EnableCap.Lighting);
+ GL.Enable(EnableCap.Texture2D);
if (alpha == 1.0f)
{
- renderer.Device.SetBlend(false);
+ GL.Disable(EnableCap.Blend);
}
else
{
- renderer.Device.SetBlend(true);
+ GL.Enable(EnableCap.Blend);
renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
}
GL.BindTexture(TextureTarget.Texture2D, t.OpenGlTextures[(int)OpenGlTextureWrapMode.RepeatClamp].Name);
@@ -217,13 +217,13 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
GL.Color4(1.0f, 1.0f, 1.0f, alpha);
if (renderer.Fog.Enabled)
{
- renderer.Device.SetFog(true);
+ GL.Enable(EnableCap.Fog);
}
if (data.DisplayList > 0)
{
GL.CallList(data.DisplayList);
- renderer.Device.SetTexture2D(false);
- renderer.Device.SetBlend(true);
+ GL.Disable(EnableCap.Texture2D);
+ GL.Enable(EnableCap.Blend);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
@@ -300,8 +300,8 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
}
GL.EndList();
GL.CallList(data.DisplayList);
- renderer.Device.SetTexture2D(false);
- renderer.Device.SetBlend(true);
+ GL.Disable(EnableCap.Texture2D);
+ GL.Enable(EnableCap.Blend);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
@@ -312,7 +312,7 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
/// The background object
private void RenderBackgroundObject(BackgroundObject data)
{
- renderer.Device.SetBlend(true);
+ GL.Enable(EnableCap.Blend);
// alpha test
renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
if (renderer.AvailableNewRenderer)
diff --git a/source/LibRender2/BaseRenderer.cs b/source/LibRender2/BaseRenderer.cs
index 96bc9d5d9d..d35640fb51 100644
--- a/source/LibRender2/BaseRenderer.cs
+++ b/source/LibRender2/BaseRenderer.cs
@@ -258,11 +258,11 @@ public void BindCSMToDefaultShader()
public double FrameRate = 1.0;
/// Whether Blend is enabled in openGL
- public bool BlendEnabled => Device.BlendEnabled;
+ private bool blendEnabled;
- private BlendingFactor blendSrcFactor = BlendingFactor.SrcAlpha;
+ private BlendingFactor blendSrcFactor;
- private BlendingFactor blendDestFactor = BlendingFactor.OneMinusSrcAlpha;
+ private BlendingFactor blendDestFactor;
/// Whether Alpha Testing is enabled in openGL
private bool alphaTestEnabled;
@@ -465,7 +465,8 @@ public virtual void Initialize()
}
GL.ClearColor(0.67f, 0.67f, 0.67f, 1.0f);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
- Device.SetDepthTest(true, DepthFunction.Lequal);
+ GL.Enable(EnableCap.DepthTest);
+ GL.DepthFunc(DepthFunction.Lequal);
SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
if (currentOptions.ForceForwardsCompatibleContext == false)
{
@@ -473,19 +474,20 @@ public virtual void Initialize()
GL.Hint(HintTarget.FogHint, HintMode.Fastest);
GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Fastest);
GL.Hint(HintTarget.GenerateMipmapHint, HintMode.Nicest);
- Device.SetLighting(false);
- Device.SetFog(false);
+ GL.Disable(EnableCap.Lighting);
+ GL.Disable(EnableCap.Fog);
GL.Hint(HintTarget.LineSmoothHint, HintMode.Fastest);
GL.Hint(HintTarget.PointSmoothHint, HintMode.Fastest);
GL.Hint(HintTarget.PolygonSmoothHint, HintMode.Fastest);
}
- Device.SetCullFace(true, CullFaceMode.Front);
+ GL.Enable(EnableCap.CullFace);
+ GL.CullFace(CullFaceMode.Front);
GL.Disable(EnableCap.Dither);
if (!AvailableNewRenderer)
{
- Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Texture2D);
GL.Fog(FogParameter.FogMode, (int)FogMode.Linear);
}
@@ -665,19 +667,21 @@ public void ReleaseResources()
///
public virtual void ResetOpenGlState()
{
- Device.SetCullFace(true, CullFaceMode.Front);
+ GL.Enable(EnableCap.CullFace);
+ GL.CullFace(CullFaceMode.Front);
if (!AvailableNewRenderer)
{
- Device.SetLighting(false);
- Device.SetFog(false);
- Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Lighting);
+ GL.Disable(EnableCap.Fog);
+ GL.Disable(EnableCap.Texture2D);
}
SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
UnsetBlendFunc();
- Device.SetDepthTest(true, DepthFunction.Lequal);
+ GL.Enable(EnableCap.DepthTest);
+ GL.DepthFunc(DepthFunction.Lequal);
GL.Disable(EnableCap.DepthClamp);
- Device.SetDepthMask(true);
+ GL.DepthMask(true);
SetAlphaFunc(AlphaFunction.Greater, 0.9f);
}
@@ -881,24 +885,35 @@ public void ResetShader(Shader shader)
public void SetBlendFunc()
{
- Device.SetBlend(true, blendSrcFactor, blendDestFactor);
+ SetBlendFunc(blendSrcFactor, blendDestFactor);
}
public void SetBlendFunc(BlendingFactor srcFactor, BlendingFactor destFactor)
{
+ blendEnabled = true;
blendSrcFactor = srcFactor;
blendDestFactor = destFactor;
- Device.SetBlend(true, srcFactor, destFactor);
+ GL.Enable(EnableCap.Blend);
+ GL.BlendFunc(srcFactor, destFactor);
}
public void UnsetBlendFunc()
{
- Device.SetBlend(false);
+ blendEnabled = false;
+ GL.Disable(EnableCap.Blend);
}
public void RestoreBlendFunc()
{
- Device.SetBlend(Device.BlendEnabled, blendSrcFactor, blendDestFactor);
+ if (blendEnabled)
+ {
+ GL.Enable(EnableCap.Blend);
+ GL.BlendFunc(blendSrcFactor, blendDestFactor);
+ }
+ else
+ {
+ GL.Disable(EnableCap.Blend);
+ }
}
/// Specifies the OpenGL alpha function to perform
@@ -920,7 +935,12 @@ public void SetAlphaFunc(AlphaFunction comparison, float value)
CurrentShader.SetAlphaTest(true);
CurrentShader.SetAlphaFunction(comparison, value);
}
- Device.SetAlphaTest(true, comparison, value);
+ else
+ {
+ GL.Enable(EnableCap.AlphaTest);
+ GL.AlphaFunc(comparison, value);
+ }
+
}
/// Disables OpenGL alpha testing
@@ -931,7 +951,11 @@ public void UnsetAlphaFunc()
{
CurrentShader.SetAlphaTest(false);
}
- Device.SetAlphaTest(false);
+ else
+ {
+ GL.Disable(EnableCap.AlphaTest);
+ }
+
}
/// Restores the OpenGL alpha function to it's previous state
@@ -939,11 +963,28 @@ public void RestoreAlphaFunc()
{
if (alphaTestEnabled)
{
- SetAlphaFunc(alphaFuncComparison, alphaFuncValue);
+ if (AvailableNewRenderer)
+ {
+ CurrentShader.SetAlphaTest(true);
+ CurrentShader.SetAlphaFunction(alphaFuncComparison, alphaFuncValue);
+ }
+ else
+ {
+ GL.Enable(EnableCap.AlphaTest);
+ GL.AlphaFunc(alphaFuncComparison, alphaFuncValue);
+ }
+
}
else
{
- UnsetAlphaFunc();
+ if (AvailableNewRenderer)
+ {
+ CurrentShader.SetAlphaTest(false);
+ }
+ else
+ {
+ GL.Disable(EnableCap.AlphaTest);
+ }
}
}
@@ -1007,13 +1048,13 @@ public void RenderFace(Shader shader, ObjectState state, MeshFace face, bool deb
if (!OptionBackFaceCulling || (face.Flags & FaceFlags.Face2Mask) != 0)
{
- Device.SetCullFace(false);
+ GL.Disable(EnableCap.CullFace);
}
else if (OptionBackFaceCulling)
{
if ((face.Flags & FaceFlags.Face2Mask) == 0)
{
- Device.SetCullFace(true);
+ GL.Enable(EnableCap.CullFace);
}
}
@@ -1232,13 +1273,13 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
if (!OptionBackFaceCulling || (face.Flags & FaceFlags.Face2Mask) != 0)
{
- Device.SetCullFace(false);
+ GL.Disable(EnableCap.CullFace);
}
else if (OptionBackFaceCulling)
{
if ((face.Flags & FaceFlags.Face2Mask) == 0)
{
- Device.SetCullFace(true);
+ GL.Enable(EnableCap.CullFace);
}
}
@@ -1282,7 +1323,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
{
if (OptionLighting)
{
- Device.SetLighting(true);
+ GL.Enable(EnableCap.Lighting);
}
}
@@ -1291,7 +1332,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
// fog
if (Fog.Enabled)
{
- Device.SetFog(true);
+ GL.Enable(EnableCap.Fog);
}
PrimitiveType drawMode;
@@ -1340,7 +1381,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
// ReSharper disable once PossibleInvalidOperationException
if (currentHost.LoadTexture(ref material.DaytimeTexture, (OpenGlTextureWrapMode)material.WrapMode))
{
- Device.SetTexture2D(true);
+ GL.Enable(EnableCap.Texture2D);
if (LastBoundTexture != material.DaytimeTexture.OpenGlTextures[(int)material.WrapMode])
{
GL.BindTexture(TextureTarget.Texture2D, material.DaytimeTexture.OpenGlTextures[(int)material.WrapMode].Name);
@@ -1355,7 +1396,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
{
factor = 1.0f;
SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
- Device.SetFog(false);
+ GL.Disable(EnableCap.Fog);
}
else if (material.NighttimeTexture == null)
{
@@ -1368,7 +1409,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
if ((material.Flags & MaterialFlags.DisableLighting) != 0)
{
- Device.SetLighting(false);
+ GL.Disable(EnableCap.Lighting);
}
float alphaFactor = distanceFactor;
@@ -1408,7 +1449,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
if (blendFactor != 0 && material.NighttimeTexture != null && currentHost.LoadTexture(ref material.NighttimeTexture, (OpenGlTextureWrapMode)material.WrapMode))
{
// texture
- Device.SetTexture2D(true);
+ GL.Enable(EnableCap.Texture2D);
if (LastBoundTexture != material.NighttimeTexture.OpenGlTextures[(int)material.WrapMode])
{
GL.BindTexture(TextureTarget.Texture2D, material.NighttimeTexture.OpenGlTextures[(int)material.WrapMode].Name);
@@ -1418,7 +1459,8 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
Device.SetBlend(true);
// alpha test
- Device.SetAlphaTest(true, AlphaFunction.Greater, 0.0f);
+ GL.Enable(EnableCap.AlphaTest);
+ GL.AlphaFunc(AlphaFunction.Greater, 0.0f);
// blend mode
float alphaFactor = distanceFactor * blendFactor;
@@ -1452,7 +1494,7 @@ public void RenderFaceImmediateMode(ObjectState state, MeshFace face, Matrix4D m
RestoreAlphaFunc();
}
- Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Texture2D);
// normals
if (OptionNormals)
diff --git a/source/LibRender2/Managers/SceneManager.cs b/source/LibRender2/Managers/SceneManager.cs
index 8aa4ffb328..8144716da2 100644
--- a/source/LibRender2/Managers/SceneManager.cs
+++ b/source/LibRender2/Managers/SceneManager.cs
@@ -294,7 +294,7 @@ public void UpdateViewingDistances(double backgroundImageDistance)
public int CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, ObjectDisposalMode AccurateObjectDisposal, ObjectCreationParameters Parameters, double BlockLength)
{
Matrix4D Translate = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z);
- Matrix4D Rotate = (Matrix4D)new Transformation(LocalTransformation ?? Transformation.NullTransformation, WorldTransformation ?? Transformation.NullTransformation);
+ Matrix4D Rotate = (Matrix4D)new Transformation(LocalTransformation, WorldTransformation);
return CreateStaticObject(Position, Prototype, LocalTransformation, Rotate, Translate, AccurateObjectDisposal, Parameters, BlockLength);
}
diff --git a/source/LibRender2/MotionBlur/MotionBlur.cs b/source/LibRender2/MotionBlur/MotionBlur.cs
index da460cd5d2..5c431e6aad 100644
--- a/source/LibRender2/MotionBlur/MotionBlur.cs
+++ b/source/LibRender2/MotionBlur/MotionBlur.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using OpenTK.Graphics.OpenGL;
namespace LibRender2.MotionBlurs
@@ -55,7 +55,7 @@ public void RenderFullscreen(MotionBlurMode mode, double frameRate, double speed
return;
}
renderer.LastBoundTexture = null;
- renderer.Device.SetTexture2D(true);
+ GL.Enable(EnableCap.Texture2D);
// render
if (PixelBufferOpenGlTextureIndex >= 0)
@@ -120,7 +120,7 @@ public void RenderFullscreen(MotionBlurMode mode, double frameRate, double speed
GL.BindTexture(TextureTarget.Texture2D, PixelBufferOpenGlTextureIndex);
GL.CopyTexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgb8, 0, 0, renderer.Screen.Width, renderer.Screen.Height, 0);
}
- renderer.Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Texture2D);
}
}
}
diff --git a/source/LibRender2/Pipeline/GraphicsDevice.cs b/source/LibRender2/Pipeline/GraphicsDevice.cs
index 1bb615b219..b717ef3c79 100644
--- a/source/LibRender2/Pipeline/GraphicsDevice.cs
+++ b/source/LibRender2/Pipeline/GraphicsDevice.cs
@@ -8,28 +8,16 @@ namespace LibRender2.Pipeline
public class GraphicsDevice
{
private bool blendEnabled;
- public bool BlendEnabled => blendEnabled;
private BlendingFactor blendSrcFactor;
private BlendingFactor blendDestFactor;
private bool depthTestEnabled = true;
- private DepthFunction depthFunction = DepthFunction.Lequal; // less than or equal to
+ private DepthFunction depthFunction = DepthFunction.Lequal;
private bool depthMask = true;
private bool cullFaceEnabled = true;
private CullFaceMode cullFaceMode = CullFaceMode.Front;
- private bool lightingEnabled;
- private bool fogEnabled;
- private bool texture2DEnabled;
-
- private bool alphaTestEnabled;
- public bool AlphaTestEnabled => alphaTestEnabled;
- private AlphaFunction alphaTestFunction = AlphaFunction.Greater;
- public AlphaFunction AlphaTestFunction => alphaTestFunction;
- private float alphaTestThreshold;
- public float AlphaTestThreshold => alphaTestThreshold;
-
///
/// Sets the blending state.
///
@@ -100,65 +88,6 @@ public void SetCullFace(bool enabled, CullFaceMode mode = CullFaceMode.Front)
}
}
- ///
- /// Sets the lighting state.
- ///
- public void SetLighting(bool enabled)
- {
- if (lightingEnabled != enabled)
- {
- lightingEnabled = enabled;
- if (enabled) GL.Enable(EnableCap.Lighting);
- else GL.Disable(EnableCap.Lighting);
- }
- }
-
- ///
- /// Sets the fog state.
- ///
- public void SetFog(bool enabled)
- {
- if (fogEnabled != enabled)
- {
- fogEnabled = enabled;
- if (enabled) GL.Enable(EnableCap.Fog);
- else GL.Disable(EnableCap.Fog);
- }
- }
-
- ///
- /// Sets the texture 2D state.
- ///
- public void SetTexture2D(bool enabled)
- {
- if (texture2DEnabled != enabled)
- {
- texture2DEnabled = enabled;
- if (enabled) GL.Enable(EnableCap.Texture2D);
- else GL.Disable(EnableCap.Texture2D);
- }
- }
-
- ///
- /// Sets the alpha test state.
- ///
- public void SetAlphaTest(bool enabled, AlphaFunction function = AlphaFunction.Greater, float threshold = 0.0f)
- {
- if (alphaTestEnabled != enabled)
- {
- alphaTestEnabled = enabled;
- if (enabled) GL.Enable(EnableCap.AlphaTest);
- else GL.Disable(EnableCap.AlphaTest);
- }
-
- if (enabled && (alphaTestFunction != function || alphaTestThreshold != threshold))
- {
- alphaTestFunction = function;
- alphaTestThreshold = threshold;
- GL.AlphaFunc(function, threshold);
- }
- }
-
///
/// Resets the cached state to match the current OpenGL defaults or a known state.
///
@@ -180,20 +109,6 @@ public void Reset()
cullFaceEnabled = true;
GL.CullFace(CullFaceMode.Back);
cullFaceMode = CullFaceMode.Back;
-
- GL.Disable(EnableCap.Lighting);
- lightingEnabled = false;
-
- GL.Disable(EnableCap.Fog);
- fogEnabled = false;
-
- GL.Disable(EnableCap.Texture2D);
- texture2DEnabled = false;
-
- GL.Disable(EnableCap.AlphaTest);
- alphaTestEnabled = false;
- alphaTestFunction = AlphaFunction.Greater;
- alphaTestThreshold = 0.0f;
}
}
}
diff --git a/source/LibRender2/Primitives/Cube.cs b/source/LibRender2/Primitives/Cube.cs
index f405ca2753..a32142556e 100644
--- a/source/LibRender2/Primitives/Cube.cs
+++ b/source/LibRender2/Primitives/Cube.cs
@@ -359,18 +359,18 @@ private void DrawRetained(VertexArrayObject VAO, Vector3 Position, Vector3 Direc
// texture
if (TextureIndex != null && renderer.currentHost.LoadTexture(ref TextureIndex, OpenGlTextureWrapMode.ClampClamp))
{
- renderer.Device.SetTexture2D(true);
+ GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, TextureIndex.OpenGlTextures[(int)OpenGlTextureWrapMode.ClampClamp].Name);
}
else
{
- renderer.Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Texture2D);
}
// render polygon
VAO.Bind();
VAO.Draw(PrimitiveType.Triangles);
- renderer.Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Texture2D);
}
/// Draws a 3D cube in immediate mode
@@ -422,7 +422,7 @@ private void DrawImmediate(Vector3 Position, Vector3 Direction, Vector3 Up, Vect
Faces[5] = new[] { 6, 2, 1, 5 };
if (TextureIndex == null || !renderer.currentHost.LoadTexture(ref TextureIndex, OpenGlTextureWrapMode.ClampClamp))
{
- renderer.Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Texture2D);
for (int i = 0; i < 6; i++)
{
GL.Begin(PrimitiveType.Quads);
@@ -438,7 +438,7 @@ private void DrawImmediate(Vector3 Position, Vector3 Direction, Vector3 Up, Vect
GL.PopMatrix();
return;
}
- renderer.Device.SetTexture2D(true);
+ GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, TextureIndex.OpenGlTextures[(int)OpenGlTextureWrapMode.ClampClamp].Name);
Vector2[][] t = new Vector2[6][];
t[0] = new[] { new Vector2(1.0, 0.0), new Vector2(1.0, 1.0), new Vector2(0.0, 1.0), new Vector2(0.0, 0.0) };
diff --git a/source/LibRender2/Primitives/Particle.cs b/source/LibRender2/Primitives/Particle.cs
index 5129ad3c02..7907cf29ce 100644
--- a/source/LibRender2/Primitives/Particle.cs
+++ b/source/LibRender2/Primitives/Particle.cs
@@ -1,4 +1,4 @@
-//Simplified BSD License (BSD-2-Clause)
+//Simplified BSD License (BSD-2-Clause)
//
//Copyright (c) 2025, The OpenBVE Project
//
@@ -109,11 +109,11 @@ public void Draw(int particleIndex, Vector3 worldPosition, Vector3 worldDirectio
{
renderer.UnsetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
- renderer.Device.SetDepthMask(true);
+ GL.DepthMask(true);
DrawRetained(particleIndex, worldPosition, worldDirection, worldUp, worldSide, size, texture, opacity);
renderer.SetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Less, 1.0f);
- renderer.Device.SetDepthMask(false);
+ GL.DepthMask(false);
DrawRetained(particleIndex, worldPosition, worldDirection, worldUp, worldSide, size, texture, opacity);
}
}
@@ -134,17 +134,17 @@ private void DrawRetained(int particleIndex, Vector3 worldPosition, Vector3 worl
// texture
if (texture != null && renderer.currentHost.LoadTexture(ref texture, OpenGlTextureWrapMode.ClampClamp))
{
- renderer.Device.SetTexture2D(true);
+ GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, texture.OpenGlTextures[(int)OpenGlTextureWrapMode.ClampClamp].Name);
}
else
{
- renderer.Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Texture2D);
}
particlesVAO[particleIndex].Bind();
particlesVAO[particleIndex].Draw(PrimitiveType.Quads);
- renderer.Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Texture2D);
}
diff --git a/source/LibRender2/Primitives/Picturebox.cs b/source/LibRender2/Primitives/Picturebox.cs
index 3e91d223ef..986db85fe6 100644
--- a/source/LibRender2/Primitives/Picturebox.cs
+++ b/source/LibRender2/Primitives/Picturebox.cs
@@ -25,7 +25,7 @@ public override void Draw()
return;
}
- Renderer.Device.SetDepthMask(true);
+ GL.DepthMask(true);
Vector2 newSize;
switch (SizeMode)
{
diff --git a/source/LibRender2/Primitives/Rectangle.cs b/source/LibRender2/Primitives/Rectangle.cs
index fbc461b6ea..fec60ae9c7 100644
--- a/source/LibRender2/Primitives/Rectangle.cs
+++ b/source/LibRender2/Primitives/Rectangle.cs
@@ -64,11 +64,11 @@ public void DrawAlpha(Texture texture, Vector2 point, Vector2 size, Color128? co
{
renderer.UnsetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
- renderer.Device.SetDepthMask(true);
+ GL.DepthMask(true);
Draw(texture, point, size, color, textureCoordinates, wrapMode);
renderer.SetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Less, 1.0f);
- renderer.Device.SetDepthMask(false);
+ GL.DepthMask(false);
Draw(texture, point, size, color, textureCoordinates, wrapMode);
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
}
@@ -176,7 +176,7 @@ private void DrawImmediate(Texture texture, Vector2 point, Vector2 size, Color12
}
if (texture == null || !renderer.currentHost.LoadTexture(ref texture, (OpenGlTextureWrapMode)wrapMode))
{
- renderer.Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Texture2D);
if (color.HasValue)
{
@@ -192,7 +192,7 @@ private void DrawImmediate(Texture texture, Vector2 point, Vector2 size, Color12
}
else
{
- renderer.Device.SetTexture2D(true);
+ GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, texture.OpenGlTextures[(int)wrapMode].Name);
if (color.HasValue)
@@ -225,7 +225,7 @@ private void DrawImmediate(Texture texture, Vector2 point, Vector2 size, Color12
GL.Vertex2(point.X, point.Y + size.Y);
}
GL.End();
- renderer.Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Texture2D);
}
GL.PopMatrix();
diff --git a/source/LibRender2/Smoke/ParticleSource.cs b/source/LibRender2/Smoke/ParticleSource.cs
index 5a93da0fc9..542b5f2841 100644
--- a/source/LibRender2/Smoke/ParticleSource.cs
+++ b/source/LibRender2/Smoke/ParticleSource.cs
@@ -242,9 +242,9 @@ public void Update(double timeElapsed, bool currentlyVisible)
return;
}
- Renderer.Device.SetCullFace(true);
- Renderer.Device.SetDepthTest(true);
- Renderer.Device.SetDepthMask(true);
+ GL.Enable(EnableCap.CullFace);
+ GL.Enable(EnableCap.DepthTest);
+ GL.DepthMask(true);
if (ParticleTexture == null)
{
diff --git a/source/LibRender2/Text/OpenGlString.cs b/source/LibRender2/Text/OpenGlString.cs
index b85fb427d9..85af581ca3 100644
--- a/source/LibRender2/Text/OpenGlString.cs
+++ b/source/LibRender2/Text/OpenGlString.cs
@@ -120,7 +120,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
/*
* Render the string.
* */
- renderer.Device.SetTexture2D(true);
+ GL.Enable(EnableCap.Texture2D);
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
@@ -153,7 +153,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
/*
* In the first pass, mask off the background with pure black.
* */
- renderer.Device.SetBlend(true, BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
+ GL.BlendFunc(BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
GL.Begin(PrimitiveType.Quads);
GL.Color4(color.A, color.A, color.A, 1.0f);
GL.TexCoord2(data.TextureCoordinates.X, data.TextureCoordinates.Y);
@@ -169,7 +169,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
/*
* In the second pass, add the character onto the background.
* */
- renderer.Device.SetBlend(true, BlendingFactor.SrcAlpha, BlendingFactor.One);
+ GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
GL.Begin(PrimitiveType.Quads);
GL.Color4(color.R, color.G, color.B, color.A);
GL.TexCoord2(data.TextureCoordinates.X, data.TextureCoordinates.Y);
@@ -187,7 +187,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
}
renderer.RestoreBlendFunc();
- renderer.Device.SetTexture2D(false);
+ GL.Disable(EnableCap.Texture2D);
GL.PopMatrix();
@@ -215,7 +215,7 @@ private void DrawWithShader(string text, OpenGlFont font, double left, double to
/*
* In the first pass, mask off the background with pure black.
*/
- renderer.Device.SetBlend(true, BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
+ GL.BlendFunc(BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
Shader.SetColor(new Color128(color.A, color.A, color.A, 1.0f));
Shader.SetPoint(new Vector2(x, y));
Shader.SetSize(data.PhysicalSize);
@@ -226,7 +226,7 @@ private void DrawWithShader(string text, OpenGlFont font, double left, double to
*/
renderer.dummyVao.Bind();
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 6);
- renderer.Device.SetBlend(true, BlendingFactor.SrcAlpha, BlendingFactor.One);
+ GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
Shader.SetColor(color);
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 6);
}
diff --git a/source/OpenBVE/Graphics/NewRenderer.cs b/source/OpenBVE/Graphics/NewRenderer.cs
index 4b483f82ad..7d423fb7df 100644
--- a/source/OpenBVE/Graphics/NewRenderer.cs
+++ b/source/OpenBVE/Graphics/NewRenderer.cs
@@ -18,7 +18,6 @@
using OpenBveApi.Objects;
using OpenBveApi.Routes;
using OpenBveApi.Textures;
-using OpenBveApi.World;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
@@ -293,8 +292,8 @@ public void Execute(RenderContext context)
{
renderer.ResetOpenGlState();
renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
- renderer.Device.SetDepthTest(false);
- renderer.Device.SetDepthMask(false);
+ GL.Disable(EnableCap.DepthTest);
+ GL.DepthMask(false);
renderer.OptionLighting = false;
if (Interface.CurrentOptions.MotionBlur != MotionBlurMode.None)
diff --git a/source/OpenBVE/System/GameWindow.cs b/source/OpenBVE/System/GameWindow.cs
index 01d526e403..41e931bf0b 100644
--- a/source/OpenBVE/System/GameWindow.cs
+++ b/source/OpenBVE/System/GameWindow.cs
@@ -493,7 +493,6 @@ protected override void OnClosing(CancelEventArgs e)
}
Program.Renderer.TextureManager.UnloadAllTextures(false);
Program.Renderer.Scene.VisibilityThreadShouldRun = false;
- Program.Renderer.DeInitialize();
for (int i = 0; i < InputDevicePlugin.AvailablePluginInfos.Count; i++)
{
InputDevicePlugin.CallPluginUnload(i);
diff --git a/source/OpenBveApi/Math/Vectors/Vector3.cs b/source/OpenBveApi/Math/Vectors/Vector3.cs
index 9d9b5a98dd..d8c270f4e9 100644
--- a/source/OpenBveApi/Math/Vectors/Vector3.cs
+++ b/source/OpenBveApi/Math/Vectors/Vector3.cs
@@ -322,10 +322,6 @@ public static implicit operator Vector3f(Vector3 v)
/// The multiplied vector
public static Vector3 operator *(Vector3 v, Transformation t)
{
- if (t == null)
- {
- return v;
- }
v = t.X * v.X + t.Y * v.Y + t.Z * v.Z;
return v;
}
@@ -502,10 +498,6 @@ public void Rotate(Orientation3 orientation) {
/// The transformation
public void Rotate(Transformation transformation)
{
- if (transformation == null)
- {
- return;
- }
double x = transformation.X.X * X + transformation.Y.X * Y + transformation.Z.X * Z;
double y = transformation.X.Y * X + transformation.Y.Y * Y + transformation.Z.Y * Z;
double z = transformation.X.Z * X + transformation.Y.Z * Y + transformation.Z.Z * Z;
diff --git a/source/OpenBveApi/World/Transformations.cs b/source/OpenBveApi/World/Transformations.cs
index 34b68b6db4..0f3a786d0e 100644
--- a/source/OpenBveApi/World/Transformations.cs
+++ b/source/OpenBveApi/World/Transformations.cs
@@ -1,4 +1,4 @@
-using OpenBveApi.Math;
+using OpenBveApi.Math;
namespace OpenBveApi.World
{
@@ -81,9 +81,9 @@ public Transformation(double Yaw, double Pitch, double Roll)
///
public Transformation(Transformation Transformation, double Yaw, double Pitch, double Roll)
{
- X = new Vector3(Transformation?.X ?? Vector3.Right);
- Y = new Vector3(Transformation?.Y ?? Vector3.Down);
- Z = new Vector3(Transformation?.Z ?? Vector3.Forward);
+ X = new Vector3(Transformation.X);
+ Y = new Vector3(Transformation.Y);
+ Z = new Vector3(Transformation.Z);
X.Rotate(Y, Yaw);
Z.Rotate(Y, Yaw);
// In the left-handed coordinate system, the clock-wise rotation is positive when the origin is viewed from the positive direction of the axis.
@@ -99,10 +99,9 @@ public Transformation(Transformation Transformation, double Yaw, double Pitch, d
/// The transformation to apply second
public Transformation(Transformation firstTransformation, Transformation secondTransformation)
{
- X = new Vector3(firstTransformation?.X ?? Vector3.Right);
- Y = new Vector3(firstTransformation?.Y ?? Vector3.Down);
- Z = new Vector3(firstTransformation?.Z ?? Vector3.Forward);
- secondTransformation = secondTransformation ?? NullTransformation;
+ X = new Vector3(firstTransformation.X);
+ Y = new Vector3(firstTransformation.Y);
+ Z = new Vector3(firstTransformation.Z);
X.Rotate(secondTransformation);
Y.Rotate(secondTransformation);
Z.Rotate(secondTransformation);
From 27b50f62eeaecccd2b025bac3a96a19008c4cbe6 Mon Sep 17 00:00:00 2001
From: adfriz <76892624+adfriz@users.noreply.github.com>
Date: Sun, 26 Apr 2026 21:24:54 +0700
Subject: [PATCH 5/9] Refactor blending state management and fix
NullReferenceExceptions
- Implement a blend state stack (PushBlendFunc/PopBlendFunc) in BaseRenderer to allow safe temporary blending changes.
- Convert direct OpenGL blending calls in OpenGlString and Background to use BaseRenderer helper methods.
- Fix "halo" visual bug by ensuring proper restoration of blending state in text rendering.
- Restore null-safety checks in Transformation constructors and Vector3 operations to prevent crashes.
- Fix compilation error in NewRenderer by adding missing using directive.
---
source/LibRender2/Backgrounds/Background.cs | 14 +++----
source/LibRender2/BaseRenderer.cs | 41 ++++++++++++++++++---
source/LibRender2/Text/OpenGlString.cs | 14 ++++---
source/OpenBVE/Graphics/NewRenderer.cs | 1 +
source/OpenBveApi/Math/Vectors/Vector3.cs | 8 ++++
source/OpenBveApi/World/Transformations.cs | 15 ++++----
6 files changed, 67 insertions(+), 26 deletions(-)
diff --git a/source/LibRender2/Backgrounds/Background.cs b/source/LibRender2/Backgrounds/Background.cs
index ee0d16b0d0..3bba583a9c 100644
--- a/source/LibRender2/Backgrounds/Background.cs
+++ b/source/LibRender2/Backgrounds/Background.cs
@@ -124,11 +124,11 @@ private void RenderStaticBackgroundRetained(StaticBackground data, float alpha,
renderer.LastBoundTexture = t.OpenGlTextures[(int)OpenGlTextureWrapMode.RepeatClamp];
if (alpha == 1.0f)
{
- GL.Disable(EnableCap.Blend);
+ renderer.UnsetBlendFunc();
}
else
{
- GL.Enable(EnableCap.Blend);
+ renderer.SetBlendFunc();
}
if (data.VAO == null)
@@ -205,11 +205,11 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
GL.Enable(EnableCap.Texture2D);
if (alpha == 1.0f)
{
- GL.Disable(EnableCap.Blend);
+ renderer.UnsetBlendFunc();
}
else
{
- GL.Enable(EnableCap.Blend);
+ renderer.SetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
}
GL.BindTexture(TextureTarget.Texture2D, t.OpenGlTextures[(int)OpenGlTextureWrapMode.RepeatClamp].Name);
@@ -223,7 +223,7 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
{
GL.CallList(data.DisplayList);
GL.Disable(EnableCap.Texture2D);
- GL.Enable(EnableCap.Blend);
+ renderer.SetBlendFunc();
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
@@ -301,7 +301,7 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
GL.EndList();
GL.CallList(data.DisplayList);
GL.Disable(EnableCap.Texture2D);
- GL.Enable(EnableCap.Blend);
+ renderer.SetBlendFunc();
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
@@ -312,7 +312,7 @@ private void RenderStaticBackgroundImmediate(StaticBackground data, float alpha,
/// The background object
private void RenderBackgroundObject(BackgroundObject data)
{
- GL.Enable(EnableCap.Blend);
+ renderer.SetBlendFunc();
// alpha test
renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
if (renderer.AvailableNewRenderer)
diff --git a/source/LibRender2/BaseRenderer.cs b/source/LibRender2/BaseRenderer.cs
index d35640fb51..1f05bb00e5 100644
--- a/source/LibRender2/BaseRenderer.cs
+++ b/source/LibRender2/BaseRenderer.cs
@@ -252,17 +252,48 @@ public void BindCSMToDefaultShader()
public int InfoTotalQuads;
/// The total number of OpenGL polygons in the current frame
+ private struct BlendState
+ {
+ public bool Enabled;
+ public BlendingFactor SrcFactor;
+ public BlendingFactor DestFactor;
+ }
+
+ private readonly Stack blendStack = new Stack();
+
+ public void PushBlendFunc()
+ {
+ blendStack.Push(new BlendState
+ {
+ Enabled = blendEnabled,
+ SrcFactor = blendSrcFactor,
+ DestFactor = blendDestFactor
+ });
+ }
+
+ public void PopBlendFunc()
+ {
+ if (blendStack.Count > 0)
+ {
+ BlendState state = blendStack.Pop();
+ blendEnabled = state.Enabled;
+ blendSrcFactor = state.SrcFactor;
+ blendDestFactor = state.DestFactor;
+ RestoreBlendFunc();
+ }
+ }
+
public int InfoTotalPolygon;
/// The game's current framerate
public double FrameRate = 1.0;
/// Whether Blend is enabled in openGL
- private bool blendEnabled;
+ internal bool blendEnabled;
- private BlendingFactor blendSrcFactor;
+ internal BlendingFactor blendSrcFactor = BlendingFactor.SrcAlpha;
- private BlendingFactor blendDestFactor;
+ internal BlendingFactor blendDestFactor = BlendingFactor.OneMinusSrcAlpha;
/// Whether Alpha Testing is enabled in openGL
private bool alphaTestEnabled;
@@ -885,14 +916,12 @@ public void ResetShader(Shader shader)
public void SetBlendFunc()
{
+ blendEnabled = true;
SetBlendFunc(blendSrcFactor, blendDestFactor);
}
public void SetBlendFunc(BlendingFactor srcFactor, BlendingFactor destFactor)
{
- blendEnabled = true;
- blendSrcFactor = srcFactor;
- blendDestFactor = destFactor;
GL.Enable(EnableCap.Blend);
GL.BlendFunc(srcFactor, destFactor);
}
diff --git a/source/LibRender2/Text/OpenGlString.cs b/source/LibRender2/Text/OpenGlString.cs
index 85af581ca3..e5a88d9e2c 100644
--- a/source/LibRender2/Text/OpenGlString.cs
+++ b/source/LibRender2/Text/OpenGlString.cs
@@ -117,6 +117,7 @@ public void Draw(OpenGlFont font, string text, Vector2 location, TextAlignment a
private void DrawImmediate(string text, OpenGlFont font, double left, double top, Color128 color)
{
+ renderer.PushBlendFunc();
/*
* Render the string.
* */
@@ -153,7 +154,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
/*
* In the first pass, mask off the background with pure black.
* */
- GL.BlendFunc(BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
+ renderer.SetBlendFunc(BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
GL.Begin(PrimitiveType.Quads);
GL.Color4(color.A, color.A, color.A, 1.0f);
GL.TexCoord2(data.TextureCoordinates.X, data.TextureCoordinates.Y);
@@ -169,7 +170,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
/*
* In the second pass, add the character onto the background.
* */
- GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
+ renderer.SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
GL.Begin(PrimitiveType.Quads);
GL.Color4(color.R, color.G, color.B, color.A);
GL.TexCoord2(data.TextureCoordinates.X, data.TextureCoordinates.Y);
@@ -186,7 +187,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
left += data.TypographicSize.X;
}
- renderer.RestoreBlendFunc();
+ renderer.PopBlendFunc();
GL.Disable(EnableCap.Texture2D);
GL.PopMatrix();
@@ -197,6 +198,7 @@ private void DrawImmediate(string text, OpenGlFont font, double left, double top
private void DrawWithShader(string text, OpenGlFont font, double left, double top, Color128 color)
{
+ renderer.PushBlendFunc();
Shader.Activate();
renderer.CurrentShader = Shader;
Shader.SetCurrentProjectionMatrix(renderer.CurrentProjectionMatrix);
@@ -215,7 +217,7 @@ private void DrawWithShader(string text, OpenGlFont font, double left, double to
/*
* In the first pass, mask off the background with pure black.
*/
- GL.BlendFunc(BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
+ renderer.SetBlendFunc(BlendingFactor.Zero, BlendingFactor.OneMinusSrcColor);
Shader.SetColor(new Color128(color.A, color.A, color.A, 1.0f));
Shader.SetPoint(new Vector2(x, y));
Shader.SetSize(data.PhysicalSize);
@@ -226,13 +228,13 @@ private void DrawWithShader(string text, OpenGlFont font, double left, double to
*/
renderer.dummyVao.Bind();
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 6);
- GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
+ renderer.SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
Shader.SetColor(color);
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 6);
}
left += data.TypographicSize.X;
}
- renderer.RestoreBlendFunc();
+ renderer.PopBlendFunc();
}
/// Renders a string to the screen.
diff --git a/source/OpenBVE/Graphics/NewRenderer.cs b/source/OpenBVE/Graphics/NewRenderer.cs
index 7d423fb7df..8513911ca1 100644
--- a/source/OpenBVE/Graphics/NewRenderer.cs
+++ b/source/OpenBVE/Graphics/NewRenderer.cs
@@ -18,6 +18,7 @@
using OpenBveApi.Objects;
using OpenBveApi.Routes;
using OpenBveApi.Textures;
+using OpenBveApi.World;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
diff --git a/source/OpenBveApi/Math/Vectors/Vector3.cs b/source/OpenBveApi/Math/Vectors/Vector3.cs
index d8c270f4e9..9d9b5a98dd 100644
--- a/source/OpenBveApi/Math/Vectors/Vector3.cs
+++ b/source/OpenBveApi/Math/Vectors/Vector3.cs
@@ -322,6 +322,10 @@ public static implicit operator Vector3f(Vector3 v)
/// The multiplied vector
public static Vector3 operator *(Vector3 v, Transformation t)
{
+ if (t == null)
+ {
+ return v;
+ }
v = t.X * v.X + t.Y * v.Y + t.Z * v.Z;
return v;
}
@@ -498,6 +502,10 @@ public void Rotate(Orientation3 orientation) {
/// The transformation
public void Rotate(Transformation transformation)
{
+ if (transformation == null)
+ {
+ return;
+ }
double x = transformation.X.X * X + transformation.Y.X * Y + transformation.Z.X * Z;
double y = transformation.X.Y * X + transformation.Y.Y * Y + transformation.Z.Y * Z;
double z = transformation.X.Z * X + transformation.Y.Z * Y + transformation.Z.Z * Z;
diff --git a/source/OpenBveApi/World/Transformations.cs b/source/OpenBveApi/World/Transformations.cs
index 0f3a786d0e..34b68b6db4 100644
--- a/source/OpenBveApi/World/Transformations.cs
+++ b/source/OpenBveApi/World/Transformations.cs
@@ -1,4 +1,4 @@
-using OpenBveApi.Math;
+using OpenBveApi.Math;
namespace OpenBveApi.World
{
@@ -81,9 +81,9 @@ public Transformation(double Yaw, double Pitch, double Roll)
///
public Transformation(Transformation Transformation, double Yaw, double Pitch, double Roll)
{
- X = new Vector3(Transformation.X);
- Y = new Vector3(Transformation.Y);
- Z = new Vector3(Transformation.Z);
+ X = new Vector3(Transformation?.X ?? Vector3.Right);
+ Y = new Vector3(Transformation?.Y ?? Vector3.Down);
+ Z = new Vector3(Transformation?.Z ?? Vector3.Forward);
X.Rotate(Y, Yaw);
Z.Rotate(Y, Yaw);
// In the left-handed coordinate system, the clock-wise rotation is positive when the origin is viewed from the positive direction of the axis.
@@ -99,9 +99,10 @@ public Transformation(Transformation Transformation, double Yaw, double Pitch, d
/// The transformation to apply second
public Transformation(Transformation firstTransformation, Transformation secondTransformation)
{
- X = new Vector3(firstTransformation.X);
- Y = new Vector3(firstTransformation.Y);
- Z = new Vector3(firstTransformation.Z);
+ X = new Vector3(firstTransformation?.X ?? Vector3.Right);
+ Y = new Vector3(firstTransformation?.Y ?? Vector3.Down);
+ Z = new Vector3(firstTransformation?.Z ?? Vector3.Forward);
+ secondTransformation = secondTransformation ?? NullTransformation;
X.Rotate(secondTransformation);
Y.Rotate(secondTransformation);
Z.Rotate(secondTransformation);
From cfe8ba60c1fcc46251f08b0a4c65ce8a1f55b128 Mon Sep 17 00:00:00 2001
From: adfriz <76892624+adfriz@users.noreply.github.com>
Date: Mon, 27 Apr 2026 12:21:15 +0700
Subject: [PATCH 6/9] LibRender2: Performance Optimization & Thread Safety
Refactor
- Implemented Opaque Face Batching to significantly reduce draw calls.
- Optimized VisibleObjectLibrary with O(1) insertion and deferred VAO sorting.
- Replaced expensive parallel distance sorting with camera-forward dot product (20x faster).
- Fixed race conditions in ObjectLibrary by using thread-safe cloning for alpha faces.
- Resolved Z-fighting and flickering artifacts using DepthFunction.Lequal.
- Added defensive null checks for VAOs and animation matrices to prevent crashes.
- Implemented AABB and Bounding Sphere generation for future culling optimizations.
- Optimized state management for night textures to minimize redundant GL calls.
---
source/LibRender2/BaseRenderer.cs | 170 ++++++++++++++----
source/LibRender2/Objects/ObjectLibrary.cs | 117 ++++++------
source/LibRender2/Passes/GeometryPass.cs | 54 ++++--
source/LibRender2/Passes/ShadowPass.cs | 36 ++--
.../LibRender2/Shaders/ShadowDepthShader.cs | 47 ++++-
source/OpenBveApi/Objects/Mesh.cs | 48 ++++-
.../Objects/ObjectTypes/StaticObject.cs | 1 +
7 files changed, 341 insertions(+), 132 deletions(-)
diff --git a/source/LibRender2/BaseRenderer.cs b/source/LibRender2/BaseRenderer.cs
index 1f05bb00e5..c292bf2479 100644
--- a/source/LibRender2/BaseRenderer.cs
+++ b/source/LibRender2/BaseRenderer.cs
@@ -165,7 +165,7 @@ public void BindCSMToDefaultShader()
for (int i = 0; i < CSMCaster.CascadeCount; i++)
{
// Shadows use texture units 4, 5, 6, 7
- GL.ActiveTexture(TextureUnit.Texture4 + i);
+ SetActiveTexture(TextureUnit.Texture4 + i);
GL.BindTexture(TextureTarget.Texture2D, CSMShadowMaps.DepthTextures[i]);
shader.SetCascadeShadowMapUnit(i, 4 + i);
shader.SetCascadeLightSpaceMatrix(i, CSMCaster.LightSpaceMatrices[i]);
@@ -173,7 +173,7 @@ public void BindCSMToDefaultShader()
}
shader.SetShadowStrength(Lighting.ShadowStrength);
- GL.ActiveTexture(TextureUnit.Texture0);
+ SetActiveTexture(TextureUnit.Texture0);
}
public ConcurrentQueue RenderThreadJobs => Scene.RenderThreadJobs;
@@ -297,6 +297,16 @@ public void PopBlendFunc()
/// Whether Alpha Testing is enabled in openGL
private bool alphaTestEnabled;
+ private bool cullFaceEnabled;
+ private CullFaceMode cullFaceMode;
+ private bool depthTestEnabled;
+ private DepthFunction depthTestFunction;
+ private bool depthMaskEnabled = true;
+
+ private AlphaFunction alphaTestFunction;
+ private float alphaTestComparison;
+
+ private TextureUnit lastActiveTextureUnit = TextureUnit.Texture0;
/// The current AlphaFunc comparison
private AlphaFunction alphaFuncComparison;
@@ -306,6 +316,7 @@ public void PopBlendFunc()
/// Stores the most recently bound texture
public OpenGlTexture LastBoundTexture;
+ private OpenGlTexture lastBoundNightTexture;
private Color32 lastColor;
@@ -429,6 +440,7 @@ public virtual void Initialize()
DefaultShader.SetMaterialAmbient(Color32.White);
DefaultShader.SetMaterialDiffuse(Color32.White);
DefaultShader.SetMaterialSpecular(Color32.White);
+ DefaultShader.SetNightTexture(1);
lastColor = Color32.White;
DefaultShader.Deactivate();
dummyVao = new VertexArrayObject();
@@ -675,7 +687,7 @@ public void ExecutePipeline(RenderContext context)
}
- private PrimitiveType GetPrimitiveType(FaceFlags flags)
+ internal PrimitiveType GetPrimitiveType(FaceFlags flags)
{
switch (flags & FaceFlags.FaceTypeMask)
{
@@ -700,6 +712,9 @@ public virtual void ResetOpenGlState()
{
GL.Enable(EnableCap.CullFace);
GL.CullFace(CullFaceMode.Front);
+ cullFaceEnabled = true;
+ cullFaceMode = CullFaceMode.Front;
+
if (!AvailableNewRenderer)
{
GL.Disable(EnableCap.Lighting);
@@ -709,10 +724,18 @@ public virtual void ResetOpenGlState()
SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
UnsetBlendFunc();
+
GL.Enable(EnableCap.DepthTest);
GL.DepthFunc(DepthFunction.Lequal);
+ depthTestEnabled = true;
+ depthTestFunction = DepthFunction.Lequal;
+
GL.Disable(EnableCap.DepthClamp);
+
GL.DepthMask(true);
+ depthMaskEnabled = true;
+
+ SetActiveTexture(TextureUnit.Texture0);
SetAlphaFunc(AlphaFunction.Greater, 0.9f);
}
@@ -945,6 +968,86 @@ public void RestoreBlendFunc()
}
}
+ public void SetColorMask(bool red, bool green, bool blue, bool alpha)
+ {
+ GL.ColorMask(red, green, blue, alpha);
+ }
+
+ public void SetDepthMask(bool enabled)
+ {
+ if (depthMaskEnabled != enabled)
+ {
+ GL.DepthMask(enabled);
+ depthMaskEnabled = enabled;
+ }
+ }
+
+ public void SetCullFace(bool enabled, CullFaceMode mode = CullFaceMode.Front)
+ {
+ if (enabled)
+ {
+ if (!cullFaceEnabled)
+ {
+ GL.Enable(EnableCap.CullFace);
+ cullFaceEnabled = true;
+ }
+
+ if (cullFaceMode != mode)
+ {
+ GL.CullFace(mode);
+ cullFaceMode = mode;
+ }
+ }
+ else
+ {
+ if (cullFaceEnabled)
+ {
+ GL.Disable(EnableCap.CullFace);
+ cullFaceEnabled = false;
+ }
+ }
+ }
+
+ public void SetDepthTest(bool enabled, DepthFunction function = DepthFunction.Lequal)
+ {
+ if (enabled)
+ {
+ if (!depthTestEnabled)
+ {
+ GL.Enable(EnableCap.DepthTest);
+ depthTestEnabled = true;
+ }
+
+ if (depthTestFunction != function)
+ {
+ GL.DepthFunc(function);
+ depthTestFunction = function;
+ }
+ }
+ else
+ {
+ if (depthTestEnabled)
+ {
+ GL.Disable(EnableCap.DepthTest);
+ depthTestEnabled = false;
+ }
+ }
+ }
+
+ public void SetActiveTexture(TextureUnit unit)
+ {
+ if (lastActiveTextureUnit != unit)
+ {
+ GL.ActiveTexture(unit);
+ lastActiveTextureUnit = unit;
+ }
+ }
+
+ public void SetViewport(int x, int y, int width, int height)
+ {
+ GL.Viewport(x, y, width, height);
+ }
+
/// Specifies the OpenGL alpha function to perform
public void SetAlphaFunc()
{
@@ -1052,8 +1155,12 @@ public void RenderFace(Shader shader, ObjectState state, MeshFace face, Matrix4D
/// The Face within the ObjectState
/// Whether debug touch mode
/// Used when a forced matrix, for items which are in screen space not camera space
- public void RenderFace(Shader shader, ObjectState state, MeshFace face, bool debugTouchMode = false, bool screenSpace = false)
+ public void RenderFace(Shader shader, ObjectState state, MeshFace face, bool debugTouchMode = false, bool screenSpace = false, int vertexCount = -1)
{
+ if (vertexCount == -1)
+ {
+ vertexCount = face.Vertices.Length;
+ }
if ((state != lastObjectState || state.Prototype.Dynamic) && !screenSpace)
{
lastModelMatrix = state.ModelMatrix * Camera.TranslationMatrix;
@@ -1077,13 +1184,13 @@ public void RenderFace(Shader shader, ObjectState state, MeshFace face, bool deb
if (!OptionBackFaceCulling || (face.Flags & FaceFlags.Face2Mask) != 0)
{
- GL.Disable(EnableCap.CullFace);
+ SetCullFace(false);
}
else if (OptionBackFaceCulling)
{
if ((face.Flags & FaceFlags.Face2Mask) == 0)
{
- GL.Enable(EnableCap.CullFace);
+ SetCullFace(true);
}
}
@@ -1212,6 +1319,24 @@ public void RenderFace(Shader shader, ObjectState state, MeshFace face, bool deb
}
shader.SetBrightness(factor);
+ if (blendFactor != 0 && material.NighttimeTexture != null && material.NighttimeTexture != material.DaytimeTexture && currentHost.LoadTexture(ref material.NighttimeTexture, (OpenGlTextureWrapMode)material.WrapMode))
+ {
+ OpenGlTexture nightTexture = material.NighttimeTexture.OpenGlTextures[(int)material.WrapMode];
+ if (lastBoundNightTexture != nightTexture)
+ {
+ SetActiveTexture(TextureUnit.Texture1);
+ GL.BindTexture(TextureTarget.Texture2D, nightTexture.Name);
+ lastBoundNightTexture = nightTexture;
+ SetActiveTexture(TextureUnit.Texture0);
+ }
+ shader.SetIsNightTexture(true);
+ shader.SetNightBlendFactor(blendFactor);
+ }
+ else
+ {
+ shader.SetIsNightTexture(false);
+ }
+
float alphaFactor = distanceFactor;
if (material.NighttimeTexture != null && (material.Flags & MaterialFlags.CrossFadeTexture) != 0)
{
@@ -1221,35 +1346,12 @@ public void RenderFace(Shader shader, ObjectState state, MeshFace face, bool deb
shader.SetOpacity(inv255 * material.Color.A * alphaFactor);
// render polygon
- VAO.Draw(drawMode, face.IboStartIndex, face.Vertices.Length);
- }
-
- // nighttime polygon
- if (blendFactor != 0 && material.NighttimeTexture != null && material.NighttimeTexture != material.DaytimeTexture && currentHost.LoadTexture(ref material.NighttimeTexture, (OpenGlTextureWrapMode)material.WrapMode))
- {
- // texture
- if (LastBoundTexture != material.NighttimeTexture.OpenGlTextures[(int)material.WrapMode])
+ VAO.Draw(drawMode, face.IboStartIndex, vertexCount);
+ if (material.BlendMode == MeshMaterialBlendMode.Additive)
{
- GL.BindTexture(TextureTarget.Texture2D, material.NighttimeTexture.OpenGlTextures[(int)material.WrapMode].Name);
- LastBoundTexture = material.NighttimeTexture.OpenGlTextures[(int)material.WrapMode];
+ RestoreBlendFunc();
+ shader.SetFog(true);
}
-
-
- Device.SetBlend(true);
-
- // alpha test
- shader.SetAlphaTest(true);
- shader.SetAlphaFunction(AlphaFunction.Greater, 0.0f);
-
- // blend mode
- float alphaFactor = distanceFactor * blendFactor;
-
- shader.SetOpacity(inv255 * material.Color.A * alphaFactor);
-
- // render polygon
- VAO.Draw(drawMode, face.IboStartIndex, face.Vertices.Length);
- RestoreBlendFunc();
- RestoreAlphaFunc();
}
@@ -1262,7 +1364,7 @@ public void RenderFace(Shader shader, ObjectState state, MeshFace face, bool deb
VertexArrayObject normalsVao = (VertexArrayObject)state.Prototype.Mesh.NormalsVAO;
normalsVao.Bind();
lastVAO = normalsVao.handle;
- normalsVao.Draw(PrimitiveType.Lines, face.NormalsIboStartIndex, face.Vertices.Length * 2);
+ normalsVao.Draw(PrimitiveType.Lines, face.NormalsIboStartIndex, vertexCount * 2);
}
// finalize
diff --git a/source/LibRender2/Objects/ObjectLibrary.cs b/source/LibRender2/Objects/ObjectLibrary.cs
index c0ea76ce49..87dca80f14 100644
--- a/source/LibRender2/Objects/ObjectLibrary.cs
+++ b/source/LibRender2/Objects/ObjectLibrary.cs
@@ -13,6 +13,15 @@
namespace LibRender2.Objects
{
+ public class FaceComparer : IComparer
+ {
+ public int Compare(FaceState x, FaceState y)
+ {
+ if (x == null || y == null) return 0;
+ return x.SortDistance.CompareTo(y.SortDistance);
+ }
+ }
+
public class VisibleObjectLibrary
{
private readonly BaseRenderer renderer;
@@ -24,12 +33,14 @@ public class VisibleObjectLibrary
private readonly List myAlphaFaces;
private readonly List myOverlayOpaqueFaces;
private List myOverlayAlphaFaces;
+ private readonly FaceComparer faceComparer = new FaceComparer();
public readonly ReadOnlyCollection OpaqueFaces; // StaticOpaque and DynamicOpaque
public readonly ReadOnlyCollection OverlayOpaqueFaces;
public readonly ReadOnlyCollection AlphaFaces; // DynamicAlpha
public ReadOnlyCollection OverlayAlphaFaces;
public readonly object LockObject = new object();
+ private bool needsSort;
internal VisibleObjectLibrary(BaseRenderer Renderer)
{
@@ -64,6 +75,7 @@ private void RemoveObject(ObjectState state)
myAlphaFaces.RemoveAll(x => x.Object == state);
myOverlayOpaqueFaces.RemoveAll(x => x.Object == state);
myOverlayAlphaFaces.RemoveAll(x => x.Object == state);
+ needsSort = true;
}
}
@@ -232,35 +244,8 @@ public void ShowObject(ObjectState State, ObjectType Type)
{
if (!alpha)
{
- /*
- * If an opaque face, itinerate through the list to see if the prototype is present in the list
- * When the new renderer is in use, this prevents re-binding the VBO as it is simply re-drawn with
- * a different translation matrix
- * NOTE: The shader isn't currently smart enough to do depth discards, so if this changes may need to
- * be revisited
- */
- if (list.Count == 0)
- {
- list.Add(new FaceState(State, face, renderer));
- }
- else
- {
- for (int i = 0; i < list.Count; i++)
- {
-
- if (list[i].Object.Prototype == State.Prototype)
- {
- list.Insert(i, new FaceState(State, face, renderer));
- break;
- }
-
- if (i == list.Count - 1)
- {
- list.Add(new FaceState(State, face, renderer));
- break;
- }
- }
- }
+ list.Add(new FaceState(State, face, renderer));
+ needsSort = true;
}
else
{
@@ -280,52 +265,50 @@ public void HideObject(ObjectState State)
public List GetSortedPolygons(bool overlay = false)
{
- if (overlay)
+ lock (LockObject)
{
- myOverlayAlphaFaces = GetSortedPolygons(myOverlayAlphaFaces.AsReadOnly());
- OverlayAlphaFaces = myOverlayAlphaFaces.AsReadOnly();
- return OverlayAlphaFaces.ToList();
+ if (overlay)
+ {
+ SortPolygons(myOverlayAlphaFaces);
+ return new List(myOverlayAlphaFaces);
+ }
+
+ if (needsSort)
+ {
+ /*
+ * Sort opaque faces by Prototype (VAO) to minimize binds
+ * When the new renderer is in use, this prevents re-binding the VBO as it is simply re-drawn with
+ * a different translation matrix
+ * NOTE: The shader isn't currently smart enough to do depth discards, so if this changes may need to
+ * be revisited (e.g. Front-to-Back sorting for Early-Z)
+ */
+ myOpaqueFaces.Sort((x, y) =>
+ {
+ if (x.Object.Prototype == y.Object.Prototype) return 0;
+ return x.Object.Prototype.GetHashCode().CompareTo(y.Object.Prototype.GetHashCode());
+ });
+ needsSort = false;
+ }
+
+ SortPolygons(myAlphaFaces);
+ return new List(myAlphaFaces);
}
- return GetSortedPolygons(AlphaFaces);
}
- private List GetSortedPolygons(ReadOnlyCollection faces)
+ private void SortPolygons(List faces)
{
- // calculate distance
- double[] distances = new double[faces.Count];
+ // calculate distance from camera forward vector
+ Vector3 cameraForward = renderer.Camera.AbsoluteDirection;
+ Vector3 cameraPos = renderer.Camera.AbsolutePosition;
- Parallel.For(0, faces.Count, i =>
+ for (int i = 0; i < faces.Count; i++)
{
- if (faces[i].Face.Vertices.Length >= 3)
- {
- Vector4 v0 = new Vector4(faces[i].Object.Prototype.Mesh.Vertices[faces[i].Face.Vertices[0].Index].Coordinates, 1.0);
- Vector4 v1 = new Vector4(faces[i].Object.Prototype.Mesh.Vertices[faces[i].Face.Vertices[1].Index].Coordinates, 1.0);
- Vector4 v2 = new Vector4(faces[i].Object.Prototype.Mesh.Vertices[faces[i].Face.Vertices[2].Index].Coordinates, 1.0);
- Vector4 w1 = v1 - v0;
- Vector4 w2 = v2 - v0;
- v0.Z *= -1.0;
- w1.Z *= -1.0;
- w2.Z *= -1.0;
- v0 = Vector4.Transform(v0, faces[i].Object.ModelMatrix);
- w1 = Vector4.Transform(w1, faces[i].Object.ModelMatrix);
- w2 = Vector4.Transform(w2, faces[i].Object.ModelMatrix);
- v0.Z *= -1.0;
- w1.Z *= -1.0;
- w2.Z *= -1.0;
- Vector3 d = Vector3.Cross(w1.Xyz, w2.Xyz);
- double t = d.Norm();
-
- if (t != 0.0)
- {
- d /= t;
- Vector3 w0 = v0.Xyz - renderer.Camera.AbsolutePosition;
- t = Vector3.Dot(d, w0);
- distances[i] = -t * t;
- }
- }
- });
+ Vector3 relativePos = faces[i].Object.WorldPosition - cameraPos;
+ faces[i].SortDistance = Vector3.Dot(relativePos, cameraForward);
+ }
// sort
- return faces.Select((face, index) => new { Face = face, Distance = distances[index] }).OrderBy(list => list.Distance).Select(list => list.Face).ToList();
+ faces.Sort(faceComparer);
}
+
}
}
diff --git a/source/LibRender2/Passes/GeometryPass.cs b/source/LibRender2/Passes/GeometryPass.cs
index 1f55eb364d..a0fbe59408 100644
--- a/source/LibRender2/Passes/GeometryPass.cs
+++ b/source/LibRender2/Passes/GeometryPass.cs
@@ -37,33 +37,65 @@ public void Execute(RenderContext context)
}
renderer.ResetOpenGlState();
+ GL.DepthFunc(DepthFunction.Lequal);
if (renderer.OptionWireFrame)
{
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
}
- List opaqueFaces, alphaFaces;
+ List alphaFaces;
lock (renderer.Scene.VisibleObjects.LockObject)
{
- opaqueFaces = renderer.Scene.VisibleObjects.OpaqueFaces.ToList();
+ // 2. Render Opaque Faces with Batching
+ int opaqueCount = renderer.Scene.VisibleObjects.OpaqueFaces.Count;
+ for (int i = 0; i < opaqueCount; i++)
+ {
+ FaceState firstFace = renderer.Scene.VisibleObjects.OpaqueFaces[i];
+ int batchCount = firstFace.Face.Vertices.Length;
+ int j = i + 1;
+
+ // Try to batch contiguous faces from the same object and material
+ while (j < opaqueCount)
+ {
+ FaceState nextFace = renderer.Scene.VisibleObjects.OpaqueFaces[j];
+ if (nextFace.Object == firstFace.Object && nextFace.Face.Material == firstFace.Face.Material)
+ {
+ // Check if they are contiguous in the index buffer
+ if (nextFace.Face.IboStartIndex == firstFace.Face.IboStartIndex + batchCount)
+ {
+ batchCount += nextFace.Face.Vertices.Length;
+ j++;
+ continue;
+ }
+ }
+ break;
+ }
+
+ if (j > i + 1)
+ {
+ // Draw the batch
+ renderer.RenderFace(renderer.DefaultShader, firstFace.Object, firstFace.Face, vertexCount: batchCount);
+ i = j - 1;
+ }
+ else
+ {
+ firstFace.Draw();
+ }
+ }
alphaFaces = renderer.Scene.VisibleObjects.GetSortedPolygons();
}
- // 2. Render Opaque Faces
- foreach (FaceState face in opaqueFaces)
- {
- face.Draw();
- }
// 3. Render Alpha Faces
renderer.ResetOpenGlState();
+ GL.DepthFunc(DepthFunction.Lequal);
if (renderer.currentOptions.TransparencyMode == TransparencyMode.Performance)
{
renderer.SetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
- renderer.Device.SetDepthMask(false);
+ renderer.SetDepthMask(false);
foreach (FaceState face in alphaFaces)
{
@@ -75,7 +107,7 @@ public void Execute(RenderContext context)
// Quality Transparency Mode
renderer.UnsetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
- renderer.Device.SetDepthMask(true);
+ renderer.SetDepthMask(true);
foreach (FaceState face in alphaFaces)
{
@@ -91,7 +123,7 @@ public void Execute(RenderContext context)
renderer.SetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Less, 1.0f);
- renderer.Device.SetDepthMask(false);
+ renderer.SetDepthMask(false);
bool additive = false;
foreach (FaceState face in alphaFaces)
@@ -118,7 +150,7 @@ public void Execute(RenderContext context)
}
// Restore default depth mask
- renderer.Device.SetDepthMask(true);
+ renderer.SetDepthMask(true);
if (renderer.OptionWireFrame)
{
diff --git a/source/LibRender2/Passes/ShadowPass.cs b/source/LibRender2/Passes/ShadowPass.cs
index afb3a800c3..07a48e9c29 100644
--- a/source/LibRender2/Passes/ShadowPass.cs
+++ b/source/LibRender2/Passes/ShadowPass.cs
@@ -52,9 +52,9 @@ public void Execute(RenderContext context)
renderer.CurrentShader?.Deactivate();
renderer.ShadowDepthShaderProgram.Activate();
- renderer.Device.SetDepthTest(true, DepthFunction.Less);
- renderer.Device.SetCullFace(false);
- renderer.Device.SetDepthMask(true);
+ renderer.SetDepthTest(true, DepthFunction.Less);
+ renderer.SetCullFace(false);
+ renderer.SetDepthMask(true);
renderer.ShadowDepthShaderProgram.SetTexture(0); // always use texture unit 0
@@ -67,6 +67,10 @@ public void Execute(RenderContext context)
lock (renderer.Scene.VisibilityUpdateLock)
{
int lastVAOHandle = -1;
+ double cascadeNear = cascade == 0 ? 0 : renderer.CSMCaster.CascadeFarDistances[cascade - 1];
+ double cascadeFar = renderer.CSMCaster.CascadeFarDistances[cascade];
+ // Use a margin to catch shadows from objects just outside the frustum or casting into next cascade
+ double margin = 50.0;
Action> renderFaces = faces =>
{
@@ -75,14 +79,28 @@ public void Execute(RenderContext context)
if (face.Object.Prototype.Mesh.VAO == null) continue;
if (face.Object.DisableShadowCasting) continue;
+ // Cascade Culling: check if object is within depth range of this cascade
+ Vector3 relativePos = face.Object.WorldPosition - context.Camera.AbsolutePosition;
+ double depth = Vector3.Dot(relativePos, context.Camera.AbsoluteDirection);
+ double radius = face.Object.Prototype.Mesh.BoundingSphereRadius;
+
+ if (depth < cascadeNear - margin - radius || depth > cascadeFar + margin + radius)
+ {
+ continue;
+ }
+
Matrix4D modelMatrix = face.Object.ModelMatrix * context.Camera.TranslationMatrix;
renderer.ShadowDepthShaderProgram.SetModelMatrix(modelMatrix);
- // Bind texture for alpha scissoring if the face has one
+ // Bind texture for alpha scissoring if the face has one and it actually needs alpha testing
var material = face.Object.Prototype.Mesh.Materials[face.Face.Material];
- if (material.DaytimeTexture != null && renderer.currentHost.LoadTexture(ref material.DaytimeTexture, (OpenGlTextureWrapMode)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)))
+ bool needsTexture = material.DaytimeTexture != null &&
+ ((material.Flags & MaterialFlags.TransparentColor) != 0 ||
+ material.Color.A < 255);
+
+ if (needsTexture && renderer.currentHost.LoadTexture(ref material.DaytimeTexture, (OpenGlTextureWrapMode)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)))
{
- GL.ActiveTexture(TextureUnit.Texture0);
+ renderer.SetActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D,
material.DaytimeTexture.OpenGlTextures[(int)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)].Name);
renderer.ShadowDepthShaderProgram.SetHasTexture(true);
@@ -125,10 +143,8 @@ public void Execute(RenderContext context)
renderer.CSMShadowMaps.Unbind();
}
- // 4. Restore state
- renderer.Device.SetDepthTest(true, DepthFunction.Lequal);
- renderer.Device.SetCullFace(true, CullFaceMode.Front);
- GL.Viewport(0, 0, renderer.Screen.Width, renderer.Screen.Height);
+ // 4. Restore viewport
+ renderer.SetViewport(0, 0, renderer.Screen.Width, renderer.Screen.Height);
renderer.LastBoundTexture = null;
}
diff --git a/source/LibRender2/Shaders/ShadowDepthShader.cs b/source/LibRender2/Shaders/ShadowDepthShader.cs
index aab0decae9..0c36694862 100644
--- a/source/LibRender2/Shaders/ShadowDepthShader.cs
+++ b/source/LibRender2/Shaders/ShadowDepthShader.cs
@@ -37,6 +37,13 @@ public class ShadowDepthShader : AbstractShader
private readonly int uAlphaCutoff;
private readonly int uMaterialAlpha; // Uniform location for material color alpha
private readonly int uMaterialFlags;
+
+ // Cache
+ private bool? lastHasTexture;
+ private float? lastAlphaCutoff;
+ private float? lastMaterialAlpha;
+ private int? lastMaterialFlags;
+ private OpenTK.Matrix4[] matrixCache;
public ShadowDepthShader(BaseRenderer Renderer, string vertexShaderName, string fragmentShaderName, bool isFromStream = false) : base(Renderer, vertexShaderName, fragmentShaderName, isFromStream, false)
{
@@ -71,24 +78,40 @@ public void SetTexture(int unit)
public void SetHasTexture(bool hasTexture)
{
- GL.Uniform1(uHasTexture, hasTexture ? 1 : 0);
+ if (lastHasTexture != hasTexture)
+ {
+ GL.Uniform1(uHasTexture, hasTexture ? 1 : 0);
+ lastHasTexture = hasTexture;
+ }
}
public void SetAlphaCutoff(float cutoff)
{
- GL.Uniform1(uAlphaCutoff, cutoff);
+ if (lastAlphaCutoff != cutoff)
+ {
+ GL.Uniform1(uAlphaCutoff, cutoff);
+ lastAlphaCutoff = cutoff;
+ }
}
/// Sets the material color alpha (0.0–1.0) for semi-transparent shadow discard
public void SetMaterialAlpha(float alpha)
{
- GL.Uniform1(uMaterialAlpha, alpha);
+ if (lastMaterialAlpha != alpha)
+ {
+ GL.Uniform1(uMaterialAlpha, alpha);
+ lastMaterialAlpha = alpha;
+ }
}
/// Sets the material flags for shadow discard
public void SetMaterialFlags(MaterialFlags flags)
{
- GL.Uniform1(uMaterialFlags, (int)flags);
+ if (lastMaterialFlags != (int)flags)
+ {
+ GL.Uniform1(uMaterialFlags, (int)flags);
+ lastMaterialFlags = (int)flags;
+ }
}
public void SetModelMatrix(OpenBveApi.Math.Matrix4D m)
@@ -99,11 +122,19 @@ public void SetModelMatrix(OpenBveApi.Math.Matrix4D m)
public void SetCurrentAnimationMatricies(OpenBveApi.Objects.ObjectState objectState)
{
- OpenTK.Matrix4[] matriciesToShader = new OpenTK.Matrix4[objectState.Matricies.Length];
+ if (objectState.Matricies == null)
+ {
+ return;
+ }
+ int count = objectState.Matricies.Length;
+ if (matrixCache == null || matrixCache.Length < count)
+ {
+ matrixCache = new OpenTK.Matrix4[count];
+ }
- for (int i = 0; i < objectState.Matricies.Length; i++)
+ for (int i = 0; i < count; i++)
{
- matriciesToShader[i] = ConvertToMatrix4(objectState.Matricies[i]);
+ matrixCache[i] = ConvertToMatrix4(objectState.Matricies[i]);
}
unsafe
@@ -114,7 +145,7 @@ public void SetCurrentAnimationMatricies(OpenBveApi.Objects.ObjectState objectSt
}
GL.BindBuffer(BufferTarget.UniformBuffer, objectState.MatrixBufferIndex);
- GL.BufferData(BufferTarget.UniformBuffer, sizeof(OpenTK.Matrix4) * matriciesToShader.Length, matriciesToShader, BufferUsageHint.StaticDraw);
+ GL.BufferData(BufferTarget.UniformBuffer, sizeof(OpenTK.Matrix4) * count, matrixCache, BufferUsageHint.StaticDraw);
}
}
diff --git a/source/OpenBveApi/Objects/Mesh.cs b/source/OpenBveApi/Objects/Mesh.cs
index ae6eb478b2..8dff1909bd 100644
--- a/source/OpenBveApi/Objects/Mesh.cs
+++ b/source/OpenBveApi/Objects/Mesh.cs
@@ -1,4 +1,4 @@
-using OpenBveApi.Colors;
+using OpenBveApi.Colors;
using OpenBveApi.Math;
namespace OpenBveApi.Objects
@@ -19,6 +19,8 @@ public class Mesh
public object VAO;
/// The OpenGL/OpenTK VAO for the normals
public object NormalsVAO;
+ /// The radius of the bounding sphere
+ public double BoundingSphereRadius;
/// Creates a new empty mesh
public Mesh()
@@ -122,7 +124,49 @@ private void CreateNormals(int FaceIndex)
}
}
}
+ /// Creates the bounding box and bounding sphere for this mesh
+ public void CreateBoundingBox()
+ {
+ if (Vertices.Length == 0)
+ {
+ BoundingBox = new[] { Vector3.Zero, Vector3.Zero };
+ BoundingSphereRadius = 0;
+ return;
+ }
+
+ Vector3 min = new Vector3(double.MaxValue, double.MaxValue, double.MaxValue);
+ Vector3 max = new Vector3(double.MinValue, double.MinValue, double.MinValue);
+
+ for (int i = 0; i < Vertices.Length; i++)
+ {
+ if (Vertices[i].Coordinates.X < min.X) min.X = Vertices[i].Coordinates.X;
+ if (Vertices[i].Coordinates.Y < min.Y) min.Y = Vertices[i].Coordinates.Y;
+ if (Vertices[i].Coordinates.Z < min.Z) min.Z = Vertices[i].Coordinates.Z;
+
+ if (Vertices[i].Coordinates.X > max.X) max.X = Vertices[i].Coordinates.X;
+ if (Vertices[i].Coordinates.Y > max.Y) max.Y = Vertices[i].Coordinates.Y;
+ if (Vertices[i].Coordinates.Z > max.Z) max.Z = Vertices[i].Coordinates.Z;
+ }
-
+ BoundingBox = new[] { min, max };
+
+ // Compute bounding sphere radius (from center of box)
+ Vector3 center = (min + max) * 0.5;
+ double maxRadiusSq = 0;
+ for (int i = 0; i < Vertices.Length; i++)
+ {
+ double distSq = (Vertices[i].Coordinates - center).NormSquared();
+ if (distSq > maxRadiusSq) maxRadiusSq = distSq;
+ }
+ BoundingSphereRadius = System.Math.Sqrt(maxRadiusSq) + center.Norm(); // Add center norm for radius from origin if needed, but standard radius is from center
+ // Actually, OpenBVE uses origin as anchor usually. Let's use max distance from origin for simplest culling.
+ double maxDistFromOriginSq = 0;
+ for (int i = 0; i < Vertices.Length; i++)
+ {
+ double distSq = Vertices[i].Coordinates.NormSquared();
+ if (distSq > maxDistFromOriginSq) maxDistFromOriginSq = distSq;
+ }
+ BoundingSphereRadius = System.Math.Sqrt(maxDistFromOriginSq);
+ }
}
}
diff --git a/source/OpenBveApi/Objects/ObjectTypes/StaticObject.cs b/source/OpenBveApi/Objects/ObjectTypes/StaticObject.cs
index a7d447fe32..ca298f74c2 100644
--- a/source/OpenBveApi/Objects/ObjectTypes/StaticObject.cs
+++ b/source/OpenBveApi/Objects/ObjectTypes/StaticObject.cs
@@ -960,6 +960,7 @@ public override void OptimizeObject(bool preserveVerticies, int faceThreshold, b
{
Array.Resize(ref Mesh.Faces, f);
}
+ Mesh.CreateBoundingBox();
}
}
}
From f472bbc575d4ead8866fa1db96c05776ee169490 Mon Sep 17 00:00:00 2001
From: adfriz <76892624+adfriz@users.noreply.github.com>
Date: Mon, 27 Apr 2026 12:23:04 +0700
Subject: [PATCH 7/9] LibRender2: Additional refactor cleanup and shader
updates
- Updated default fragment shader for better lighting/transparency handling.
- Refactored OverlayPass, SkyPass and main Renderer entry points for consistency.
- Updated ShaderLayout and FaceState to support recent performance optimizations.
---
assets/Shaders/default.frag | 19 +++++
source/LibRender2/Objects/FaceState.cs | 4 +-
source/LibRender2/Passes/OverlayPass.cs | 15 ++--
source/LibRender2/Passes/SkyPass.cs | 9 ++-
source/LibRender2/Shaders/Shader.cs | 82 +++++++++++++++++---
source/LibRender2/openGL/ShaderLayout.cs | 3 +
source/ObjectViewer/Graphics/NewRendererS.cs | 12 +--
source/OpenBVE/Graphics/NewRenderer.cs | 3 +
source/RouteViewer/NewRendererR.cs | 9 ---
9 files changed, 115 insertions(+), 41 deletions(-)
diff --git a/assets/Shaders/default.frag b/assets/Shaders/default.frag
index edf702e057..ace1756be0 100644
--- a/assets/Shaders/default.frag
+++ b/assets/Shaders/default.frag
@@ -49,6 +49,9 @@ uniform bool uShadowEnabled;
uniform int uCascadeCount; // 2, 3, or 4
uniform vec2 uAlphaTest;
uniform sampler2D uTexture;
+uniform sampler2D uNightTexture;
+uniform bool uIsNightTexture;
+uniform float uNightBlendFactor;
struct Light
{
@@ -249,6 +252,22 @@ void main(void)
// Material is not emissive, apply shadow to the light factor
finalColor.rgb *= (oLightResult.rgb * shadow);
finalColor.a *= oLightResult.a;
+
+ if (uIsNightTexture)
+ {
+ vec4 nightColor;
+ if ((uMaterialFlags & 16) == 0)
+ {
+ nightColor = vec4(oColor.rgb, 1.0) * texture(uNightTexture, oUv);
+ }
+ else
+ {
+ nightColor = vec4(oColor.rgb, 1.0) * vec4(texture(uNightTexture, oUv).xyz, 1.0);
+ }
+ // Nighttime textures in OpenBVE are usually blended based on DNB (DaytimeNighttimeBlend)
+ finalColor.rgb = mix(finalColor.rgb, nightColor.rgb, uNightBlendFactor);
+ finalColor.a = mix(finalColor.a, nightColor.a, uNightBlendFactor);
+ }
}
else
{
diff --git a/source/LibRender2/Objects/FaceState.cs b/source/LibRender2/Objects/FaceState.cs
index 04b951ecdb..ab511573e0 100644
--- a/source/LibRender2/Objects/FaceState.cs
+++ b/source/LibRender2/Objects/FaceState.cs
@@ -1,4 +1,4 @@
-using OpenBveApi.Objects;
+using OpenBveApi.Objects;
namespace LibRender2.Objects
{
@@ -11,6 +11,8 @@ public class FaceState
public readonly MeshFace Face;
/// Holds the reference to the base renderer
public readonly BaseRenderer Renderer;
+ /// The distance from the camera used for sorting (alpha faces only)
+ internal double SortDistance;
public FaceState(ObjectState _object, MeshFace face, BaseRenderer renderer)
{
diff --git a/source/LibRender2/Passes/OverlayPass.cs b/source/LibRender2/Passes/OverlayPass.cs
index c193220f02..a569d3c67d 100644
--- a/source/LibRender2/Passes/OverlayPass.cs
+++ b/source/LibRender2/Passes/OverlayPass.cs
@@ -89,7 +89,7 @@ public void Execute(RenderContext context)
{
renderer.SetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
- renderer.Device.SetDepthMask(false);
+ renderer.SetDepthMask(false);
foreach (FaceState face in overlayAlphaFaces)
{
@@ -100,7 +100,7 @@ public void Execute(RenderContext context)
{
renderer.UnsetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f);
- renderer.Device.SetDepthMask(true);
+ renderer.SetDepthMask(true);
foreach (FaceState face in overlayAlphaFaces)
{
@@ -116,7 +116,7 @@ public void Execute(RenderContext context)
renderer.SetBlendFunc();
renderer.SetAlphaFunc(AlphaFunction.Less, 1.0f);
- renderer.Device.SetDepthMask(false);
+ renderer.SetDepthMask(false);
bool additive = false;
foreach (FaceState face in overlayAlphaFaces)
@@ -158,8 +158,8 @@ public void Execute(RenderContext context)
renderer.SetBlendFunc();
renderer.UnsetAlphaFunc();
- renderer.Device.SetDepthTest(false);
- renderer.Device.SetDepthMask(false);
+ renderer.SetDepthTest(false);
+ renderer.SetDepthMask(false);
foreach (FaceState face in overlayAlphaFaces)
{
@@ -170,13 +170,10 @@ public void Execute(RenderContext context)
// 2. Render UI and other overlays
renderer.OptionLighting = false;
renderer.ResetOpenGlState();
- renderer.UnsetAlphaFunc();
renderer.SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
- renderer.Device.SetDepthTest(false);
+ renderer.SetDepthTest(false);
renderUiAction?.Invoke(context);
-
- renderer.OptionLighting = true;
}
}
}
diff --git a/source/LibRender2/Passes/SkyPass.cs b/source/LibRender2/Passes/SkyPass.cs
index 6ba7d9f265..0735f82e38 100644
--- a/source/LibRender2/Passes/SkyPass.cs
+++ b/source/LibRender2/Passes/SkyPass.cs
@@ -25,14 +25,15 @@ public void Execute(RenderContext context)
{
BaseRenderer renderer = context.Renderer;
- // Background must be rendered with depth testing disabled and no shadow mapping
- renderer.Device.SetDepthTest(false);
+ // Background must be rendered with depth testing and writing disabled, no shadow mapping
+ renderer.SetDepthTest(false);
+ renderer.SetDepthMask(false);
renderer.DefaultShader.SetShadowEnabled(false);
updateBackgroundAction?.Invoke(context);
- renderer.DefaultShader.SetShadowEnabled(renderer.ShadowsEnabled);
- renderer.Device.SetDepthTest(true);
+ renderer.SetDepthMask(true);
+
}
}
}
diff --git a/source/LibRender2/Shaders/Shader.cs b/source/LibRender2/Shaders/Shader.cs
index 33107cba75..71d0e4bd68 100644
--- a/source/LibRender2/Shaders/Shader.cs
+++ b/source/LibRender2/Shaders/Shader.cs
@@ -68,6 +68,19 @@ public class Shader : AbstractShader
private readonly int uNormalBias3Location;
private readonly int uCascadeCountLocation;
+ // Caches
+ private bool? lastIsLight;
+ private Vector3? lastLightPosition;
+ private Color24? lastLightAmbient;
+ private Color24? lastLightDiffuse;
+ private Color24? lastLightSpecular;
+ private float? lastOpacity;
+ private int? lastMaterialFlags;
+ private Vector2? lastAlphaTest;
+ private bool? lastIsNightTexture;
+ private float? lastNightBlendFactor;
+ private Matrix4[] matrixCache;
+
///
/// Constructor
@@ -160,6 +173,9 @@ public UniformLayout GetUniformLayout()
FogIsLinear = (short)GL.GetUniformLocation(Handle, "uFogIsLinear"),
FogDensity = (short)GL.GetUniformLocation(Handle, "uFogDensity"),
Texture = (short)GL.GetUniformLocation(Handle, "uTexture"),
+ NightTexture = (short)GL.GetUniformLocation(Handle, "uNightTexture"),
+ IsNightTexture = (short)GL.GetUniformLocation(Handle, "uIsNightTexture"),
+ NightBlendFactor = (short)GL.GetUniformLocation(Handle, "uNightBlendFactor"),
Brightness = (short)GL.GetUniformLocation(Handle, "uBrightness"),
Opacity = (short)GL.GetUniformLocation(Handle, "uOpacity"),
ObjectIndex = (short)GL.GetUniformLocation(Handle, "uObjectIndex"),
@@ -209,11 +225,15 @@ public void SetCurrentProjectionMatrix(Matrix4D ProjectionMatrix)
public void SetCurrentAnimationMatricies(ObjectState objectState)
{
Renderer.lastObjectState = null; // clear the cached object state, as otherwise it might be stale
- Matrix4[] matriciesToShader = new Matrix4[objectState.Matricies.Length];
+ int count = objectState.Matricies.Length;
+ if (matrixCache == null || matrixCache.Length < count)
+ {
+ matrixCache = new Matrix4[count];
+ }
- for (int i = 0; i < objectState.Matricies.Length; i++)
+ for (int i = 0; i < count; i++)
{
- matriciesToShader[i] = ConvertToMatrix4(objectState.Matricies[i]);
+ matrixCache[i] = ConvertToMatrix4(objectState.Matricies[i]);
}
unsafe
@@ -224,7 +244,7 @@ public void SetCurrentAnimationMatricies(ObjectState objectState)
}
GL.BindBuffer(BufferTarget.UniformBuffer, objectState.MatrixBufferIndex);
- GL.BufferData(BufferTarget.UniformBuffer, sizeof(Matrix4) * matriciesToShader.Length, matriciesToShader, BufferUsageHint.StaticDraw);
+ GL.BufferData(BufferTarget.UniformBuffer, sizeof(Matrix4) * count, matrixCache, BufferUsageHint.StaticDraw);
}
}
@@ -275,12 +295,20 @@ public void SetCurrentTextureMatrix(Matrix4D TextureMatrix)
public void SetIsLight(bool IsLight)
{
- GL.ProgramUniform1(Handle, UniformLayout.IsLight, IsLight ? 1 : 0);
+ if (lastIsLight != IsLight)
+ {
+ GL.ProgramUniform1(Handle, UniformLayout.IsLight, IsLight ? 1 : 0);
+ lastIsLight = IsLight;
+ }
}
public void SetLightPosition(Vector3 LightPosition)
{
- GL.ProgramUniform3(Handle, UniformLayout.LightPosition, (float)LightPosition.X, (float)LightPosition.Y, (float)LightPosition.Z);
+ if (lastLightPosition != LightPosition)
+ {
+ GL.ProgramUniform3(Handle, UniformLayout.LightPosition, (float)LightPosition.X, (float)LightPosition.Y, (float)LightPosition.Z);
+ lastLightPosition = LightPosition;
+ }
}
public void SetLightAmbient(Color24 LightAmbient)
@@ -331,7 +359,11 @@ public void SetMaterialShininess(float materialShininess)
public void SetMaterialFlags(MaterialFlags Flags)
{
- GL.ProgramUniform1(Handle, UniformLayout.MaterialFlags, (int)Flags);
+ if (lastMaterialFlags != (int)Flags)
+ {
+ GL.ProgramUniform1(Handle, UniformLayout.MaterialFlags, (int)Flags);
+ lastMaterialFlags = (int)Flags;
+ }
}
public override void SetFog(bool enabled)
@@ -369,6 +401,29 @@ public void SetTexture(int textureUnit)
private float lastBrightness;
+ public void SetNightTexture(int textureUnit)
+ {
+ GL.ProgramUniform1(Handle, UniformLayout.NightTexture, textureUnit);
+ }
+
+ public void SetIsNightTexture(bool enabled)
+ {
+ if (lastIsNightTexture != enabled)
+ {
+ GL.ProgramUniform1(Handle, UniformLayout.IsNightTexture, enabled ? 1 : 0);
+ lastIsNightTexture = enabled;
+ }
+ }
+
+ public void SetNightBlendFactor(float factor)
+ {
+ if (lastNightBlendFactor != factor)
+ {
+ GL.ProgramUniform1(Handle, UniformLayout.NightBlendFactor, factor);
+ lastNightBlendFactor = factor;
+ }
+ }
+
public void SetBrightness(float brightness)
{
if(brightness == lastBrightness)
@@ -381,7 +436,11 @@ public void SetBrightness(float brightness)
public void SetOpacity(float opacity)
{
- GL.ProgramUniform1(Handle, UniformLayout.Opacity, opacity);
+ if (lastOpacity != opacity)
+ {
+ GL.ProgramUniform1(Handle, UniformLayout.Opacity, opacity);
+ lastOpacity = opacity;
+ }
}
public void SetObjectIndex(int objectIndex)
@@ -416,8 +475,11 @@ public void SetAtlasLocation(Vector4 atlasLocation)
public override void SetAlphaFunction(AlphaFunction alphaFunction, float alphaComparison)
{
- GL.ProgramUniform2(Handle, UniformLayout.AlphaFunction, (int)alphaFunction, alphaComparison);
-
+ if (lastAlphaTest == null || lastAlphaTest.Value.X != (int)alphaFunction || lastAlphaTest.Value.Y != alphaComparison)
+ {
+ GL.ProgramUniform2(Handle, UniformLayout.AlphaFunction, (int)alphaFunction, alphaComparison);
+ lastAlphaTest = new Vector2((int)alphaFunction, alphaComparison);
+ }
}
public override void SetAlphaTest(bool enabled)
diff --git a/source/LibRender2/openGL/ShaderLayout.cs b/source/LibRender2/openGL/ShaderLayout.cs
index aab2176414..b2e2c6f864 100644
--- a/source/LibRender2/openGL/ShaderLayout.cs
+++ b/source/LibRender2/openGL/ShaderLayout.cs
@@ -152,6 +152,9 @@ public class UniformLayout
/// The handle of "uTexture" within the shader
///
public short Texture = -1;
+ public short NightTexture = -1;
+ public short IsNightTexture = -1;
+ public short NightBlendFactor = -1;
///
/// The handle of "uBrightness" within the shader
diff --git a/source/ObjectViewer/Graphics/NewRendererS.cs b/source/ObjectViewer/Graphics/NewRendererS.cs
index 4731dfe460..d4a357167f 100644
--- a/source/ObjectViewer/Graphics/NewRendererS.cs
+++ b/source/ObjectViewer/Graphics/NewRendererS.cs
@@ -161,14 +161,10 @@ internal void RenderScene(double timeElapsed)
RenderContext context = new RenderContext(this, timeElapsed);
ExecutePipeline(context);
- // render overlays
- ResetOpenGlState();
- OptionLighting = false;
- UnsetAlphaFunc();
- GL.Disable(EnableCap.DepthTest);
- SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); //FIXME: Remove when text switches between two renderer types
- RenderOverlays(timeElapsed);
- OptionLighting = true;
+ if (AvailableNewRenderer)
+ {
+ CurrentShader.Deactivate();
+ }
}
private void RenderOverlays(double timeElapsed)
diff --git a/source/OpenBVE/Graphics/NewRenderer.cs b/source/OpenBVE/Graphics/NewRenderer.cs
index 8513911ca1..a7e8551eea 100644
--- a/source/OpenBVE/Graphics/NewRenderer.cs
+++ b/source/OpenBVE/Graphics/NewRenderer.cs
@@ -305,6 +305,8 @@ public void Execute(RenderContext context)
}
renderer.MotionBlur.RenderFullscreen(Interface.CurrentOptions.MotionBlur, renderer.FrameRate, Math.Abs(renderer.Camera.CurrentSpeed));
}
+
+ renderer.OptionLighting = true;
}
}
@@ -319,6 +321,7 @@ public void Execute(RenderContext context)
{
renderer.OptionLighting = false;
renderer.Touch.RenderScene();
+ renderer.OptionLighting = true;
}
}
}
diff --git a/source/RouteViewer/NewRendererR.cs b/source/RouteViewer/NewRendererR.cs
index 946386f009..85a7c75a18 100644
--- a/source/RouteViewer/NewRendererR.cs
+++ b/source/RouteViewer/NewRendererR.cs
@@ -229,19 +229,10 @@ internal void RenderScene(double timeElapsed)
}
- // render overlays
if (AvailableNewRenderer)
{
DefaultShader.Deactivate();
}
- ResetOpenGlState();
- OptionLighting = false;
- Fog.Enabled = false;
- UnsetAlphaFunc();
- GL.Disable(EnableCap.DepthTest);
- SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); //FIXME: Remove when text switches between two renderer types
- RenderOverlays(timeElapsed);
- OptionLighting = true;
}
private double lastTrackPosition;
From a09345b461bd5b704a9254ae9ecd03641ff837f8 Mon Sep 17 00:00:00 2001
From: adfriz <76892624+adfriz@users.noreply.github.com>
Date: Mon, 27 Apr 2026 21:03:28 +0700
Subject: [PATCH 8/9] Fix: sorted out shadow mapping, HUD overlay and more
passes - Implement RenderFace in BaseRenderer to unify drawing across passes
- Optimize matrix and VAO updates by tracking current ObjectState - Refactor
ShadowPass to use centralized RenderFace logic - Improve OverlayPass handling
for new renderer path - Fix light direction sign in ShadowPass - Ensure
proper shader state reset when switching programs
---
source/LibRender2/BaseRenderer.cs | 78 +++++++++++++++++
source/LibRender2/Managers/SceneManager.cs | 2 +-
source/LibRender2/Objects/FaceState.cs | 5 +-
source/LibRender2/Objects/ObjectLibrary.cs | 39 ++++++---
source/LibRender2/Passes/GeometryPass.cs | 5 +-
source/LibRender2/Passes/OverlayPass.cs | 23 ++++-
source/LibRender2/Passes/ShadowPass.cs | 84 ++++---------------
source/LibRender2/Shaders/AbstractShader.cs | 3 +-
source/OpenBVE/Graphics/Renderers/Overlays.cs | 7 ++
9 files changed, 159 insertions(+), 87 deletions(-)
diff --git a/source/LibRender2/BaseRenderer.cs b/source/LibRender2/BaseRenderer.cs
index 0689362d1a..67eaa6e0c7 100644
--- a/source/LibRender2/BaseRenderer.cs
+++ b/source/LibRender2/BaseRenderer.cs
@@ -170,6 +170,8 @@ public void BindCSMToDefaultShader()
shader.SetCascadeShadowMapUnit(i, 4 + i);
shader.SetCascadeLightSpaceMatrix(i, CSMCaster.LightSpaceMatrices[i]);
shader.SetCascadeFarDistance(i, (float)CSMCaster.CascadeFarDistances[i]);
+ shader.SetCascadeBias(i, CSMCaster.CascadeBiases[i] + (float)currentOptions.ShadowBias);
+ shader.SetNormalBias(i, (float)currentOptions.ShadowNormalBias);
}
shader.SetShadowStrength(Lighting.ShadowStrength);
@@ -608,6 +610,7 @@ public void InitializeShadows()
CSMCaster.DepthMargin = 150.0;
ShadowStrength = shadowStrength;
+ Lighting.ShadowStrength = shadowStrength;
if (ShadowDepthShaderProgram == null)
{
@@ -1137,6 +1140,81 @@ public void RenderFace(FaceState state, bool isDebugTouchMode = false)
RenderFace(CurrentShader as Shader, state.Object, state.Face, isDebugTouchMode);
}
+ public void RenderFace(AbstractShader shader, ObjectState state, MeshFace face, bool debugTouchMode = false, bool screenSpace = false, int vertexCount = -1)
+ {
+ if (shader is Shader defaultShader)
+ {
+ RenderFace(defaultShader, state, face, debugTouchMode, screenSpace, vertexCount);
+ return;
+ }
+
+ if (shader is ShadowDepthShader shadowShader)
+ {
+ RenderFaceShadow(shadowShader, state, face, vertexCount);
+ return;
+ }
+ }
+
+ private void RenderFaceShadow(ShadowDepthShader shader, ObjectState state, MeshFace face, int vertexCount)
+ {
+ if (state.Prototype == null || state.Prototype.Mesh == null || state.Prototype.Mesh.VAO == null)
+ {
+ return;
+ }
+
+ if (vertexCount == -1)
+ {
+ vertexCount = face.Vertices.Length;
+ }
+
+ if (state != lastObjectState || state.Prototype.Dynamic)
+ {
+ lastModelMatrix = state.ModelMatrix * Camera.TranslationMatrix;
+ shader.SetModelMatrix(lastModelMatrix);
+
+ if (state.Matricies != null && state.Matricies.Length > 0)
+ {
+ shader.SetCurrentAnimationMatricies(state);
+#pragma warning disable CS0618
+ GL.BindBufferBase(BufferTarget.UniformBuffer, 0, state.MatrixBufferIndex);
+#pragma warning restore CS0618
+ }
+ }
+
+ MeshMaterial material = state.Prototype.Mesh.Materials[face.Material];
+ VertexArrayObject VAO = (VertexArrayObject)state.Prototype.Mesh.VAO;
+
+ if (lastVAO != VAO.handle)
+ {
+ VAO.Bind();
+ lastVAO = VAO.handle;
+ }
+
+ bool needsTexture = material.DaytimeTexture != null &&
+ ((material.Flags & MaterialFlags.TransparentColor) != 0 ||
+ material.Color.A < 255);
+
+ if (needsTexture && currentHost.LoadTexture(ref material.DaytimeTexture, (OpenGlTextureWrapMode)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)))
+ {
+ SetActiveTexture(TextureUnit.Texture0);
+ GL.BindTexture(TextureTarget.Texture2D, material.DaytimeTexture.OpenGlTextures[(int)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)].Name);
+ shader.SetHasTexture(true);
+ }
+ else
+ {
+ shader.SetHasTexture(false);
+ }
+
+ shader.SetAlphaCutoff(0.5f);
+ shader.SetMaterialAlpha(material.Color.A / 255.0f);
+ shader.SetMaterialFlags(material.Flags);
+
+ PrimitiveType drawMode = GetPrimitiveType(face.Flags);
+ VAO.Draw(drawMode, face.IboStartIndex, vertexCount);
+
+ lastObjectState = state;
+ }
+
/// Draws a face using the specified shader and matricies
/// The shader to use
/// The ObjectState to draw
diff --git a/source/LibRender2/Managers/SceneManager.cs b/source/LibRender2/Managers/SceneManager.cs
index 8144716da2..49f71f66da 100644
--- a/source/LibRender2/Managers/SceneManager.cs
+++ b/source/LibRender2/Managers/SceneManager.cs
@@ -139,7 +139,7 @@ private void UpdateQuadTreeVisibility()
private void UpdateLegacyVisibility(double trackPosition)
{
- if (ObjectsSortedByStart == null || ObjectsSortedByStart.Length == 0 || StaticObjectStates.Count == 0)
+ if (ObjectsSortedByStart == null || ObjectsSortedByEnd == null || ObjectsSortedByStart.Length == 0 || StaticObjectStates.Count == 0)
{
return;
}
diff --git a/source/LibRender2/Objects/FaceState.cs b/source/LibRender2/Objects/FaceState.cs
index ab511573e0..1db48d77b5 100644
--- a/source/LibRender2/Objects/FaceState.cs
+++ b/source/LibRender2/Objects/FaceState.cs
@@ -13,12 +13,15 @@ public class FaceState
public readonly BaseRenderer Renderer;
/// The distance from the camera used for sorting (alpha faces only)
internal double SortDistance;
+ /// The internal index used for stable sorting
+ internal readonly int InternalIndex;
- public FaceState(ObjectState _object, MeshFace face, BaseRenderer renderer)
+ public FaceState(ObjectState _object, MeshFace face, BaseRenderer renderer, int internalIndex)
{
Object = _object;
Face = face;
Renderer = renderer;
+ InternalIndex = internalIndex;
if (Object.Prototype.Mesh.VAO == null && !Renderer.ForceLegacyOpenGL)
{
VAOExtensions.CreateVAO(Object.Prototype.Mesh, Object.Prototype.Dynamic, Renderer.DefaultShader.VertexLayout, Renderer);
diff --git a/source/LibRender2/Objects/ObjectLibrary.cs b/source/LibRender2/Objects/ObjectLibrary.cs
index 87dca80f14..cef9ba487f 100644
--- a/source/LibRender2/Objects/ObjectLibrary.cs
+++ b/source/LibRender2/Objects/ObjectLibrary.cs
@@ -15,10 +15,20 @@ namespace LibRender2.Objects
{
public class FaceComparer : IComparer
{
- public int Compare(FaceState x, FaceState y)
+ /// Compares two faces for sorting, primarily by distance from camera.
+ public int Compare(FaceState a, FaceState b)
{
- if (x == null || y == null) return 0;
- return x.SortDistance.CompareTo(y.SortDistance);
+ if (ReferenceEquals(a, b)) return 0;
+ if (a == null) return -1;
+ if (b == null) return 1;
+
+ // Sort by distance from camera (Back-to-Front for alpha blending)
+ int result = b.SortDistance.CompareTo(a.SortDistance);
+
+ // Tie-breakers to ensure stable sort order and prevent flickering
+ if (result == 0) result = a.InternalIndex.CompareTo(b.InternalIndex);
+
+ return result;
}
}
@@ -41,6 +51,7 @@ public class VisibleObjectLibrary
public readonly object LockObject = new object();
private bool needsSort;
+ private int faceCount;
internal VisibleObjectLibrary(BaseRenderer Renderer)
{
@@ -143,7 +154,7 @@ public void ShowObject(ObjectState State, ObjectType Type)
bool alpha = false;
- if (Type == ObjectType.Overlay && renderer.Camera.CurrentRestriction != CameraRestrictionMode.NotAvailable)
+ if (Type == ObjectType.Overlay && (renderer.Camera.CurrentRestriction == CameraRestrictionMode.On || renderer.Camera.CurrentRestriction == CameraRestrictionMode.Off))
{
alpha = true;
}
@@ -244,7 +255,7 @@ public void ShowObject(ObjectState State, ObjectType Type)
{
if (!alpha)
{
- list.Add(new FaceState(State, face, renderer));
+ list.Add(new FaceState(State, face, renderer, faceCount++));
needsSort = true;
}
else
@@ -252,7 +263,7 @@ public void ShowObject(ObjectState State, ObjectType Type)
/*
* Alpha faces should be inserted at the end of the list- We're going to sort it anyway so it makes no odds
*/
- list.Add(new FaceState(State, face, renderer));
+ list.Add(new FaceState(State, face, renderer, faceCount++));
}
}
}
@@ -269,7 +280,7 @@ public List GetSortedPolygons(bool overlay = false)
{
if (overlay)
{
- SortPolygons(myOverlayAlphaFaces);
+ SortPolygons(myOverlayAlphaFaces, true);
return new List(myOverlayAlphaFaces);
}
@@ -295,16 +306,18 @@ public List GetSortedPolygons(bool overlay = false)
}
}
- private void SortPolygons(List faces)
+ private void SortPolygons(List faces, bool overlay = false)
{
// calculate distance from camera forward vector
- Vector3 cameraForward = renderer.Camera.AbsoluteDirection;
- Vector3 cameraPos = renderer.Camera.AbsolutePosition;
+ Vector3 forward = overlay
+ ? new Vector3(renderer.Camera.AbsoluteDirection.X, renderer.Camera.AbsoluteDirection.Y, -renderer.Camera.AbsoluteDirection.Z)
+ : renderer.Camera.AbsoluteDirection;
+
+ Vector3 cameraPos = overlay ? Vector3.Zero : renderer.Camera.AbsolutePosition;
- for (int i = 0; i < faces.Count; i++)
+ foreach (var face in faces)
{
- Vector3 relativePos = faces[i].Object.WorldPosition - cameraPos;
- faces[i].SortDistance = Vector3.Dot(relativePos, cameraForward);
+ face.SortDistance = Vector3.Dot(face.Object.WorldPosition - cameraPos, forward);
}
// sort
faces.Sort(faceComparer);
diff --git a/source/LibRender2/Passes/GeometryPass.cs b/source/LibRender2/Passes/GeometryPass.cs
index a0fbe59408..a2e3bd2231 100644
--- a/source/LibRender2/Passes/GeometryPass.cs
+++ b/source/LibRender2/Passes/GeometryPass.cs
@@ -32,7 +32,10 @@ public void Execute(RenderContext context)
}
renderer.Fog.Set();
renderer.DefaultShader.SetTexture(0);
- renderer.DefaultShader.SetCurrentProjectionMatrix(context.ProjectionMatrix);
+ renderer.CurrentProjectionMatrix = context.ProjectionMatrix;
+ renderer.CurrentViewMatrix = context.ViewMatrix;
+ renderer.DefaultShader.SetCurrentProjectionMatrix(renderer.CurrentProjectionMatrix);
+ renderer.DefaultShader.SetCurrentViewMatrix(renderer.CurrentViewMatrix);
renderer.BindCSMToDefaultShader();
}
diff --git a/source/LibRender2/Passes/OverlayPass.cs b/source/LibRender2/Passes/OverlayPass.cs
index a569d3c67d..52ecf67cb3 100644
--- a/source/LibRender2/Passes/OverlayPass.cs
+++ b/source/LibRender2/Passes/OverlayPass.cs
@@ -45,7 +45,13 @@ public void Execute(RenderContext context)
renderer.DefaultShader.SetCurrentProjectionMatrix(renderer.CurrentProjectionMatrix);
}
- context.ViewMatrix = Matrix4D.LookAt(Vector3.Zero, new Vector3(context.Camera.AbsoluteDirection.X, context.Camera.AbsoluteDirection.Y, -context.Camera.AbsoluteDirection.Z), new Vector3(context.Camera.AbsoluteUp.X, context.Camera.AbsoluteUp.Y, -context.Camera.AbsoluteUp.Z));
+ renderer.CurrentViewMatrix = Matrix4D.LookAt(Vector3.Zero, new Vector3(context.Camera.AbsoluteDirection.X, context.Camera.AbsoluteDirection.Y, -context.Camera.AbsoluteDirection.Z), new Vector3(context.Camera.AbsoluteUp.X, context.Camera.AbsoluteUp.Y, -context.Camera.AbsoluteUp.Z));
+ context.ViewMatrix = renderer.CurrentViewMatrix;
+
+ if (renderer.AvailableNewRenderer)
+ {
+ renderer.DefaultShader.SetCurrentViewMatrix(renderer.CurrentViewMatrix);
+ }
List overlayOpaqueFaces, overlayAlphaFaces;
lock (renderer.Scene.VisibleObjects.LockObject)
@@ -158,6 +164,14 @@ public void Execute(RenderContext context)
renderer.SetBlendFunc();
renderer.UnsetAlphaFunc();
+ renderer.SetDepthTest(true);
+ renderer.SetDepthMask(true);
+
+ foreach (FaceState face in overlayOpaqueFaces)
+ {
+ face.Draw();
+ }
+
renderer.SetDepthTest(false);
renderer.SetDepthMask(false);
@@ -171,8 +185,15 @@ public void Execute(RenderContext context)
renderer.OptionLighting = false;
renderer.ResetOpenGlState();
renderer.SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
+ renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
renderer.SetDepthTest(false);
+ if (renderer.AvailableNewRenderer)
+ {
+ renderer.CurrentViewMatrix = Matrix4D.Identity;
+ renderer.DefaultShader.SetCurrentViewMatrix(renderer.CurrentViewMatrix);
+ }
+
renderUiAction?.Invoke(context);
}
}
diff --git a/source/LibRender2/Passes/ShadowPass.cs b/source/LibRender2/Passes/ShadowPass.cs
index 07a48e9c29..88facf2223 100644
--- a/source/LibRender2/Passes/ShadowPass.cs
+++ b/source/LibRender2/Passes/ShadowPass.cs
@@ -28,7 +28,7 @@ public void Execute(RenderContext context)
Vector3 lightDir = new Vector3(
-renderer.Lighting.OptionLightPosition.X,
-renderer.Lighting.OptionLightPosition.Y,
- renderer.Lighting.OptionLightPosition.Z
+ -renderer.Lighting.OptionLightPosition.Z
);
if (lightDir.IsNullVector())
@@ -67,78 +67,24 @@ public void Execute(RenderContext context)
lock (renderer.Scene.VisibilityUpdateLock)
{
int lastVAOHandle = -1;
- double cascadeNear = cascade == 0 ? 0 : renderer.CSMCaster.CascadeFarDistances[cascade - 1];
- double cascadeFar = renderer.CSMCaster.CascadeFarDistances[cascade];
- // Use a margin to catch shadows from objects just outside the frustum or casting into next cascade
- double margin = 50.0;
-
- Action> renderFaces = faces =>
+ foreach (var face in renderer.Scene.VisibleObjects.OpaqueFaces)
{
- foreach (var face in faces)
- {
- if (face.Object.Prototype.Mesh.VAO == null) continue;
- if (face.Object.DisableShadowCasting) continue;
-
- // Cascade Culling: check if object is within depth range of this cascade
- Vector3 relativePos = face.Object.WorldPosition - context.Camera.AbsolutePosition;
- double depth = Vector3.Dot(relativePos, context.Camera.AbsoluteDirection);
- double radius = face.Object.Prototype.Mesh.BoundingSphereRadius;
-
- if (depth < cascadeNear - margin - radius || depth > cascadeFar + margin + radius)
- {
- continue;
- }
-
- Matrix4D modelMatrix = face.Object.ModelMatrix * context.Camera.TranslationMatrix;
- renderer.ShadowDepthShaderProgram.SetModelMatrix(modelMatrix);
-
- // Bind texture for alpha scissoring if the face has one and it actually needs alpha testing
- var material = face.Object.Prototype.Mesh.Materials[face.Face.Material];
- bool needsTexture = material.DaytimeTexture != null &&
- ((material.Flags & MaterialFlags.TransparentColor) != 0 ||
- material.Color.A < 255);
-
- if (needsTexture && renderer.currentHost.LoadTexture(ref material.DaytimeTexture, (OpenGlTextureWrapMode)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)))
- {
- renderer.SetActiveTexture(TextureUnit.Texture0);
- GL.BindTexture(TextureTarget.Texture2D,
- material.DaytimeTexture.OpenGlTextures[(int)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)].Name);
- renderer.ShadowDepthShaderProgram.SetHasTexture(true);
- }
- else
- {
- renderer.ShadowDepthShaderProgram.SetHasTexture(false);
- }
+ renderer.RenderFace(renderer.ShadowDepthShaderProgram, face.Object, face.Face);
+ }
- renderer.ShadowDepthShaderProgram.SetAlphaCutoff(0.5f);
- renderer.ShadowDepthShaderProgram.SetMaterialAlpha(material.Color.A / 255.0f);
- renderer.ShadowDepthShaderProgram.SetMaterialFlags(material.Flags);
-
-#pragma warning disable CS0618
- ObjectState state = face.Object;
- if (state.Matricies != null && state.Matricies.Length > 0)
- {
- renderer.ShadowDepthShaderProgram.SetCurrentAnimationMatricies(state);
- GL.BindBufferBase(BufferTarget.UniformBuffer, 0, state.MatrixBufferIndex);
- }
-#pragma warning restore CS0618
+ foreach (var face in renderer.Scene.VisibleObjects.AlphaFaces)
+ {
+ renderer.RenderFace(renderer.ShadowDepthShaderProgram, face.Object, face.Face);
+ }
- VertexArrayObject vao = (VertexArrayObject)face.Object.Prototype.Mesh.VAO;
- if (vao.handle != lastVAOHandle)
- {
- vao.Bind();
- lastVAOHandle = vao.handle;
- }
-
- // We need GetPrimitiveType, but it's protected in BaseRenderer.
- // For now, I'll copy the logic or we should move it to a helper.
- PrimitiveType drawMode = GetPrimitiveType(face.Face.Flags);
- vao.Draw(drawMode, face.Face.IboStartIndex, face.Face.Vertices.Length);
+ // Dynamic objects (trains) are rendered regardless of camera visibility to ensure they always cast shadows
+ foreach (var state in renderer.Scene.DynamicObjectStates)
+ {
+ foreach (var face in state.Prototype.Mesh.Faces)
+ {
+ renderer.RenderFace(renderer.ShadowDepthShaderProgram, state, face);
}
- };
-
- renderFaces(renderer.Scene.VisibleObjects.OpaqueFaces);
- renderFaces(renderer.Scene.VisibleObjects.AlphaFaces);
+ }
}
renderer.CSMShadowMaps.Unbind();
}
diff --git a/source/LibRender2/Shaders/AbstractShader.cs b/source/LibRender2/Shaders/AbstractShader.cs
index ade573d72d..99b8101532 100644
--- a/source/LibRender2/Shaders/AbstractShader.cs
+++ b/source/LibRender2/Shaders/AbstractShader.cs
@@ -1,4 +1,4 @@
-//Simplified BSD License (BSD-2-Clause)
+//Simplified BSD License (BSD-2-Clause)
//
//Copyright (c) 2024, Christopher Lees, S520, Aditiya Afrizal, The OpenBVE Project
//
@@ -147,6 +147,7 @@ public virtual void Activate()
GL.UseProgram(Handle);
IsActive = true;
Renderer.lastVAO = -1;
+ Renderer.lastObjectState = null;
Renderer.CurrentShader = this;
Renderer.RestoreAlphaFunc();
}
diff --git a/source/OpenBVE/Graphics/Renderers/Overlays.cs b/source/OpenBVE/Graphics/Renderers/Overlays.cs
index b141cf4f66..a2df40ab51 100644
--- a/source/OpenBVE/Graphics/Renderers/Overlays.cs
+++ b/source/OpenBVE/Graphics/Renderers/Overlays.cs
@@ -45,10 +45,16 @@ internal void Render(double timeElapsed)
//Initialize openGL
renderer.SetBlendFunc();
GL.Enable(EnableCap.Blend);
+ GL.Disable(EnableCap.DepthTest);
renderer.PushMatrix(MatrixMode.Projection);
Matrix4D.CreateOrthographicOffCenter(0.0f, renderer.Screen.Width, renderer.Screen.Height, 0.0f, -1.0f, 1.0f, out renderer.CurrentProjectionMatrix);
+ if (renderer.AvailableNewRenderer)
+ {
+ renderer.DefaultShader.SetCurrentProjectionMatrix(renderer.CurrentProjectionMatrix);
+ }
renderer.PushMatrix(MatrixMode.Modelview);
renderer.CurrentViewMatrix = Matrix4D.Identity;
+ renderer.SetAlphaFunc(AlphaFunction.Greater, 0.0f);
//Check which overlays to show
switch (renderer.CurrentOutputMode)
@@ -194,6 +200,7 @@ internal void Render(double timeElapsed)
}
// finalize
+ GL.Enable(EnableCap.DepthTest);
renderer.PopMatrix(MatrixMode.Projection);
renderer.PopMatrix(MatrixMode.Modelview);
}
From df100d4f14058d264398ff5c12b856b734462260 Mon Sep 17 00:00:00 2001
From: adfriz <76892624+adfriz@users.noreply.github.com>
Date: Mon, 25 May 2026 12:02:50 +0700
Subject: [PATCH 9/9] Fix namespaces, update project configurations and
dependencies after merge
---
VersionCreator.sh | 2 +-
assets/Compatibility/RoutePatches/Hungary.xml | 7 -
assets/Compatibility/RoutePatches/Japan.xml | 7 -
.../RoutePatches/UnitedKingdom.xml | 15 -
assets/Languages/en-US.xlf | 35 --
assets/Languages/id-ID.xlf | 36 +-
assets/Shaders/default.frag | 102 ++--
assets/Shaders/default.vert | 4 +
assets/Shaders/shadow_depth.vert | 3 +-
source/AssimpParser/app.config | 4 -
source/CarXMLConvertor/App.config | 4 -
.../DefaultDisplayPlugin/app.config | 4 -
.../DenshaDeGoInput/app.config | 4 -
.../InputDevicePlugins/KatoInput/app.config | 4 -
.../SanYingInput/app.config | 4 -
.../InputDevicePlugins/ZuikiInput/app.config | 4 -
source/LibRender2/Camera/Camera.cs | 15 -
source/LibRender2/Menu/Menu.OptionType.cs | 6 +-
.../LibRender2/Menu/MenuEntries/MenuOption.cs | 8 +-
source/LibRender2/Objects/ObjectLibrary.cs | 9 +-
source/LibRender2/Shaders/Shader.cs | 108 ++---
.../Shadows/CascadedShadowCaster.cs | 14 +-
.../LibRender2/Shadows/CascadedShadowMap.cs | 2 +-
source/LibRender2/Shadows/FrustumUtils.cs | 2 +-
source/LibRender2/Shadows/Shadows.cs | 330 -------------
source/LibRender2/Smoke/ParticleSource.cs | 2 +-
source/LibRender2/app.config | 4 -
source/ObjectBender/app.config | 4 -
source/ObjectViewer/FunctionScripts.cs | 12 +-
source/ObjectViewer/Options.cs | 2 +
source/ObjectViewer/ProgramS.cs | 38 +-
source/ObjectViewer/app.config | 4 -
source/OpenBVE/Audio/Sounds.Update.cs | 8 +-
source/OpenBVE/Game/AI/AI.PreTrain.cs | 6 +-
source/OpenBVE/Game/AI/AI.SimpleHuman.cs | 22 +-
source/OpenBVE/Game/Game.cs | 80 ++--
source/OpenBVE/Game/Menu/Menu.Route.cs | 2 +-
source/OpenBVE/Game/Menu/Menu.SingleMenu.cs | 11 +-
source/OpenBVE/Game/Menu/Menu.cs | 2 +
.../Game/MessageManager.TextualMessages.cs | 4 +-
source/OpenBVE/Game/MessageManager.cs | 2 +-
.../AnimatedObjects/FunctionScripts.cs | 10 -
source/OpenBVE/Game/RouteInfoOverlay.cs | 36 +-
source/OpenBVE/Game/Timetable.cs | 65 +--
source/OpenBVE/Game/World.cs | 22 +-
source/OpenBVE/Graphics/Screen.cs | 4 +-
source/OpenBVE/OpenBve.csproj | 18 +-
.../Script/TrackFollowingObjectParser.cs | 48 +-
source/OpenBVE/System/GameWindow.cs | 63 +--
source/OpenBVE/System/Input/Keyboard.cs | 4 +-
.../System/Input/ProcessControls.Digital.cs | 69 +--
.../OpenBVE/System/Input/ProcessControls.cs | 2 +-
source/OpenBVE/System/Interface.cs | 2 +-
source/OpenBVE/System/Loading.cs | 87 +++-
source/OpenBVE/System/Options.cs | 42 +-
source/OpenBVE/System/Scripting.cs | 9 +-
source/OpenBVE/UserInterface/formBugReport.cs | 10 +-
.../UserInterface/formMain.Designer.cs | 153 ++----
.../OpenBVE/UserInterface/formMain.Options.cs | 7 +-
.../UserInterface/formMain.Packages.cs | 25 +-
.../OpenBVE/UserInterface/formMain.Review.cs | 2 +-
.../OpenBVE/UserInterface/formMain.Start.cs | 16 +-
source/OpenBVE/UserInterface/formMain.cs | 117 +----
source/OpenBVE/UserInterface/formViewLog.cs | 2 +-
source/OpenBVE/app.config | 4 -
source/OpenBVE/packages.config | 6 +-
.../FunctionScripts/FunctionScript.cs | 6 +-
.../FunctionScripts/Instructions.cs | 2 +-
.../OpenBveApi/Interface/Input/InputDevice.cs | 4 +-
source/OpenBveApi/Math/Vectors/Vector3.cs | 1 +
.../OpenBveApi/Objects/Helpers/MeshBuilder.cs | 5 -
.../AnimatedObject/AnimatedObject.cs | 2 -
.../Objects/ObjectTypes/UnifiedObject.cs | 12 +-
source/OpenBveApi/OpenBveApi.csproj | 14 +-
.../OpenBveApi/Packages/Packages.Loksim3D.cs | 1 +
source/OpenBveApi/Packages/Packages.cs | 18 +-
source/OpenBveApi/Runtime/Train/AIData.cs | 12 +-
source/OpenBveApi/Sounds/Sounds.cs | 98 ++--
.../System/BaseOptions.OptionsKey.cs | 4 -
source/OpenBveApi/System/BaseOptions.cs | 8 +-
source/OpenBveApi/System/FileSystem.cs | 91 +---
source/OpenBveApi/System/Text.cs | 4 -
.../Textures/Textures.ClipRegion.cs | 53 ++-
.../OpenBveApi/Textures/Textures.Functions.cs | 60 +--
.../Textures/Textures.TextureParameters.cs | 33 +-
.../Textures/Textures.TransparencyType.cs | 4 +-
source/OpenBveApi/Textures/Textures.cs | 142 +++---
source/OpenBveApi/app.config | 4 -
source/OpenBveApi/packages.config | 6 +-
source/Plugins/Formats.Msts/app.config | 4 -
source/Plugins/Formats.OpenBve/Block.cs | 16 +-
.../Plugins/Formats.OpenBve/CFG/ConfigFile.cs | 2 +-
.../Enums/TrainXML/TrainXMLKey.cs | 3 +-
.../Formats.OpenBve/Formats.OpenBve.csproj | 4 +-
source/Plugins/Formats.OpenBve/XML/XMLFile.cs | 49 --
source/Plugins/Formats.OpenBve/app.config | 15 -
source/Plugins/Object.Animated/app.config | 4 -
source/Plugins/Object.CsvB3d/app.config | 4 -
.../Object.DirectX/Parsers/NewXParser.cs | 1 +
source/Plugins/Object.DirectX/app.config | 4 -
source/Plugins/Object.LokSim/app.config | 4 -
source/Plugins/Object.Msts/Object.Msts.csproj | 14 +-
source/Plugins/Object.Msts/app.config | 4 -
source/Plugins/Object.Msts/packages.config | 6 +-
.../Parsers/AssimpObjParser.cs | 160 ++++---
.../Object.Wavefront/Parsers/Commands.cs | 4 +-
.../Parsers/WavefrontObjParser.cs | 153 +++---
source/Plugins/Object.Wavefront/Plugin.cs | 14 +-
source/Plugins/Object.Wavefront/app.config | 4 -
source/Plugins/OpenBveAts/app.config | 4 -
.../Route.Bve5/MapParser/ConfirmComponents.cs | 5 +-
source/Plugins/Route.Bve5/Plugin.cs | 2 -
source/Plugins/Route.Bve5/Route.Bve5.csproj | 4 +-
source/Plugins/Route.Bve5/ScenarioParser.cs | 2 +-
source/Plugins/Route.Bve5/app.config | 4 -
source/Plugins/Route.Bve5/packages.config | 2 +-
.../CsvRwRouteParser.Preprocess.cs | 6 -
.../Namespaces/NonTrack/Structure.cs | 2 +-
.../Route.CsvRw/Namespaces/Track/Track.cs | 20 +-
source/Plugins/Route.CsvRw/Plugin.cs | 2 -
.../Route.CsvRw/Structures/Expression.cs | 5 -
.../Structures/Signals/SignalData.BVE4.cs | 134 +++---
.../Plugins/Route.CsvRw/XML/DynamicLight.cs | 5 +-
source/Plugins/Route.CsvRw/app.config | 4 -
source/Plugins/Route.Mechanik/Plugin.cs | 14 +-
source/Plugins/Route.Mechanik/app.config | 4 -
source/Plugins/Sound.Flac/Decoder.cs | 160 +++----
source/Plugins/Sound.Flac/Plugin.cs | 4 -
source/Plugins/Sound.Flac/app.config | 4 -
source/Plugins/Sound.MP3/Plugin.cs | 4 -
source/Plugins/Sound.MP3/app.config | 4 -
.../Sound.RiffWave/Chunks/DataChunk.cs | 9 +-
.../Plugins/Sound.RiffWave/Plugin.Parser.cs | 133 ++----
source/Plugins/Sound.RiffWave/Plugin.cs | 6 +-
source/Plugins/Sound.RiffWave/app.config | 4 -
source/Plugins/Sound.Vorbis/Plugin.cs | 4 -
source/Plugins/Sound.Vorbis/app.config | 2 +-
source/Plugins/Texture.Ace/Plugin.Parser.cs | 10 +-
source/Plugins/Texture.Ace/Plugin.cs | 5 +-
source/Plugins/Texture.Ace/app.config | 4 -
.../BMP/BmpDecoder.cs | 2 +-
.../GIF/GifDecoder.cs | 4 +-
.../PNG/ColorType.cs | 2 +-
.../PNG/PngDecoder.cs | 12 +-
.../Texture.BmpGifJpegPngTiff/app.config | 4 -
source/Plugins/Texture.Dds/Dds.FourCc.cs | 2 +-
source/Plugins/Texture.Dds/Plugin.Parser.cs | 130 +++---
source/Plugins/Texture.Dds/app.config | 4 -
source/Plugins/Texture.Tga/app.config | 4 -
source/Plugins/Train.MsTs/Train.MsTs.csproj | 14 +-
source/Plugins/Train.MsTs/app.config | 4 -
source/Plugins/Train.MsTs/packages.config | 6 +-
.../Panel/PanelAnimatedXmlParser.cs | 2 +-
.../Train.OpenBve/Panel/PanelCfgParser.cs | 138 ++----
.../Train.OpenBve/Panel/PanelXmlParser.cs | 2 +-
.../Train.OpenBve/Sound/SoundCfg.Xml.cs | 8 +-
.../Train/BVE/ExtensionsCfgParser.cs | 442 +++++++++---------
.../Train.OpenBve/Train/BVE/TrainDatParser.cs | 56 +--
.../Train/XML/TrainXmlParser.CarNode.cs | 11 -
.../Train.OpenBve/Train/XML/TrainXmlParser.cs | 9 +-
source/Plugins/Train.OpenBve/app.config | 4 -
source/Plugins/Win32PluginProxy/App.config | 4 -
source/RouteManager2/CurrentRoute.cs | 45 +-
.../RouteManager2/Illustrations/RouteMap.cs | 4 +
source/RouteManager2/RouteInformation.cs | 3 +-
source/RouteManager2/app.config | 4 -
source/RouteViewer/Audio/Sounds.Update.cs | 8 +-
source/RouteViewer/FunctionScripts.cs | 21 +-
source/RouteViewer/Game/Menu.cs | 5 +-
source/RouteViewer/LoadingR.cs | 84 +++-
source/RouteViewer/NewRendererR.cs | 2 +-
source/RouteViewer/Options.cs | 15 +-
source/RouteViewer/ProgramR.cs | 55 ++-
source/RouteViewer/System/Gamewindow.cs | 2 +-
source/RouteViewer/System/Host.cs | 6 +-
source/RouteViewer/TrainManagerR.cs | 20 +
source/RouteViewer/app.config | 4 -
source/RouteViewer/formOptions.Designer.cs | 40 +-
source/RouteViewer/formOptions.cs | 16 +-
source/SoundManager/app.config | 4 -
source/TrainEditor/app.config | 4 -
source/TrainEditor2/App.config | 4 -
source/TrainManager/Car/CarBase.cs | 58 +--
.../Car/Systems/ReadhesionDevice.cs | 3 +-
source/TrainManager/Car/Systems/RunSounds.cs | 6 +-
source/TrainManager/Car/Systems/Sanders.cs | 9 +-
.../TrainManager/Car/Windscreen/Windscreen.cs | 2 +-
.../Handles/Brake/Handles.Brake.cs | 32 +-
.../Handles/Brake/Handles.EmergencyBrake.cs | 3 +-
.../Handles/Brake/Handles.LocoBrake.cs | 24 +-
.../TrainManager/Handles/Power/PowerHandle.cs | 6 +-
.../SafetySystems/Plugin/ProxyPlugin.cs | 35 +-
.../AI/TrackFollowingObject.AI.cs | 3 +-
.../TrackFollowingObject/ScriptedTrain.cs | 3 +-
source/TrainManager/Train/TrainBase.cs | 56 +--
source/TrainManager/app.config | 4 -
196 files changed, 1779 insertions(+), 3059 deletions(-)
delete mode 100644 source/LibRender2/Shadows/Shadows.cs
delete mode 100644 source/Plugins/Formats.OpenBve/app.config
diff --git a/VersionCreator.sh b/VersionCreator.sh
index 9ce3711670..3debee67a4 100755
--- a/VersionCreator.sh
+++ b/VersionCreator.sh
@@ -69,7 +69,7 @@ Maintainer: leezer3
Architecture: all
Version: $Version
Provides: bve-engine
-Depends: debhelper (>= 9), mono-runtime (>= 5.20.1), libmono-corlib4.5-cil (>= 5.20.1), libmono-system-drawing4.0-cil (>= 1.0), libmono-system-windows-forms4.0-cil (>= 1.0), libmono-system4.0-cil (>= 5.20.1), libmono-system-xml-linq4.0-cil (>= 5.20.1), libmono-i18n-cjk4.0-cil, libmono-i18n-mideast4.0-cil, libmono-i18n-other4.0-cil, libmono-i18n-rare4.0-cil, libmono-i18n-west4.0-cil, libmono-microsoft-csharp4.0-cil (>= 5.20.1), libopenal1, libusb-1.0-0, fonts-noto-core, fonts-noto-cjk
+Depends: debhelper (>= 9), mono-runtime (>= 5.20.1), libmono-corlib4.5-cil (>= 5.20.1), libmono-system-drawing4.0-cil (>= 1.0), libmono-system-windows-forms4.0-cil (>= 1.0), libmono-system4.0-cil (>= 5.20.1), libmono-system-xml-linq4.0-cil (>= 5.20.1), libmono-i18n4.0-all, libmono-microsoft-csharp4.0-cil (>= 5.20.1), libopenal1, libusb-1.0-0, fonts-noto-core, fonts-noto-cjk
Recommends: bve-route, bve-train
Homepage: http://openbve-project.net
Description: realistic 3D train/railway simulator (main program)
diff --git a/assets/Compatibility/RoutePatches/Hungary.xml b/assets/Compatibility/RoutePatches/Hungary.xml
index f6d2f1003f..cf0ce1d518 100644
--- a/assets/Compatibility/RoutePatches/Hungary.xml
+++ b/assets/Compatibility/RoutePatches/Hungary.xml
@@ -6,7 +6,6 @@
- true
@@ -90,11 +89,5 @@
true
true
-
- 8444E8B8286A703C70C55C31B4FCE7EB2636C77EA72297004FE4EC2FD61AB842
- Teglagyari-kisvasut.csv
- true
- true
-
\ No newline at end of file
diff --git a/assets/Compatibility/RoutePatches/Japan.xml b/assets/Compatibility/RoutePatches/Japan.xml
index cc2ca0756e..86e4134cd3 100644
--- a/assets/Compatibility/RoutePatches/Japan.xml
+++ b/assets/Compatibility/RoutePatches/Japan.xml
@@ -201,12 +201,5 @@
1367S(曳舟→渋谷)bve4.csv
true
-
-
-
- DF28B51375CD2E1ECB1A894876A18398BBDCB42D1F3F09D6BA0EBE26EDA6E60E
- l-テエSlJoテゥテ嘘.csv
- Texture.Background(1) gaku2\Back_Mt1.bmp
-
\ No newline at end of file
diff --git a/assets/Compatibility/RoutePatches/UnitedKingdom.xml b/assets/Compatibility/RoutePatches/UnitedKingdom.xml
index f744204d3e..1d726346eb 100644
--- a/assets/Compatibility/RoutePatches/UnitedKingdom.xml
+++ b/assets/Compatibility/RoutePatches/UnitedKingdom.xml
@@ -51,21 +51,6 @@
true
Bakerloo v3 routefile detected- Applying cylinder hack.
-
-
- 58A8458F15C8C007EA0333652E1D9F06D6716A700C925E052E3E4774049C91DE
- BVE2 Edgware-Morden via Bank.csv
- true
- Northern Line v3.2 routefile detected- Applying cylinder hack.
- LU.xml
-
-
- 310C70EF764E226062E40B094E5C8A2CAAD80BA4EA97E100E42D3307C033EB33
- BVE2 Kennington-High Barnet.csv
- true
- Northern Line v3.2 routefile detected- Applying cylinder hack.
- LU.xml
-
diff --git a/assets/Languages/en-US.xlf b/assets/Languages/en-US.xlf
index 79a7582719..25be7ef51a 100755
--- a/assets/Languages/en-US.xlf
+++ b/assets/Languages/en-US.xlf
@@ -1204,18 +1204,6 @@
Miscellaneous
-
- Camera options
-
-
- Smooth interior transition
-
-
- Smooth exterior transition
-
-
- Transition duration (sec):
-
Detail of simulation
@@ -1421,29 +1409,6 @@
UI Scale Factor:
-
-
- The texture filtering mode used to smooth textures.
-
-
- Higher levels of anisotropic filtering improve texture quality when viewed at an angle.
-
-
- Reduces jagged edges on polygons.
-
-
- Sets the quality of transparency rendering.
-
-
- The maximum distance at which objects are rendered.
-
-
- Enables motion blur effects when moving at speed.
-
-
- Enable the modern shader-based renderer. Recommended for better visuals and performance on modern hardware.
-
-
CSV files
diff --git a/assets/Languages/id-ID.xlf b/assets/Languages/id-ID.xlf
index 6caf778145..92a6e9bda9 100644
--- a/assets/Languages/id-ID.xlf
+++ b/assets/Languages/id-ID.xlf
@@ -1,4 +1,4 @@
-
+
@@ -1635,11 +1635,11 @@
Previous Page...
- Sebelumnya...
+ Berikutnya...
Next Page...
- Berikutnya...
+ Sebelumnya..
Kiosk Mode
@@ -1812,36 +1812,6 @@
Intensitas Bayangan:
-
-
- The texture filtering mode used to smooth textures.
- Mode pemfilteran tekstur yang digunakan untuk menghaluskan tekstur.
-
-
- Higher levels of anisotropic filtering improve texture quality when viewed at an angle.
- Level pemfilteran anisotropik yang lebih tinggi meningkatkan kualitas tekstur saat dilihat dari sudut miring.
-
-
- Reduces jagged edges on polygons.
- Mengurangi tepi bergerigi pada poligon.
-
-
- Sets the quality of transparency rendering.
- Mengatur kualitas rendering transparansi.
-
-
- The maximum distance at which objects are rendered.
- Jarak maksimum di mana objek akan ditampilkan.
-
-
- Enables motion blur effects when moving at speed.
- Mengaktifkan efek motion blur saat bergerak dengan kecepatan tinggi.
-
-
- Enable the modern shader-based renderer. Recommended for better visuals and performance on modern hardware.
- Aktifkan renderer berbasis shader modern. Direkomasikan untuk visual dan performa yang lebih baik pada perangkat keras modern.
-
-
CSV files
diff --git a/assets/Shaders/default.frag b/assets/Shaders/default.frag
index f273f94413..ace1756be0 100644
--- a/assets/Shaders/default.frag
+++ b/assets/Shaders/default.frag
@@ -28,32 +28,26 @@ in vec4 oViewPos;
in vec2 oUv;
in vec4 oColor;
in vec4 oLightResult;
-// --- SHADOW MAPPING ---
-uniform bool uShadowEnabled;
-uniform float uShadowStrength;
-uniform int uShadowCascadeCount;
-
-uniform sampler2DShadow uShadowMap0;
-uniform sampler2DShadow uShadowMap1;
-uniform sampler2DShadow uShadowMap2;
-uniform sampler2DShadow uShadowMap3;
-
-uniform float uShadowSplit0; // Boundary where cascade 0 ends and 1 begins
-uniform float uShadowSplit1; // Boundary where cascade 1 ends and 2 begins
-uniform float uShadowSplit2; // Boundary where cascade 2 ends and 3 begins
-uniform float uShadowSplit3; // Final shadow distance boundary
-
-uniform float uShadowBias0;
-uniform float uShadowBias1;
-uniform float uShadowBias2;
-uniform float uShadowBias3;
-
-uniform float uShadowNormalBias0;
-uniform float uShadowNormalBias1;
-uniform float uShadowNormalBias2;
-uniform float uShadowNormalBias3;
-
-uniform vec2 uAlphaTest;
+uniform sampler2DShadow uShadowMap0; // Cascade 0 (near)
+uniform sampler2DShadow uShadowMap1; // Cascade 1 (mid)
+uniform sampler2DShadow uShadowMap2; // Cascade 2 (far)
+uniform sampler2DShadow uShadowMap3; // Cascade 3 (extra far)
+uniform float uCascadeFarDist0;
+uniform float uCascadeFarDist1;
+uniform float uCascadeFarDist2;
+uniform float uCascadeFarDist3;
+uniform float uCascadeBias0;
+uniform float uCascadeBias1;
+uniform float uCascadeBias2;
+uniform float uCascadeBias3;
+uniform float uNormalBias0;
+uniform float uNormalBias1;
+uniform float uNormalBias2;
+uniform float uNormalBias3;
+uniform float uShadowStrength;
+uniform bool uShadowEnabled;
+uniform int uCascadeCount; // 2, 3, or 4
+uniform vec2 uAlphaTest;
uniform sampler2D uTexture;
uniform sampler2D uNightTexture;
uniform bool uIsNightTexture;
@@ -75,6 +69,7 @@ in vec4 vPosLightSpace0;
in vec4 vPosLightSpace1;
in vec4 vPosLightSpace2;
in vec4 vPosLightSpace3;
+in float vViewDepth;
uniform int uMaterialFlags;
uniform float uBrightness;
uniform float uOpacity;
@@ -86,8 +81,8 @@ uniform float uFogDensity;
uniform bool uFogIsLinear;
out vec4 fragColor;
-/// Samples a single cascade using hardware PCF.
-float GetCascadeShadowFactor(sampler2DShadow shadowMap, vec4 posLightSpace, float bias, float normalBias)
+/// Samples a single cascade with 4-tap PCF via hardware comparison.
+float SampleCascade(sampler2DShadow shadowMap, vec4 posLightSpace, float bias, float normalBias)
{
vec3 projCoords = posLightSpace.xyz / posLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
@@ -105,7 +100,7 @@ float GetCascadeShadowFactor(sampler2DShadow shadowMap, vec4 posLightSpace, floa
vec3 lightDir = normalize(uLight.position);
float biasScale = clamp(1.0 - dot(normal, lightDir), 0.0, 1.0);
// Multiply the base Z-bias by a slope factor to perfectly cure acne on thin meshes
- float activeBias = bias * (1.0 + biasScale * normalBias);
+ float activeBias = bias * (1.1 + biasScale * normalBias);
float currentDepth = projCoords.z - activeBias;
@@ -124,50 +119,43 @@ float GetCascadeShadowFactor(sampler2DShadow shadowMap, vec4 posLightSpace, floa
return shadow;
}
-/// Helper to sample a cascade by index.
float SampleCascadeByIndex(int idx)
{
- if (idx == 0) return GetCascadeShadowFactor(uShadowMap0, vPosLightSpace0, uShadowBias0, uShadowNormalBias0);
- if (idx == 1) return GetCascadeShadowFactor(uShadowMap1, vPosLightSpace1, uShadowBias1, uShadowNormalBias1);
- if (idx == 2) return GetCascadeShadowFactor(uShadowMap2, vPosLightSpace2, uShadowBias2, uShadowNormalBias2);
- if (idx == 3) return GetCascadeShadowFactor(uShadowMap3, vPosLightSpace3, uShadowBias3, uShadowNormalBias3);
+ if (idx == 0) return SampleCascade(uShadowMap0, vPosLightSpace0, uCascadeBias0, uNormalBias0);
+ if (idx == 1) return SampleCascade(uShadowMap1, vPosLightSpace1, uCascadeBias1, uNormalBias1);
+ if (idx == 2) return SampleCascade(uShadowMap2, vPosLightSpace2, uCascadeBias2, uNormalBias2);
+ if (idx == 3) return SampleCascade(uShadowMap3, vPosLightSpace3, uCascadeBias3, uNormalBias3);
return 1.0;
}
-/// Helper to get the split distance of a cascade by index.
-float GetShadowSplitDistance(int idx)
+float GetCascadeFarDist(int idx)
{
- if (idx == 0) return uShadowSplit0;
- if (idx == 1) return uShadowSplit1;
- if (idx == 2) return uShadowSplit2;
- if (idx == 3) return uShadowSplit3;
+ if (idx == 0) return uCascadeFarDist0;
+ if (idx == 1) return uCascadeFarDist1;
+ if (idx == 2) return uCascadeFarDist2;
+ if (idx == 3) return uCascadeFarDist3;
return 0.0;
}
-/// Calculates the final shadow factor using CSM with smooth blending.
-float CalculateShadowFactor()
+/// Full CSM sampling with cascade selection and smooth blending.
+float CSMShadow()
{
- if (!uShadowEnabled) return 1.0;
-
- // Calculate view depth per-pixel for perspective correctness (crucial for large polygons like ground)
- float vViewDepth = abs(oViewPos.z);
-
float blendRange = 15.0;
float shadow = 1.0;
- int cascadeCount = uShadowCascadeCount;
+ int cascadeCount = uCascadeCount;
for (int i = 0; i < cascadeCount; i++)
{
- float splitDist = GetShadowSplitDistance(i);
+ float farDist = GetCascadeFarDist(i);
- if (vViewDepth < splitDist)
+ if (vViewDepth < farDist)
{
shadow = SampleCascadeByIndex(i);
// Blend toward next cascade near the boundary
if (i < cascadeCount - 1)
{
- float blendStart = splitDist - blendRange;
+ float blendStart = farDist - blendRange;
if (vViewDepth > blendStart)
{
float nextShadow = SampleCascadeByIndex(i + 1);
@@ -178,15 +166,15 @@ float CalculateShadowFactor()
else
{
// Last cascade: fade out at far edge
- float fadeStart = splitDist - blendRange * 2.0;
+ float fadeStart = farDist - blendRange * 2.0;
if (vViewDepth > fadeStart)
{
- float t = (vViewDepth - fadeStart) / (splitDist - fadeStart);
+ float t = (vViewDepth - fadeStart) / (farDist - fadeStart);
shadow = mix(shadow, 1.0, t);
}
}
- break;
+ break; // Found our cascade, stop searching
}
}
@@ -253,7 +241,11 @@ void main(void)
* as otherwise light coming through a semi-transparent material will
* affect it's final opacity, and hence whether its discarded or not
*/
- float shadow = CalculateShadowFactor();
+ float shadow = 1.0;
+ if (uShadowEnabled)
+ {
+ shadow = CSMShadow();
+ }
if ((uMaterialFlags & 1) == 0 && (uMaterialFlags & 4) == 0)
{
diff --git a/assets/Shaders/default.vert b/assets/Shaders/default.vert
index fb37ec3176..f86bd5e493 100644
--- a/assets/Shaders/default.vert
+++ b/assets/Shaders/default.vert
@@ -79,6 +79,7 @@ out vec4 vPosLightSpace0;
out vec4 vPosLightSpace1;
out vec4 vPosLightSpace2;
out vec4 vPosLightSpace3;
+out float vViewDepth;
out vec3 vNormal;
vec4 getLightResult()
@@ -221,6 +222,8 @@ void main()
vPosLightSpace1 = uLightSpaceMatrix1 * worldPos4;
vPosLightSpace2 = uLightSpaceMatrix2 * worldPos4;
vPosLightSpace3 = uLightSpaceMatrix3 * worldPos4;
+
+ vViewDepth = abs(oViewPos.z);
}
else
{
@@ -228,6 +231,7 @@ void main()
vPosLightSpace1 = vec4(0.0);
vPosLightSpace2 = vec4(0.0);
vPosLightSpace3 = vec4(0.0);
+ vViewDepth = 0.0;
}
oUv = (uCurrentTextureMatrix * vec4(iUv, 1.0, 1.0)).xy;
diff --git a/assets/Shaders/shadow_depth.vert b/assets/Shaders/shadow_depth.vert
index 18117b507d..8fdb4e17e7 100644
--- a/assets/Shaders/shadow_depth.vert
+++ b/assets/Shaders/shadow_depth.vert
@@ -30,7 +30,6 @@ layout(location = 4) in ivec3 iMatrixChain;
uniform mat4 uLightSpaceMatrix;
uniform mat4 uModelMatrix;
-uniform mat4 uTextureMatrix;
out vec2 vUv;
@@ -90,7 +89,7 @@ void main()
// OpenBVE explicitly negates Z for world geometry.
pos.z = -pos.z;
- vUv = (uTextureMatrix * vec4(iUv, 1.0, 1.0)).xy;
+ vUv = iUv;
gl_Position = uLightSpaceMatrix * uModelMatrix * vec4(pos, 1.0);
}
diff --git a/source/AssimpParser/app.config b/source/AssimpParser/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/AssimpParser/app.config
+++ b/source/AssimpParser/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/CarXMLConvertor/App.config b/source/CarXMLConvertor/App.config
index e83b408bea..3a071c0277 100644
--- a/source/CarXMLConvertor/App.config
+++ b/source/CarXMLConvertor/App.config
@@ -13,10 +13,6 @@
-
-
-
-
diff --git a/source/InputDevicePlugins/DefaultDisplayPlugin/app.config b/source/InputDevicePlugins/DefaultDisplayPlugin/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/InputDevicePlugins/DefaultDisplayPlugin/app.config
+++ b/source/InputDevicePlugins/DefaultDisplayPlugin/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/InputDevicePlugins/DenshaDeGoInput/app.config b/source/InputDevicePlugins/DenshaDeGoInput/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/InputDevicePlugins/DenshaDeGoInput/app.config
+++ b/source/InputDevicePlugins/DenshaDeGoInput/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/InputDevicePlugins/KatoInput/app.config b/source/InputDevicePlugins/KatoInput/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/InputDevicePlugins/KatoInput/app.config
+++ b/source/InputDevicePlugins/KatoInput/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/InputDevicePlugins/SanYingInput/app.config b/source/InputDevicePlugins/SanYingInput/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/InputDevicePlugins/SanYingInput/app.config
+++ b/source/InputDevicePlugins/SanYingInput/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/InputDevicePlugins/ZuikiInput/app.config b/source/InputDevicePlugins/ZuikiInput/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/InputDevicePlugins/ZuikiInput/app.config
+++ b/source/InputDevicePlugins/ZuikiInput/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/LibRender2/Camera/Camera.cs b/source/LibRender2/Camera/Camera.cs
index 3093378292..01ae3cb140 100644
--- a/source/LibRender2/Camera/Camera.cs
+++ b/source/LibRender2/Camera/Camera.cs
@@ -102,21 +102,6 @@ public CameraViewMode CurrentMode
public CameraAlignment SavedTrack;
/// The current quad tree leaf node
public QuadTreeLeafNode QuadTreeLeaf;
-
- /// The target camera car index for queued transitions
- public int TargetCameraCar = -1;
- /// The previous camera car index (used for transitions)
- public int PreviousCameraCar = -1;
- /// The current transition timer
- public double CameraCarTransitionTimer = 0.0;
- /// Whether the camera is transitioning between cars
- public bool IsTransitioning = false;
- /// The start anchor for mode transitions (fly-in)
- public (Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, double TrackPosition, CameraAlignment Alignment) ModeTransitionStart;
- /// The timer for mode transitions (fly-in)
- public double ModeTransitionTimer = 1.0;
- /// The duration of the camera car transition in seconds
- public const double CameraCarTransitionDuration = 0.4;
private Vector3 absolutePosition;
private CameraAlignment alignmentDirection;
diff --git a/source/LibRender2/Menu/Menu.OptionType.cs b/source/LibRender2/Menu/Menu.OptionType.cs
index 73d2beb992..6f5d01a112 100644
--- a/source/LibRender2/Menu/Menu.OptionType.cs
+++ b/source/LibRender2/Menu/Menu.OptionType.cs
@@ -1,4 +1,4 @@
-//Simplified BSD License (BSD-2-Clause)
+//Simplified BSD License (BSD-2-Clause)
//
//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project
//
@@ -46,8 +46,6 @@ public enum OptionType
/// Sets whether to automatically reload the current objects
AutoReloadObjects,
/// Sets the shadow quality
- ShadowQuality,
- /// Sets whether shadow casters are filtered per cascade
- ShadowFilterCascades
+ ShadowQuality
}
}
diff --git a/source/LibRender2/Menu/MenuEntries/MenuOption.cs b/source/LibRender2/Menu/MenuEntries/MenuOption.cs
index c4330b9898..6bb95e63dd 100644
--- a/source/LibRender2/Menu/MenuEntries/MenuOption.cs
+++ b/source/LibRender2/Menu/MenuEntries/MenuOption.cs
@@ -1,4 +1,4 @@
-//Simplified BSD License (BSD-2-Clause)
+//Simplified BSD License (BSD-2-Clause)
//
//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project
//
@@ -169,9 +169,6 @@ public MenuOption(AbstractMenu menu, OptionType type, string text, object[] entr
break;
}
return;
- case OptionType.ShadowFilterCascades:
- CurrentlySelectedOption = BaseMenu.CurrentOptions.ShadowFilterCascades ? 0 : 1;
- return;
}
CurrentlySelectedOption = 0;
}
@@ -319,9 +316,6 @@ public void Flip()
}
BaseMenu.Renderer.InitializeShadows();
break;
- case OptionType.ShadowFilterCascades:
- BaseMenu.CurrentOptions.ShadowFilterCascades = !BaseMenu.CurrentOptions.ShadowFilterCascades;
- break;
}
diff --git a/source/LibRender2/Objects/ObjectLibrary.cs b/source/LibRender2/Objects/ObjectLibrary.cs
index 379bdefd96..cef9ba487f 100644
--- a/source/LibRender2/Objects/ObjectLibrary.cs
+++ b/source/LibRender2/Objects/ObjectLibrary.cs
@@ -130,16 +130,15 @@ public void ShowObject(ObjectState State, ObjectType Type)
* Unfortunately, there appear to be X objects in the wild which expect a non-default wrapping mode
* which means the best fast exit we can do is to check for RepeatRepeat....
*
- */
- for (int i = 0; i < face.Vertices.Length; i++)
+ */
+ foreach (VertexTemplate vertex in State.Prototype.Mesh.Vertices)
{
- int v = face.Vertices[i].Index;
- if (State.Prototype.Mesh.Vertices[v].TextureCoordinates.X < 0.0f || State.Prototype.Mesh.Vertices[v].TextureCoordinates.X > 1.0f)
+ if (vertex.TextureCoordinates.X < 0.0f || vertex.TextureCoordinates.X > 1.0f)
{
wrap |= OpenGlTextureWrapMode.RepeatClamp;
}
- if (State.Prototype.Mesh.Vertices[v].TextureCoordinates.Y < 0.0f || State.Prototype.Mesh.Vertices[v].TextureCoordinates.Y > 1.0f)
+ if (vertex.TextureCoordinates.Y < 0.0f || vertex.TextureCoordinates.Y > 1.0f)
{
wrap |= OpenGlTextureWrapMode.ClampRepeat;
}
diff --git a/source/LibRender2/Shaders/Shader.cs b/source/LibRender2/Shaders/Shader.cs
index 2ebad8f5e9..71d0e4bd68 100644
--- a/source/LibRender2/Shaders/Shader.cs
+++ b/source/LibRender2/Shaders/Shader.cs
@@ -43,30 +43,30 @@ public class Shader : AbstractShader
public readonly VertexLayout VertexLayout;
public readonly UniformLayout UniformLayout;
private readonly int uShadowEnabledLocation;
- private readonly int uShadowStrengthLocation;
- private readonly int uShadowCascadeCountLocation;
- private readonly int uShadowMap0Location;
- private readonly int uShadowMap1Location;
- private readonly int uShadowMap2Location;
- private readonly int uShadowMap3Location;
- private readonly int uShadowSplit0Location;
- private readonly int uShadowSplit1Location;
- private readonly int uShadowSplit2Location;
- private readonly int uShadowSplit3Location;
- private readonly int uShadowBias0Location;
- private readonly int uShadowBias1Location;
- private readonly int uShadowBias2Location;
- private readonly int uShadowBias3Location;
- private readonly int uShadowNormalBias0Location;
- private readonly int uShadowNormalBias1Location;
- private readonly int uShadowNormalBias2Location;
- private readonly int uShadowNormalBias3Location;
private readonly int uLightSpaceMatrix0Location;
private readonly int uLightSpaceMatrix1Location;
private readonly int uLightSpaceMatrix2Location;
- private readonly int uLightSpaceMatrix3Location;
+ private readonly int uShadowMap0Location;
+ private readonly int uShadowMap1Location;
+ private readonly int uShadowMap2Location;
+ private readonly int uCascadeFarDist0Location;
+ private readonly int uCascadeFarDist1Location;
+ private readonly int uCascadeFarDist2Location;
+ private readonly int uCascadeBias0Location;
+ private readonly int uCascadeBias1Location;
+ private readonly int uCascadeBias2Location;
+ private readonly int uShadowStrengthLocation;
private readonly int uModelMatrixLocation;
private readonly int uCurrentViewMatrixLocation;
+ private readonly int uLightSpaceMatrix3Location;
+ private readonly int uShadowMap3Location;
+ private readonly int uCascadeFarDist3Location;
+ private readonly int uCascadeBias3Location;
+ private readonly int uNormalBias0Location;
+ private readonly int uNormalBias1Location;
+ private readonly int uNormalBias2Location;
+ private readonly int uNormalBias3Location;
+ private readonly int uCascadeCountLocation;
// Caches
private bool? lastIsLight;
@@ -92,30 +92,30 @@ public class Shader : AbstractShader
public Shader(BaseRenderer Renderer, string vertexShaderName, string fragmentShaderName, bool isFromStream = false) : base(Renderer, vertexShaderName, fragmentShaderName, isFromStream, true)
{
uShadowEnabledLocation = GL.GetUniformLocation(Handle, "uShadowEnabled");
- uShadowStrengthLocation = GL.GetUniformLocation(Handle, "uShadowStrength");
- uShadowCascadeCountLocation = GL.GetUniformLocation(Handle, "uShadowCascadeCount");
- uShadowMap0Location = GL.GetUniformLocation(Handle, "uShadowMap0");
- uShadowMap1Location = GL.GetUniformLocation(Handle, "uShadowMap1");
- uShadowMap2Location = GL.GetUniformLocation(Handle, "uShadowMap2");
- uShadowMap3Location = GL.GetUniformLocation(Handle, "uShadowMap3");
- uShadowSplit0Location = GL.GetUniformLocation(Handle, "uShadowSplit0");
- uShadowSplit1Location = GL.GetUniformLocation(Handle, "uShadowSplit1");
- uShadowSplit2Location = GL.GetUniformLocation(Handle, "uShadowSplit2");
- uShadowSplit3Location = GL.GetUniformLocation(Handle, "uShadowSplit3");
- uShadowBias0Location = GL.GetUniformLocation(Handle, "uShadowBias0");
- uShadowBias1Location = GL.GetUniformLocation(Handle, "uShadowBias1");
- uShadowBias2Location = GL.GetUniformLocation(Handle, "uShadowBias2");
- uShadowBias3Location = GL.GetUniformLocation(Handle, "uShadowBias3");
- uShadowNormalBias0Location = GL.GetUniformLocation(Handle, "uShadowNormalBias0");
- uShadowNormalBias1Location = GL.GetUniformLocation(Handle, "uShadowNormalBias1");
- uShadowNormalBias2Location = GL.GetUniformLocation(Handle, "uShadowNormalBias2");
- uShadowNormalBias3Location = GL.GetUniformLocation(Handle, "uShadowNormalBias3");
uLightSpaceMatrix0Location = GL.GetUniformLocation(Handle, "uLightSpaceMatrix0");
uLightSpaceMatrix1Location = GL.GetUniformLocation(Handle, "uLightSpaceMatrix1");
uLightSpaceMatrix2Location = GL.GetUniformLocation(Handle, "uLightSpaceMatrix2");
- uLightSpaceMatrix3Location = GL.GetUniformLocation(Handle, "uLightSpaceMatrix3");
+ uShadowMap0Location = GL.GetUniformLocation(Handle, "uShadowMap0");
+ uShadowMap1Location = GL.GetUniformLocation(Handle, "uShadowMap1");
+ uShadowMap2Location = GL.GetUniformLocation(Handle, "uShadowMap2");
+ uCascadeFarDist0Location = GL.GetUniformLocation(Handle, "uCascadeFarDist0");
+ uCascadeFarDist1Location = GL.GetUniformLocation(Handle, "uCascadeFarDist1");
+ uCascadeFarDist2Location = GL.GetUniformLocation(Handle, "uCascadeFarDist2");
+ uCascadeBias0Location = GL.GetUniformLocation(Handle, "uCascadeBias0");
+ uCascadeBias1Location = GL.GetUniformLocation(Handle, "uCascadeBias1");
+ uCascadeBias2Location = GL.GetUniformLocation(Handle, "uCascadeBias2");
+ uShadowStrengthLocation = GL.GetUniformLocation(Handle, "uShadowStrength");
uModelMatrixLocation = GL.GetUniformLocation(Handle, "uModelMatrix");
uCurrentViewMatrixLocation = GL.GetUniformLocation(Handle, "uCurrentViewMatrix");
+ uLightSpaceMatrix3Location = GL.GetUniformLocation(Handle, "uLightSpaceMatrix3");
+ uShadowMap3Location = GL.GetUniformLocation(Handle, "uShadowMap3");
+ uCascadeFarDist3Location = GL.GetUniformLocation(Handle, "uCascadeFarDist3");
+ uCascadeBias3Location = GL.GetUniformLocation(Handle, "uCascadeBias3");
+ uNormalBias0Location = GL.GetUniformLocation(Handle, "uNormalBias0");
+ uNormalBias1Location = GL.GetUniformLocation(Handle, "uNormalBias1");
+ uNormalBias2Location = GL.GetUniformLocation(Handle, "uNormalBias2");
+ uNormalBias3Location = GL.GetUniformLocation(Handle, "uNormalBias3");
+ uCascadeCountLocation = GL.GetUniformLocation(Handle, "uCascadeCount");
VertexLayout = GetVertexLayout();
UniformLayout = GetUniformLayout();
@@ -128,7 +128,7 @@ public Shader(BaseRenderer Renderer, string vertexShaderName, string fragmentSha
GL.ProgramUniform1(Handle, uShadowMap3Location, 7);
// Also ensure shadow is disabled by default
GL.ProgramUniform1(Handle, uShadowEnabledLocation, 0);
- GL.ProgramUniform1(Handle, uShadowCascadeCountLocation, 0);
+ GL.ProgramUniform1(Handle, uCascadeCountLocation, 0);
GL.ProgramUniform1(Handle, uShadowStrengthLocation, 1.0f);
}
@@ -524,15 +524,15 @@ public void SetCascadeShadowMapUnit(int cascade, int textureUnit)
GL.ProgramUniform1(Handle, loc, textureUnit);
}
- public void SetShadowSplitDistance(int cascade, float distance)
+ public void SetCascadeFarDistance(int cascade, float distance)
{
int loc;
switch (cascade)
{
- case 0: loc = uShadowSplit0Location; break;
- case 1: loc = uShadowSplit1Location; break;
- case 2: loc = uShadowSplit2Location; break;
- case 3: loc = uShadowSplit3Location; break;
+ case 0: loc = uCascadeFarDist0Location; break;
+ case 1: loc = uCascadeFarDist1Location; break;
+ case 2: loc = uCascadeFarDist2Location; break;
+ case 3: loc = uCascadeFarDist3Location; break;
default: return;
}
GL.ProgramUniform1(Handle, loc, distance);
@@ -543,10 +543,10 @@ public void SetCascadeBias(int cascade, float bias)
int loc;
switch (cascade)
{
- case 0: loc = uShadowBias0Location; break;
- case 1: loc = uShadowBias1Location; break;
- case 2: loc = uShadowBias2Location; break;
- case 3: loc = uShadowBias3Location; break;
+ case 0: loc = uCascadeBias0Location; break;
+ case 1: loc = uCascadeBias1Location; break;
+ case 2: loc = uCascadeBias2Location; break;
+ case 3: loc = uCascadeBias3Location; break;
default: return;
}
GL.ProgramUniform1(Handle, loc, bias);
@@ -557,18 +557,18 @@ public void SetNormalBias(int cascade, float bias)
int loc;
switch (cascade)
{
- case 0: loc = uShadowNormalBias0Location; break;
- case 1: loc = uShadowNormalBias1Location; break;
- case 2: loc = uShadowNormalBias2Location; break;
- case 3: loc = uShadowNormalBias3Location; break;
+ case 0: loc = uNormalBias0Location; break;
+ case 1: loc = uNormalBias1Location; break;
+ case 2: loc = uNormalBias2Location; break;
+ case 3: loc = uNormalBias3Location; break;
default: return;
}
GL.ProgramUniform1(Handle, loc, bias);
}
- public void SetShadowCascadeCount(int count)
+ public void SetCascadeCount(int count)
{
- GL.ProgramUniform1(Handle, uShadowCascadeCountLocation, count);
+ GL.ProgramUniform1(Handle, uCascadeCountLocation, count);
}
public void SetShadowStrength(float strength)
diff --git a/source/LibRender2/Shadows/CascadedShadowCaster.cs b/source/LibRender2/Shadows/CascadedShadowCaster.cs
index 6c9f63ecc7..32c527203c 100644
--- a/source/LibRender2/Shadows/CascadedShadowCaster.cs
+++ b/source/LibRender2/Shadows/CascadedShadowCaster.cs
@@ -1,7 +1,7 @@
using System;
using OpenBveApi.Math;
-namespace LibRender2.ShadowMapping
+namespace LibRender2.Shadows
{
///
/// Computes per-cascade light-space matrices by fitting an orthographic
@@ -29,12 +29,8 @@ public class CascadedShadowCaster
public Matrix4D[] LightSpaceMatrices { get; private set; }
/// Per-cascade split distances (view-space Z).
- ///
- /// Length = CascadeCount. Renamed from FarDistance to SplitDistance to better reflect
- /// standard CSM/PSSM terminology. These values represent the frustum slice boundaries
- /// in view-space Z where the shadow transition between cascades occurs.
- ///
- public float[] SplitDistances { get; private set; }
+ ///>Length = CascadeCount. Used in the fragment shader to pick cascade.
+ public float[] CascadeFarDistances { get; private set; }
/// Per-cascade depth bias for shadow acne prevention.
public float[] CascadeBiases { get; private set; }
@@ -43,7 +39,7 @@ public CascadedShadowCaster(int cascadeCount = 3)
{
CascadeCount = cascadeCount;
LightSpaceMatrices = new Matrix4D[cascadeCount];
- SplitDistances = new float[cascadeCount];
+ CascadeFarDistances = new float[cascadeCount];
CascadeBiases = new float[cascadeCount];
for (int i = 0; i < cascadeCount; i++)
@@ -141,7 +137,7 @@ public void Update(Vector3 lightDirection, Matrix4D cameraView, Matrix4D cameraP
Matrix4D.CreateOrthographic(orthoSize * 2.0, orthoSize * 2.0, zNear, zFar, out Matrix4D lightProj);
LightSpaceMatrices[i] = lightView * lightProj;
- SplitDistances[i] = (float)splits[i + 1];
+ CascadeFarDistances[i] = (float)splits[i + 1];
// Z-Bias: Convert physical texel size into a Depth Buffer fraction.
// This ensures we push the depth exactly enough to cure acne, but no more.
diff --git a/source/LibRender2/Shadows/CascadedShadowMap.cs b/source/LibRender2/Shadows/CascadedShadowMap.cs
index 2f2f505e24..c0ae11b574 100644
--- a/source/LibRender2/Shadows/CascadedShadowMap.cs
+++ b/source/LibRender2/Shadows/CascadedShadowMap.cs
@@ -1,7 +1,7 @@
using System;
using OpenTK.Graphics.OpenGL;
-namespace LibRender2.ShadowMapping
+namespace LibRender2.Shadows
{
///
/// Manages multiple depth-only FBOs for Cascaded Shadow Mapping.
diff --git a/source/LibRender2/Shadows/FrustumUtils.cs b/source/LibRender2/Shadows/FrustumUtils.cs
index ad345f414c..ec8b81590e 100644
--- a/source/LibRender2/Shadows/FrustumUtils.cs
+++ b/source/LibRender2/Shadows/FrustumUtils.cs
@@ -2,7 +2,7 @@
using System.Linq;
using OpenBveApi.Math;
-namespace LibRender2.ShadowMapping
+namespace LibRender2.Shadows
{
///
/// Utility class for camera frustum calculations, specifically for Cascaded Shadow Mapping.
diff --git a/source/LibRender2/Shadows/Shadows.cs b/source/LibRender2/Shadows/Shadows.cs
deleted file mode 100644
index 9de935cee1..0000000000
--- a/source/LibRender2/Shadows/Shadows.cs
+++ /dev/null
@@ -1,330 +0,0 @@
-using System;
-using System.Collections.Generic;
-using LibRender2.Objects;
-using LibRender2.Shaders;
-using OpenBveApi.Graphics;
-using OpenBveApi.Interface;
-using OpenBveApi.Math;
-using OpenBveApi.Objects;
-using OpenBveApi.Textures;
-using OpenTK.Graphics.OpenGL;
-
-namespace LibRender2.ShadowMapping
-{
- ///
- /// Manages the Cascaded Shadow Mapping (CSM) system, including depth passes and shader binding.
- ///
- public class Shadows
- {
- private readonly BaseRenderer renderer;
-
- /// The shadow map textures and framebuffers.
- internal CascadedShadowMap Map;
- /// The math engine for computing cascade frustums and matrices.
- internal CascadedShadowCaster Caster;
- /// The shader used for rendering the shadow depth pass.
- internal ShadowDepthShader DepthShader;
-
- /// Whether shadows are currently active.
- public bool Enabled;
- /// The current darkness of the shadows (0.0 to 1.0).
- public float Strength;
-
- public Shadows(BaseRenderer renderer)
- {
- this.renderer = renderer;
- }
-
- ///
- /// Initializes (or reinitializes) shadow mapping from current options.
- ///
- public void Initialize()
- {
- var opts = renderer.currentOptions;
-
- if (opts.ShadowResolution == ShadowMapResolution.Off)
- {
- Dispose();
- Enabled = false;
- renderer.fileSystem.AppendToLogFile("[CSM] Shadows disabled by user setting.");
- return;
- }
-
- int resolution = Math.Max(1, (int)opts.ShadowResolution);
- int cascadeCount = (int)opts.ShadowCascades;
- double shadowDistance = opts.ShadowDrawDistance == ShadowDistance.ViewingDistance ? opts.ViewingDistance : (double)(int)opts.ShadowDrawDistance;
- shadowDistance = Math.Max(1.0, shadowDistance);
- Strength = (float)opts.ShadowStrength;
-
- try
- {
- if (Map == null)
- {
- Map = new CascadedShadowMap(cascadeCount, resolution);
- }
- else
- {
- Map.Resize(cascadeCount, resolution);
- }
-
- if (Caster == null || cascadeCount != Caster.CascadeCount)
- {
- Caster = new CascadedShadowCaster(cascadeCount);
- }
-
- Caster.ShadowDistance = shadowDistance;
- Caster.Resolution = resolution;
- Caster.SplitLambda = 0.75;
- Caster.DepthMargin = 150.0;
-
- if (DepthShader == null)
- {
- DepthShader = new ShadowDepthShader(renderer, "shadow_depth", "shadow_depth", true);
- }
-
- Enabled = true;
- renderer.fileSystem.AppendToLogFile($"[CSM] Initialized: {cascadeCount} cascades, {resolution}×{resolution}, distance={shadowDistance}m, strength={Strength:P0}");
- }
- catch (Exception ex)
- {
- renderer.fileSystem.AppendToLogFile($"[CSM] Init failed: {ex.Message}");
- Enabled = false;
- GL.GetError();
- }
- }
-
- ///
- /// Performs the shadow depth pass for all cascades.
- ///
- public void RenderPass()
- {
- if (!Enabled || Map == null || Caster == null || DepthShader == null)
- {
- return;
- }
-
- // 1. Get light direction pointing FROM the sun TOWARD the scene
- // Sun position is in OpenBVE coordinates (X: right, Y: up, Z: backward)
- // Light direction needs to be negated for some components to match the shadow math.
- Vector3 lightDir = new Vector3(
- -renderer.Lighting.OptionLightPosition.X,
- -renderer.Lighting.OptionLightPosition.Y,
- renderer.Lighting.OptionLightPosition.Z
- );
-
- if (lightDir.IsNullVector())
- {
- return;
- }
-
- // 2. Update cascade matrices
- // NOTE: We pass renderer.CurrentViewMatrix here which reflects the camera's rotation.
- // The Caster will use this to align the shadow frustums with the view direction.
- Caster.Resolution = Map.Resolution;
- if (renderer.currentOptions.ShadowDrawDistance == ShadowDistance.ViewingDistance)
- {
- Caster.ShadowDistance = renderer.currentOptions.ViewingDistance;
- }
- Caster.Update(lightDir, renderer.CurrentViewMatrix, renderer.CurrentProjectionMatrix, 0.1, renderer.Camera.VerticalViewingAngle, renderer.Screen.AspectRatio);
-
- // 3. Setup state for depth pass
- renderer.CurrentShader?.Deactivate();
- DepthShader.Activate();
- GL.Enable(EnableCap.DepthTest);
- GL.DepthFunc(DepthFunction.Less);
- if (renderer.OptionBackFaceCulling)
- {
- GL.Enable(EnableCap.CullFace);
- GL.CullFace(CullFaceMode.Front); // OpenBVE culls Front faces by default
- }
- else
- {
- GL.Disable(EnableCap.CullFace);
- }
- GL.DepthMask(true);
- DepthShader.SetTexture(0);
-
- for (int i = 0; i < Caster.CascadeCount; i++)
- {
- Map.BindCascadeForWriting(i);
- GL.Clear(ClearBufferMask.DepthBufferBit);
- DepthShader.SetLightSpaceMatrix(Caster.LightSpaceMatrices[i]);
-
- lock (renderer.VisibleObjects.LockObject)
- {
- int lastVAO = -1;
- /*
- * Culling Per-Cascade:
- * Distant objects don't need to be rendered into near-field high-res shadow maps.
- * We use a safety margin (150m) to catch long shadows from tall objects.
- */
- double maxDistance = renderer.currentOptions.ShadowFilterCascades ? Caster.SplitDistances[i] + 150.0 : double.MaxValue;
- double maxDistanceSquared = maxDistance * maxDistance;
-
- RenderFacesFiltered(renderer.VisibleObjects.OpaqueFaces, ref lastVAO, maxDistanceSquared);
- RenderFacesFiltered(renderer.VisibleObjects.AlphaFaces, ref lastVAO, maxDistanceSquared);
- }
- Map.Unbind();
- }
-
- // 4. Restore state
- GL.DepthFunc(DepthFunction.Lequal);
- GL.CullFace(CullFaceMode.Front);
- GL.Viewport(0, 0, renderer.Screen.Width, renderer.Screen.Height);
- // Shadow pass corrupts the GL texture state, so ensure we null it out
- // so the next render pass re-binds what it needs.
- renderer.LastBoundTexture = null;
- }
-
- ///
- /// Renders a collection of faces while minimizing VAO and texture state switches.
- ///
- /// The faces to render.
- /// A reference to the last bound VAO handle, to avoid redundant binds.
- private void RenderFaces(IEnumerable faces, ref int lastVAO)
- {
- RenderFacesFiltered(faces, ref lastVAO, double.MaxValue);
- }
-
- ///
- /// Renders a collection of faces filtered by distance to optimize per-cascade draw calls.
- ///
- /// The faces to render.
- /// A reference to the last bound VAO handle, to avoid redundant binds.
- /// The squared maximum distance from camera for an object to cast shadows into this cascade.
- private void RenderFacesFiltered(IEnumerable faces, ref int lastVAO, double maxDistanceSquared)
- {
- Vector3 cameraPos = renderer.Camera.AbsolutePosition;
-
- foreach (var face in faces)
- {
- if (face.Object.Prototype.Mesh.VAO == null || face.Object.DisableShadowCasting)
- {
- continue;
- }
-
- ObjectState state = face.Object;
-
- // Per-cascade distance culling
- if (maxDistanceSquared < double.MaxValue)
- {
- double dx = state.WorldPosition.X - cameraPos.X;
- double dy = state.WorldPosition.Y - cameraPos.Y;
- double dz = state.WorldPosition.Z - cameraPos.Z;
-
- if (dx * dx + dy * dy + dz * dz > maxDistanceSquared)
- {
- continue;
- }
- }
-
- DepthShader.SetModelMatrix(state.ModelMatrix * renderer.Camera.TranslationMatrix);
- DepthShader.SetTextureMatrix(state.TextureTranslation);
-
- var material = face.Object.Prototype.Mesh.Materials[face.Face.Material];
- if ((material.Flags & MaterialFlags.NoShadow) != 0 || material.BlendMode == MeshMaterialBlendMode.Additive)
- {
- continue;
- }
- if (material.DaytimeTexture != null && renderer.currentHost.LoadTexture(ref material.DaytimeTexture, (OpenGlTextureWrapMode)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)))
- {
- GL.ActiveTexture(TextureUnit.Texture0);
- GL.BindTexture(TextureTarget.Texture2D, material.DaytimeTexture.OpenGlTextures[(int)(material.WrapMode ?? OpenGlTextureWrapMode.ClampClamp)].Name);
- DepthShader.SetHasTexture(true);
- }
- else
- {
- DepthShader.SetHasTexture(false);
- }
-
- DepthShader.SetAlphaCutoff(0.5f);
- DepthShader.SetMaterialAlpha(material.Color.A / 255.0f);
- DepthShader.SetMaterialFlags(material.Flags);
-
- if (state.Matricies != null && state.Matricies.Length > 0)
- {
- DepthShader.SetCurrentAnimationMatricies(state);
- GL.BindBufferBase(BufferTarget.UniformBuffer, 0, state.MatrixBufferIndex);
- }
-
- VertexArrayObject vao = (VertexArrayObject)face.Object.Prototype.Mesh.VAO;
- if (vao.handle != lastVAO)
- {
- vao.Bind();
- lastVAO = vao.handle;
- }
- if (renderer.OptionBackFaceCulling)
- {
- if ((face.Face.Flags & FaceFlags.Face2Mask) != 0)
- {
- // Double-sided faces (Face2) must not be culled to ensure they cast shadows from both sides
- GL.Disable(EnableCap.CullFace);
- }
- else
- {
- GL.Enable(EnableCap.CullFace);
- }
- }
- PrimitiveType drawMode = renderer.GetPrimitiveType(face.Face.Flags);
- vao.Draw(drawMode, face.Face.IboStartIndex, face.Face.Vertices.Length);
- }
- }
-
- ///
- /// Binds shadow data to the main scene shader.
- ///
- public void Bind(Shader shader)
- {
- if (!Enabled || Map == null || Caster == null)
- {
- shader.SetShadowEnabled(false);
- // To satisfy strict OpenGL drivers, always bind something to the shadow map units
- // even if shadow is disabled, to avoid "sampler collision" errors.
- for (int i = 0; i < 4; i++)
- {
- GL.ActiveTexture(TextureUnit.Texture4 + i);
- GL.BindTexture(TextureTarget.Texture2D, renderer.nullDepthMap);
- }
- GL.ActiveTexture(TextureUnit.Texture0);
- return;
- }
-
- shader.Activate();
- shader.SetShadowEnabled(true);
- shader.SetShadowStrength((float)renderer.currentOptions.ShadowStrength);
- shader.SetCurrentViewMatrix(renderer.CurrentViewMatrix);
-
- Map.BindAllCascadesForReading(TextureUnit.Texture4);
-
- int cascadeCount = Caster.CascadeCount;
- for (int i = 0; i < cascadeCount; i++)
- {
- shader.SetCascadeLightSpaceMatrix(i, Caster.LightSpaceMatrices[i]);
- shader.SetCascadeShadowMapUnit(i, 4 + i);
- // Split distance = the view-space Z where this cascade ends.
- shader.SetShadowSplitDistance(i, (float)Caster.SplitDistances[i]);
- shader.SetCascadeBias(i, Caster.CascadeBiases[i] + (float)renderer.currentOptions.ShadowBias);
- shader.SetNormalBias(i, (float)renderer.currentOptions.ShadowNormalBias);
- }
-
- for (int i = cascadeCount; i < 4; i++)
- {
- shader.SetShadowSplitDistance(i, 0.0f);
- }
- shader.SetShadowCascadeCount(cascadeCount);
- }
-
- ///
- /// Disposes shadow resources.
- ///
- public void Dispose()
- {
- Map?.Dispose();
- Map = null;
- DepthShader?.Dispose();
- DepthShader = null;
- Caster = null;
- Enabled = false;
- }
- }
-}
diff --git a/source/LibRender2/Smoke/ParticleSource.cs b/source/LibRender2/Smoke/ParticleSource.cs
index c74213bae6..542b5f2841 100644
--- a/source/LibRender2/Smoke/ParticleSource.cs
+++ b/source/LibRender2/Smoke/ParticleSource.cs
@@ -112,7 +112,7 @@ public ParticleSource(BaseRenderer renderer, AbstractCar car, Vector3 offset, do
public void Update(double timeElapsed, bool currentlyVisible)
{
- if (!Renderer.AvailableNewRenderer || Controller == null)
+ if (!Renderer.AvailableNewRenderer)
{
return;
}
diff --git a/source/LibRender2/app.config b/source/LibRender2/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/LibRender2/app.config
+++ b/source/LibRender2/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/ObjectBender/app.config b/source/ObjectBender/app.config
index 2c700c093c..0a9966da17 100644
--- a/source/ObjectBender/app.config
+++ b/source/ObjectBender/app.config
@@ -11,10 +11,6 @@
-
-
-
-
diff --git a/source/ObjectViewer/FunctionScripts.cs b/source/ObjectViewer/FunctionScripts.cs
index 5861b646c0..3a76686052 100644
--- a/source/ObjectViewer/FunctionScripts.cs
+++ b/source/ObjectViewer/FunctionScripts.cs
@@ -265,17 +265,7 @@ internal static void ExecuteFunctionScript(FunctionScript Function, TrainBase Tr
Function.Stack[s] = 1;
}
s++; break;
- case Instructions.CameraCar:
- if (IsPartOfTrain && Train != null)
- {
- Function.Stack[s] = Train.CameraCar;
- }
- else
- {
- Function.Stack[s] = 0.0;
- }
- s++; break;
- // train
+ // train
case Instructions.PlayerTrain:
if (IsPartOfTrain && Train != null)
{
diff --git a/source/ObjectViewer/Options.cs b/source/ObjectViewer/Options.cs
index fcfc336cea..76188eba29 100644
--- a/source/ObjectViewer/Options.cs
+++ b/source/ObjectViewer/Options.cs
@@ -170,10 +170,12 @@ internal static void LoadOptions()
block.TryGetValue(OptionsKey.NearClipBase, ref Interface.CurrentOptions.NearClipBase, NumberRange.Positive);
// ensure viewing distance is greater than the near clipping plane to avoid rendering issues
if (Interface.CurrentOptions.ViewingDistance <= Interface.CurrentOptions.NearClipBase)
+
{
Interface.CurrentOptions.ViewingDistance = (int)Math.Ceiling(Interface.CurrentOptions.NearClipBase) + 1;
}
+ block.GetValue(OptionsKey.IsUseNewRenderer, out Interface.CurrentOptions.IsUseNewRenderer);
block.GetValue(OptionsKey.AutoReloadObjects, out Interface.CurrentOptions.AutoReloadObjects);
block.TryGetValue(OptionsKey.ViewingDistance, ref Interface.CurrentOptions.ViewingDistance, NumberRange.Positive);
break;
diff --git a/source/ObjectViewer/ProgramS.cs b/source/ObjectViewer/ProgramS.cs
index b86a4ff276..81ba263a7c 100644
--- a/source/ObjectViewer/ProgramS.cs
+++ b/source/ObjectViewer/ProgramS.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Windows.Forms;
using LibRender2.Menu;
@@ -28,7 +27,7 @@ internal static class Program {
internal static FileSystem FileSystem = null;
// members
- internal static HashSet Files = new HashSet();
+ internal static List Files = new List();
/// Last time the objects were reloaded (UTC).
internal static DateTime LastReloadTime = DateTime.UtcNow;
/// The number of failed auto-reloads
@@ -162,8 +161,7 @@ internal static void Main(string[] args)
if (filesToLoad.Count != 0)
{
- Files.Clear();
- Files.UnionWith(filesToLoad);
+ Files = filesToLoad;
}
}
@@ -257,10 +255,6 @@ internal static void MouseEvent(object sender, MouseButtonEventArgs e)
internal static void DragFile(object sender, FileDropEventArgs e)
{
- if (Files.Contains(e.FileName))
- {
- return;
- }
Files.Add(System.IO.Path.GetFullPath(e.FileName));
// reset
LightingRelative = -1.0;
@@ -345,13 +339,13 @@ internal static void RefreshObjects(bool autoReload = false)
Renderer.Reset();
Game.Reset();
formTrain.Instance?.DisableUI();
- foreach (string currentFile in Files)
- {
+ for (int i = 0; i < Files.Count; i++)
+ {
try
{
- if(currentFile.EndsWith(".dat", StringComparison.InvariantCultureIgnoreCase) || currentFile.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase) || currentFile.EndsWith(".cfg", StringComparison.InvariantCultureIgnoreCase) || currentFile.EndsWith(".con", StringComparison.InvariantCultureIgnoreCase))
+ if(Files[i].EndsWith(".dat", StringComparison.InvariantCultureIgnoreCase) || Files[i].EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase) || Files[i].EndsWith(".cfg", StringComparison.InvariantCultureIgnoreCase) || Files[i].EndsWith(".con", StringComparison.InvariantCultureIgnoreCase))
{
- string currentTrain = currentFile;
+ string currentTrain = Files[i];
if (currentTrain.EndsWith("extensions.cfg", StringComparison.InvariantCultureIgnoreCase))
{
currentTrain = System.IO.Path.GetDirectoryName(currentTrain);
@@ -393,12 +387,12 @@ internal static void RefreshObjects(bool autoReload = false)
else
{
//As we now attempt to load the train as a whole, the most likely outcome is that the train.dat file is MIA
- Interface.AddMessage(MessageType.Critical, false, "No plugin found capable of loading file " + currentFile + ".");
+ Interface.AddMessage(MessageType.Critical, false, "No plugin found capable of loading file " + Files[i] + ".");
}
}
else
{
- if (CurrentHost.LoadObject(currentFile, Encoding.UTF8, out UnifiedObject o))
+ if (CurrentHost.LoadObject(Files[i], Encoding.UTF8, out UnifiedObject o))
{
o.CreateObject(Vector3.Zero, new ObjectCreationParameters());
}
@@ -414,11 +408,11 @@ internal static void RefreshObjects(bool autoReload = false)
{
// failure counter must be above 5
Interface.CurrentOptions.AutoReloadObjects = false;
- Interface.AddMessage(MessageType.Critical, false, "Stopped automatically re-loading objects due to the Unhandled error (" + ex.Message + ") encountered while processing the file " + currentFile + ".");
+ Interface.AddMessage(MessageType.Critical, false, "Stopped automatically re-loading objects due to the Unhandled error (" + ex.Message + ") encountered while processing the file " + Files[i] + ".");
}
else
{
- Interface.AddMessage(MessageType.Critical, false, "Unhandled error (" + ex.Message + ") encountered while processing the file " + currentFile + ".");
+ Interface.AddMessage(MessageType.Critical, false, "Unhandled error (" + ex.Message + ") encountered while processing the file " + Files[i] + ".");
}
}
@@ -447,7 +441,7 @@ internal static void RefreshObjects(bool autoReload = false)
if (Files.Count == 1)
{
- Renderer.GameWindow.Title = "Object Viewer - " + Path.GetFileName(Files.ToList()[0]);
+ Renderer.GameWindow.Title = "Object Viewer - " + Path.GetFileName(Files[0]);
}
else
{
@@ -466,18 +460,18 @@ internal static void CheckFileChanges(double timeElapsed)
}
reloadCheckTimer = 0.0;
- foreach (string currentFile in Files)
+ for (int i = 0; i < Files.Count; i++)
{
- try
+ try
{
- DateTime time = System.IO.File.GetLastWriteTimeUtc(currentFile);
+ DateTime time = System.IO.File.GetLastWriteTimeUtc(Files[i]);
if ((DateTime.Now - time).TotalSeconds < 5 || time.Year == 1601)
{
// file is held open for constant write (within last 5s)
// file no longer exists (returns 01/01/1601)
continue;
}
- if (System.IO.File.GetLastWriteTimeUtc(currentFile) > LastReloadTime)
+ if (System.IO.File.GetLastWriteTimeUtc(Files[i]) > LastReloadTime)
{
RefreshObjects();
return;
@@ -628,7 +622,7 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e)
case Key.Delete:
LightingRelative = -1.0;
Game.Reset();
- Files.Clear();
+ Files = new List();
LastReloadTime = DateTime.UtcNow;
NearestTrain.UpdateSpecs();
Renderer.ApplyBackgroundColor();
diff --git a/source/ObjectViewer/app.config b/source/ObjectViewer/app.config
index 8d045bfe8d..9706ed099b 100644
--- a/source/ObjectViewer/app.config
+++ b/source/ObjectViewer/app.config
@@ -16,10 +16,6 @@
-
-
-
-
diff --git a/source/OpenBVE/Audio/Sounds.Update.cs b/source/OpenBVE/Audio/Sounds.Update.cs
index 894c8987be..ffe7a16c74 100644
--- a/source/OpenBVE/Audio/Sounds.Update.cs
+++ b/source/OpenBVE/Audio/Sounds.Update.cs
@@ -37,7 +37,7 @@ protected override void UpdateInverseModel(double timeElapsed)
}
AL.Listener(ALListener3f.Position, 0.0f, 0.0f, 0.0f);
AL.Listener(ALListener3f.Velocity, (float)listenerVelocity.X, (float)listenerVelocity.Y, (float)listenerVelocity.Z);
- float[] Orientation = {(float) listenerOrientation.Z.X, (float) listenerOrientation.Z.Y, (float) listenerOrientation.Z.Z,-(float) listenerOrientation.Y.X, -(float) listenerOrientation.Y.Y, -(float) listenerOrientation.Y.Z};
+ var Orientation = new[]{(float) listenerOrientation.Z.X, (float) listenerOrientation.Z.Y, (float) listenerOrientation.Z.Z,-(float) listenerOrientation.Y.X, -(float) listenerOrientation.Y.Y, -(float) listenerOrientation.Y.Z};
AL.Listener(ALListenerfv.Orientation, ref Orientation);
/*
* Set up the atmospheric attributes.
@@ -120,7 +120,7 @@ protected override void UpdateInverseModel(double timeElapsed)
* */
if (Sources[i].State == SoundSourceState.Playing) {
AL.GetSource(Sources[i].OpenAlSourceName, ALGetSourcei.SourceState, out int state);
- if (state != (int)ALSourceState.Initial && state != (int)ALSourceState.Playing) {
+ if (state != (int)ALSourceState.Initial & state != (int)ALSourceState.Playing) {
/*
* The sound is not playing any longer.
* Remove it from the list of sound sources.
@@ -142,11 +142,11 @@ protected override void UpdateInverseModel(double timeElapsed)
switch (Sources[i].Type)
{
case SoundType.TrainCar:
- AbstractCar Car = (AbstractCar)Sources[i].Parent;
+ var Car = (AbstractCar)Sources[i].Parent;
Car.CreateWorldCoordinates(Sources[i].Position, out position, out _);
break;
case SoundType.AnimatedObject:
- WorldSound WorldSound = (WorldSound)Sources[i].Parent;
+ var WorldSound = (WorldSound)Sources[i].Parent;
position = WorldSound.Follower.WorldPosition + WorldSound.Position;
break;
default:
diff --git a/source/OpenBVE/Game/AI/AI.PreTrain.cs b/source/OpenBVE/Game/AI/AI.PreTrain.cs
index 71e3c83055..f8dc5a8061 100644
--- a/source/OpenBVE/Game/AI/AI.PreTrain.cs
+++ b/source/OpenBVE/Game/AI/AI.PreTrain.cs
@@ -32,7 +32,7 @@ public override void Trigger(double timeElapsed)
double bp = double.MinValue, bt = double.MinValue;
for (int i = 0; i < Program.CurrentRoute.BogusPreTrainInstructions.Length; i++)
{
- if (Program.CurrentRoute.BogusPreTrainInstructions[i].Time < Program.CurrentRoute.SecondsSinceMidnight || at == double.MaxValue)
+ if (Program.CurrentRoute.BogusPreTrainInstructions[i].Time < Program.CurrentRoute.SecondsSinceMidnight | at == double.MaxValue)
{
at = Program.CurrentRoute.BogusPreTrainInstructions[i].Time;
ap = Program.CurrentRoute.BogusPreTrainInstructions[i].TrackPosition;
@@ -40,13 +40,13 @@ public override void Trigger(double timeElapsed)
}
for (int i = Program.CurrentRoute.BogusPreTrainInstructions.Length - 1; i >= 0; i--)
{
- if (Program.CurrentRoute.BogusPreTrainInstructions[i].Time > at || bt == double.MinValue)
+ if (Program.CurrentRoute.BogusPreTrainInstructions[i].Time > at | bt == double.MinValue)
{
bt = Program.CurrentRoute.BogusPreTrainInstructions[i].Time;
bp = Program.CurrentRoute.BogusPreTrainInstructions[i].TrackPosition;
}
}
- if (at != double.MaxValue && bt != double.MinValue && Program.CurrentRoute.SecondsSinceMidnight <= Program.CurrentRoute.BogusPreTrainInstructions[Program.CurrentRoute.BogusPreTrainInstructions.Length - 1].Time)
+ if (at != double.MaxValue & bt != double.MinValue & Program.CurrentRoute.SecondsSinceMidnight <= Program.CurrentRoute.BogusPreTrainInstructions[Program.CurrentRoute.BogusPreTrainInstructions.Length - 1].Time)
{
double r = bt - at;
if (r > 0.0)
diff --git a/source/OpenBVE/Game/AI/AI.SimpleHuman.cs b/source/OpenBVE/Game/AI/AI.SimpleHuman.cs
index 285cfd51ab..23849af9e1 100644
--- a/source/OpenBVE/Game/AI/AI.SimpleHuman.cs
+++ b/source/OpenBVE/Game/AI/AI.SimpleHuman.cs
@@ -822,14 +822,10 @@ private void LookAheadForwards()
if (elim == 0.0)
{
double redSignalStopDistance;
- if (Train.Station >= 0 & Train.StationState == TrainStopState.Completed)
+ if (Train.Station >= 0 & Train.StationState == TrainStopState.Completed & dist < 120.0)
{
- redSignalStopDistance = dist > 120 ? 35 : 25;
- if (dist <= redSignalStopDistance)
- {
- // as otherwise the AI will get stuck
- redSignalStopDistance = dist - 1;
- }
+ dist = 1.0;
+ redSignalStopDistance = 25.0;
}
else if (Train.Station >= 0 & Train.StationState == TrainStopState.Pending | stopDistance < dist)
{
@@ -1141,14 +1137,10 @@ private void LookAheadBackwards()
if (elim == 0.0)
{
double redSignalStopDistance;
- if (Train.Station >= 0 & Train.StationState == TrainStopState.Completed)
+ if (Train.Station >= 0 & Train.StationState == TrainStopState.Completed & dist < 120.0)
{
- redSignalStopDistance = dist > 120 ? 35 : 25;
- if (dist <= redSignalStopDistance)
- {
- // as otherwise the AI will get stuck
- redSignalStopDistance = dist - 1;
- }
+ dist = 1.0;
+ redSignalStopDistance = 25.0;
}
else if (Train.Station >= 0 & Train.StationState == TrainStopState.Pending | stopDistance < dist)
{
@@ -1390,7 +1382,7 @@ private void LookAheadBackwards()
}
}
- /// The timer until the doors may be opened
+ /// The timer unti the doors may be opened
private double doorWaitingTimer = 2.0;
/// Controls the AI operating the wipers
private double wiperTimer;
diff --git a/source/OpenBVE/Game/Game.cs b/source/OpenBVE/Game/Game.cs
index 51212cb446..1b10e7dd0f 100644
--- a/source/OpenBVE/Game/Game.cs
+++ b/source/OpenBVE/Game/Game.cs
@@ -93,50 +93,48 @@ internal static void UpdateBlackBox() {
BlackBoxNextUpdate = Program.CurrentRoute.SecondsSinceMidnight + 1.0;
}
}
- internal static void AddBlackBoxEntry()
- {
- if (!Interface.CurrentOptions.BlackBox)
- {
- return;
- }
- BlackBoxEntry newEntry = new BlackBoxEntry();
- newEntry.Time = Program.CurrentRoute.SecondsSinceMidnight;
- newEntry.Position = TrainManager.PlayerTrain.Cars[0].TrackPosition;
- newEntry.Speed = (float)TrainManager.PlayerTrain.CurrentSpeed;
- newEntry.Acceleration = (float)TrainManager.PlayerTrain.Specs.CurrentAverageAcceleration;
- newEntry.ReverserDriver = (short)TrainManager.PlayerTrain.Handles.Reverser.Driver;
- newEntry.ReverserSafety = (short)TrainManager.PlayerTrain.Handles.Reverser.Actual;
- newEntry.PowerDriver = (BlackBoxPower)TrainManager.PlayerTrain.Handles.Power.Driver;
- newEntry.PowerSafety = (BlackBoxPower)TrainManager.PlayerTrain.Handles.Power.Safety;
- if (TrainManager.PlayerTrain.Handles.EmergencyBrake.Driver) {
- newEntry.BrakeDriver = BlackBoxBrake.Emergency;
- } else if (TrainManager.PlayerTrain.Handles.HoldBrake.Driver) {
- newEntry.BrakeDriver = BlackBoxBrake.HoldBrake;
- } else if (TrainManager.PlayerTrain.Handles.Brake is AirBrakeHandle) {
- switch ((AirBrakeHandleState)TrainManager.PlayerTrain.Handles.Brake.Driver) {
- case AirBrakeHandleState.Release: newEntry.BrakeDriver = BlackBoxBrake.Release; break;
- case AirBrakeHandleState.Lap: newEntry.BrakeDriver = BlackBoxBrake.Lap; break;
- case AirBrakeHandleState.Service: newEntry.BrakeDriver = BlackBoxBrake.Service; break;
- default: newEntry.BrakeDriver = BlackBoxBrake.Emergency; break;
+ internal static void AddBlackBoxEntry() {
+ if (Interface.CurrentOptions.BlackBox) {
+
+ BlackBoxEntry newEntry = new BlackBoxEntry();
+ newEntry.Time = Program.CurrentRoute.SecondsSinceMidnight;
+ newEntry.Position = TrainManager.PlayerTrain.Cars[0].TrackPosition;
+ newEntry.Speed = (float)TrainManager.PlayerTrain.CurrentSpeed;
+ newEntry.Acceleration = (float)TrainManager.PlayerTrain.Specs.CurrentAverageAcceleration;
+ newEntry.ReverserDriver = (short)TrainManager.PlayerTrain.Handles.Reverser.Driver;
+ newEntry.ReverserSafety = (short)TrainManager.PlayerTrain.Handles.Reverser.Actual;
+ newEntry.PowerDriver = (BlackBoxPower)TrainManager.PlayerTrain.Handles.Power.Driver;
+ newEntry.PowerSafety = (BlackBoxPower)TrainManager.PlayerTrain.Handles.Power.Safety;
+ if (TrainManager.PlayerTrain.Handles.EmergencyBrake.Driver) {
+ newEntry.BrakeDriver = BlackBoxBrake.Emergency;
+ } else if (TrainManager.PlayerTrain.Handles.HoldBrake.Driver) {
+ newEntry.BrakeDriver = BlackBoxBrake.HoldBrake;
+ } else if (TrainManager.PlayerTrain.Handles.Brake is AirBrakeHandle) {
+ switch ((AirBrakeHandleState)TrainManager.PlayerTrain.Handles.Brake.Driver) {
+ case AirBrakeHandleState.Release: newEntry.BrakeDriver = BlackBoxBrake.Release; break;
+ case AirBrakeHandleState.Lap: newEntry.BrakeDriver = BlackBoxBrake.Lap; break;
+ case AirBrakeHandleState.Service: newEntry.BrakeDriver = BlackBoxBrake.Service; break;
+ default: newEntry.BrakeDriver = BlackBoxBrake.Emergency; break;
+ }
+ } else {
+ newEntry.BrakeDriver = (BlackBoxBrake)TrainManager.PlayerTrain.Handles.Brake.Driver;
}
- } else {
- newEntry.BrakeDriver = (BlackBoxBrake)TrainManager.PlayerTrain.Handles.Brake.Driver;
- }
- if (TrainManager.PlayerTrain.Handles.EmergencyBrake.Safety) {
- newEntry.BrakeSafety = BlackBoxBrake.Emergency;
- } else if (TrainManager.PlayerTrain.Handles.HoldBrake.Actual) {
- newEntry.BrakeSafety = BlackBoxBrake.HoldBrake;
- } else if (TrainManager.PlayerTrain.Handles.Brake is AirBrakeHandle) {
- switch ((AirBrakeHandleState)TrainManager.PlayerTrain.Handles.Brake.Safety) {
- case AirBrakeHandleState.Release: newEntry.BrakeSafety = BlackBoxBrake.Release; break;
- case AirBrakeHandleState.Lap: newEntry.BrakeSafety = BlackBoxBrake.Lap; break;
- case AirBrakeHandleState.Service: newEntry.BrakeSafety = BlackBoxBrake.Service; break;
- default: newEntry.BrakeSafety = BlackBoxBrake.Emergency; break;
+ if (TrainManager.PlayerTrain.Handles.EmergencyBrake.Safety) {
+ newEntry.BrakeSafety = BlackBoxBrake.Emergency;
+ } else if (TrainManager.PlayerTrain.Handles.HoldBrake.Actual) {
+ newEntry.BrakeSafety = BlackBoxBrake.HoldBrake;
+ } else if (TrainManager.PlayerTrain.Handles.Brake is AirBrakeHandle) {
+ switch ((AirBrakeHandleState)TrainManager.PlayerTrain.Handles.Brake.Safety) {
+ case AirBrakeHandleState.Release: newEntry.BrakeSafety = BlackBoxBrake.Release; break;
+ case AirBrakeHandleState.Lap: newEntry.BrakeSafety = BlackBoxBrake.Lap; break;
+ case AirBrakeHandleState.Service: newEntry.BrakeSafety = BlackBoxBrake.Service; break;
+ default: newEntry.BrakeSafety = BlackBoxBrake.Emergency; break;
+ }
+ } else {
+ newEntry.BrakeSafety = (BlackBoxBrake)TrainManager.PlayerTrain.Handles.Brake.Safety;
}
- } else {
- newEntry.BrakeSafety = (BlackBoxBrake)TrainManager.PlayerTrain.Handles.Brake.Safety;
+ BlackBoxEntries.Add(newEntry);
}
- BlackBoxEntries.Add(newEntry);
}
}
}
diff --git a/source/OpenBVE/Game/Menu/Menu.Route.cs b/source/OpenBVE/Game/Menu/Menu.Route.cs
index 71bb4c68a9..6188e6f95e 100644
--- a/source/OpenBVE/Game/Menu/Menu.Route.cs
+++ b/source/OpenBVE/Game/Menu/Menu.Route.cs
@@ -184,7 +184,7 @@ private static void routeWorkerThread_doWork(object sender, DoWorkEventArgs e)
{
// ReSharper disable once RedundantCast
object Route = (object)Program.CurrentRoute; // must cast to allow us to use the ref keyword correctly.
- string RailwayFolder = Program.FileSystem.GetRailwayFolder(currentFile, System.Windows.Forms.Application.StartupPath);
+ string RailwayFolder = Loading.GetRailwayFolder(currentFile);
string ObjectFolder = Path.CombineDirectory(RailwayFolder, "Object");
string SoundFolder = Path.CombineDirectory(RailwayFolder, "Sound");
if (Program.CurrentHost.Plugins[i].Route.LoadRoute(currentFile, RouteEncoding, null, ObjectFolder, SoundFolder, true, ref Route))
diff --git a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs
index c627725e4c..4fad18b4d8 100644
--- a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs
+++ b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs
@@ -198,7 +198,7 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max
}
Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.File, 0);
string ext = System.IO.Path.GetExtension(fileName);
- if (!iconCache.TryGetValue(ext, out Items[totalEntries].Icon))
+ if (!iconCache.ContainsKey(ext))
{
// As some people have used arbitrary extensions for packages, let's show all files
// Try and pull out the default icon from the cache for something a little nicer looking
@@ -218,13 +218,17 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max
}
}
+ else
+ {
+ Items[totalEntries].Icon = iconCache[ext];
+ }
totalEntries++;
}
Array.Resize(ref Items, totalEntries);
Align = TextAlignment.TopLeft;
break;
case MenuType.Options:
- Items = new MenuEntry[12];
+ Items = new MenuEntry[11];
Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"panel","options"}));
Items[1] = new MenuOption(menu, OptionType.ScreenResolution, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","resolution"}), Program.Renderer.Screen.AvailableResolutions.ToArray());
Items[2] = new MenuOption(menu, OptionType.FullScreen, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","display_mode_fullscreen"}), new[] { "true", "false" });
@@ -250,8 +254,7 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max
Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "shadows_resolution_high" }),
Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "shadows_resolution_ultra" })
});
- Items[10] = new MenuOption(menu, OptionType.ShadowFilterCascades, "Per-cascade culling", new[] { "true", "false" });
- Items[11] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","back"}), MenuTag.MenuBack, 0);
+ Items[10] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","back"}), MenuTag.MenuBack, 0);
Align = TextAlignment.TopLeft;
break;
case MenuType.RouteList:
diff --git a/source/OpenBVE/Game/Menu/Menu.cs b/source/OpenBVE/Game/Menu/Menu.cs
index 86fe5527fa..c82aaee951 100644
--- a/source/OpenBVE/Game/Menu/Menu.cs
+++ b/source/OpenBVE/Game/Menu/Menu.cs
@@ -898,6 +898,8 @@ public override void Draw(double RealTimeElapsed)
nextStepButton.Draw();
//Choose Train and Game start button
+ bool allowNextPhase =
+
nextStepButton.Enabled = (menu.Type == MenuType.RouteList && RoutefileState == RouteState.Processed) || (menu.Type == MenuType.TrainList && Interface.CurrentOptions.TrainFolder != string.Empty);
break;
}
diff --git a/source/OpenBVE/Game/MessageManager.TextualMessages.cs b/source/OpenBVE/Game/MessageManager.TextualMessages.cs
index 304e4dd6ed..08a983d12d 100644
--- a/source/OpenBVE/Game/MessageManager.TextualMessages.cs
+++ b/source/OpenBVE/Game/MessageManager.TextualMessages.cs
@@ -118,7 +118,7 @@ public override void Update(double timeElapsed)
case MessageDependency.StationDeparture:
{
int j = TrainManager.PlayerTrain.Station;
- if (j >= 0 && TrainManager.PlayerTrain.StationState != TrainStopState.Completed)
+ if (j >= 0 & TrainManager.PlayerTrain.StationState != TrainStopState.Completed)
{
double d = TrainManager.PlayerTrain.StationDepartureTime - Program.CurrentRoute.SecondsSinceMidnight + 1.0;
if (d < 0.0) d = 0.0;
@@ -158,7 +158,7 @@ public override void Update(double timeElapsed)
}
//Remove the message if it has completely faded out
//NOTE: The fadeout is done in the renderer itself...
- if (Timeout <= 0 && RendererAlpha == 0.0)
+ if (Timeout <= 0 & RendererAlpha == 0.0)
{
QueueForRemoval = true;
}
diff --git a/source/OpenBVE/Game/MessageManager.cs b/source/OpenBVE/Game/MessageManager.cs
index e9e53c5393..1b1f804e12 100644
--- a/source/OpenBVE/Game/MessageManager.cs
+++ b/source/OpenBVE/Game/MessageManager.cs
@@ -71,7 +71,7 @@ internal static void AddMessage(AbstractMessage message)
ImageMessages.Add(message);
return;
}
- GameMessage m = message as GameMessage;
+ var m = message as GameMessage;
if (m != null && m.Depencency == MessageDependency.PassedRedSignal)
{
for (int i = TextualMessages.Count -1; i >= 0; i--)
diff --git a/source/OpenBVE/Game/ObjectManager/AnimatedObjects/FunctionScripts.cs b/source/OpenBVE/Game/ObjectManager/AnimatedObjects/FunctionScripts.cs
index 3710a10d0f..c4f2d0f506 100644
--- a/source/OpenBVE/Game/ObjectManager/AnimatedObjects/FunctionScripts.cs
+++ b/source/OpenBVE/Game/ObjectManager/AnimatedObjects/FunctionScripts.cs
@@ -267,16 +267,6 @@ internal static void ExecuteFunctionScript(FunctionScript Function, TrainBase Tr
Function.Stack[s] = 1;
}
s++; break;
- case Instructions.CameraCar:
- if (IsPartOfTrain && Train != null)
- {
- Function.Stack[s] = Train.CameraCar;
- }
- else
- {
- Function.Stack[s] = 0.0;
- }
- s++; break;
// train
case Instructions.PlayerTrain:
if (IsPartOfTrain && Train != null)
diff --git a/source/OpenBVE/Game/RouteInfoOverlay.cs b/source/OpenBVE/Game/RouteInfoOverlay.cs
index b3c98246c8..ff49a81299 100644
--- a/source/OpenBVE/Game/RouteInfoOverlay.cs
+++ b/source/OpenBVE/Game/RouteInfoOverlay.cs
@@ -88,8 +88,9 @@ public void Show()
case OverlayState.Gradient:
Program.Renderer.Rectangle.Draw(gradientImage, origin, gradientSize);
// get current train position in track
+ int trackPos = (int)(TrainManager.PlayerTrain.FrontCarTrackPosition);
// convert to gradient profile offset
- Pos.X = gradientSize.Y * (TrainManager.PlayerTrain.FrontCarTrackPosition - Program.CurrentRoute.Information.GradientMinTrack) /
+ Pos.X = gradientSize.Y * (trackPos - Program.CurrentRoute.Information.GradientMinTrack) /
(Program.CurrentRoute.Information.GradientMaxTrack - Program.CurrentRoute.Information.GradientMinTrack);
// draw a vertical bar at the current train position
Program.Renderer.Rectangle.Draw(null, new Vector2(Pos.X, gradientSize.Y / 2),
@@ -104,26 +105,21 @@ private void SetState(OverlayState newState)
{
switch (newState)
{
- case OverlayState.Map:
- if (mapImage == null)
- {
- mapImage = new Texture(Program.CurrentRoute.Information.RouteMap);
- mapSize = new Vector2(Program.CurrentRoute.Information.RouteMap.Width,
- Program.CurrentRoute.Information.RouteMap.Height);
- }
-
- break;
- case OverlayState.Gradient:
- if (gradientImage == null)
- {
- gradientImage = new Texture(Program.CurrentRoute.Information.GradientProfile);
- gradientSize = new Vector2(Program.CurrentRoute.Information.GradientProfile.Width,
- Program.CurrentRoute.Information.GradientProfile.Height);
- }
-
- break;
+ case OverlayState.Map:
+ if (mapImage == null)
+ {
+ mapImage = new Texture(Program.CurrentRoute.Information.RouteMap);
+ mapSize = new Vector2(Program.CurrentRoute.Information.RouteMap.Width, Program.CurrentRoute.Information.RouteMap.Height);
+ }
+ break;
+ case OverlayState.Gradient:
+ if (gradientImage == null)
+ {
+ gradientImage = new Texture(Program.CurrentRoute.Information.GradientProfile);
+ gradientSize = new Vector2(Program.CurrentRoute.Information.GradientProfile.Width, Program.CurrentRoute.Information.GradientProfile.Height);
+ }
+ break;
}
-
currentState = newState;
}
}
diff --git a/source/OpenBVE/Game/Timetable.cs b/source/OpenBVE/Game/Timetable.cs
index e147d8cf8c..0651fa364e 100644
--- a/source/OpenBVE/Game/Timetable.cs
+++ b/source/OpenBVE/Game/Timetable.cs
@@ -222,11 +222,11 @@ internal void RenderData(ref Texture timetableTexture)
}
// prepare timetable
int w = 384, h = 192;
- int xOffset = 0;
- int actualHeight = h;
- float descriptionWidth = 256;
- float descriptionHeight = 16;
- float stationNameWidth = 16;
+ int offsetx = 0;
+ int actualheight = h;
+ float descriptionwidth = 256;
+ float descriptionheight = 16;
+ float stationnamewidth = 16;
for (int k = 0; k < 2; k++)
{
Bitmap b = new Bitmap(w, h);
@@ -234,20 +234,20 @@ internal void RenderData(ref Texture timetableTexture)
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
g.Clear(Color.Transparent);
- g.FillRectangle(Brushes.White, new RectangleF(xOffset, 0, w, actualHeight));
+ g.FillRectangle(Brushes.White, new RectangleF(offsetx, 0, w, actualheight));
Font f = new Font(FontFamily.GenericSansSerif, 13.0f, GraphicsUnit.Pixel);
Font fs = new Font(FontFamily.GenericSansSerif, 11.0f, GraphicsUnit.Pixel);
Font fss = new Font(FontFamily.GenericSansSerif, 9.0f, GraphicsUnit.Pixel);
// draw timetable
string t;
// description
- float x0 = xOffset + 8;
+ float x0 = offsetx + 8;
float y0 = 8;
if (k == 1)
{
t = Program.CurrentRoute.Information.DefaultTimetableDescription;
- g.DrawString(t, f, Brushes.Black, new RectangleF(x0, 6, descriptionWidth, descriptionHeight + 8));
- y0 += descriptionHeight + 2;
+ g.DrawString(t, f, Brushes.Black, new RectangleF(x0, 6, descriptionwidth, descriptionheight + 8));
+ y0 += descriptionheight + 2;
}
// highest speed
@@ -266,7 +266,7 @@ internal void RenderData(ref Texture timetableTexture)
if (x > x1) x1 = x;
}
- g.DrawLine(Pens.LightGray, new PointF(x1 - 2, 4 + descriptionHeight), new PointF(x1 - 2, y0a + 18 * Tracks.Length - 1));
+ g.DrawLine(Pens.LightGray, new PointF(x1 - 2, 4 + descriptionheight), new PointF(x1 - 2, y0a + 18 * Tracks.Length - 1));
// driving time
t = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"timetable","drivingtime"});
s = g.MeasureString(t, fs);
@@ -309,10 +309,10 @@ internal void RenderData(ref Texture timetableTexture)
for (int i = 0; i < Tracks.Length; i++)
{
float y = y0a + 18 * i;
- g.DrawLine(Pens.LightGray, new PointF(xOffset + 4, y - 1), new PointF(x2 - 2, y - 1));
+ g.DrawLine(Pens.LightGray, new PointF(offsetx + 4, y - 1), new PointF(x2 - 2, y - 1));
}
- g.DrawLine(Pens.LightGray, new PointF(x2 - 2, 4 + descriptionHeight), new PointF(x2 - 2, y0a + 18 * Tracks.Length - 1));
+ g.DrawLine(Pens.LightGray, new PointF(x2 - 2, 4 + descriptionheight), new PointF(x2 - 2, y0a + 18 * Tracks.Length - 1));
// station name
float y2 = y0;
t = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"timetable","stationname"});
@@ -324,7 +324,7 @@ internal void RenderData(ref Texture timetableTexture)
float y = y0 + 18 * (i + 1) + 2;
g.DrawLine(Pens.LightGray, new PointF(x2 - 2, y - 1), new PointF(w - 4, y - 1));
t = Stations[i].Name;
- if (Stations[i].NameJapanese && Stations[i].Name.Length > 1)
+ if (Stations[i].NameJapanese & Stations[i].Name.Length > 1)
{
float[] sizes = new float[t.Length];
float totalsize = 0.0f;
@@ -334,7 +334,7 @@ internal void RenderData(ref Texture timetableTexture)
totalsize += sizes[j];
}
- float space = (stationNameWidth - totalsize) / (t.Length - 1);
+ float space = (stationnamewidth - totalsize) / (t.Length - 1);
float x = 0.0f;
for (int j = 0; j < t.Length; j++)
{
@@ -354,10 +354,10 @@ internal void RenderData(ref Texture timetableTexture)
}
}
- g.DrawLine(Pens.LightGray, new PointF(x3 - 2, 4 + descriptionHeight), new PointF(x3 - 2, y0 + 18 * (Stations.Count + 1)));
+ g.DrawLine(Pens.LightGray, new PointF(x3 - 2, 4 + descriptionheight), new PointF(x3 - 2, y0 + 18 * (Stations.Count + 1)));
if (k == 0)
{
- stationNameWidth = x3 - x2 - 6;
+ stationnamewidth = x3 - x2 - 6;
}
// arrival time
@@ -393,7 +393,7 @@ internal void RenderData(ref Texture timetableTexture)
s = g.MeasureString(t, fs);
float x = x3 + s.Width;
- if (Stations[i].Arrival.Minute.Length != 0 && Stations[i].Arrival.Second.Length != 0)
+ if (Stations[i].Arrival.Minute.Length != 0 & Stations[i].Arrival.Second.Length != 0)
{
t = Stations[i].Arrival.Minute + ":" + Stations[i].Arrival.Second;
}
@@ -406,7 +406,7 @@ internal void RenderData(ref Texture timetableTexture)
}
}
- g.DrawLine(Pens.LightGray, new PointF(x4 - 2, 4 + descriptionHeight), new PointF(x4 - 2, y0 + 18 * (Stations.Count + 1)));
+ g.DrawLine(Pens.LightGray, new PointF(x4 - 2, 4 + descriptionheight), new PointF(x4 - 2, y0 + 18 * (Stations.Count + 1)));
// departure time
t = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"timetable","departuretime"});
s = g.MeasureString(t, f);
@@ -429,20 +429,23 @@ internal void RenderData(ref Texture timetableTexture)
}
else
{
- t = "00";
if (Stations[i].Departure.Hour.Length != 0)
{
t = Stations[i].Departure.Hour;
g.DrawString(t, fs, Brushes.Black, x4, y);
}
+ else
+ {
+ t = "00";
+ }
+
s = g.MeasureString(t, fs);
float x = x4 + s.Width;
-
- t = "";
- if (Stations[i].Departure.Minute.Length != 0 && Stations[i].Departure.Second.Length != 0)
+ if (Stations[i].Departure.Minute.Length != 0 & Stations[i].Departure.Second.Length != 0)
{
t = Stations[i].Departure.Minute + ":" + Stations[i].Departure.Second;
}
+ else t = "";
g.DrawString(t, f, Brushes.Black, x, y);
s = g.MeasureString(t, f);
@@ -460,10 +463,10 @@ internal void RenderData(ref Texture timetableTexture)
// border
if (k == 1)
{
- g.DrawLine(Pens.Black, new PointF(xOffset + 4, 4), new PointF(xOffset + 4, y0a + 18 * Tracks.Length - 1));
- g.DrawLine(Pens.Black, new PointF(xOffset + 4, y0a + 18 * Tracks.Length - 1), new PointF(x2 - 2, y0a + 18 * Tracks.Length - 1));
- g.DrawLine(Pens.Black, new PointF(xOffset + 4, 4), new PointF(w - 4, 4));
- g.DrawLine(Pens.Black, new PointF(xOffset + 4, 4 + descriptionHeight), new PointF(w - 4, 4 + descriptionHeight));
+ g.DrawLine(Pens.Black, new PointF(offsetx + 4, 4), new PointF(offsetx + 4, y0a + 18 * Tracks.Length - 1));
+ g.DrawLine(Pens.Black, new PointF(offsetx + 4, y0a + 18 * Tracks.Length - 1), new PointF(x2 - 2, y0a + 18 * Tracks.Length - 1));
+ g.DrawLine(Pens.Black, new PointF(offsetx + 4, 4), new PointF(w - 4, 4));
+ g.DrawLine(Pens.Black, new PointF(offsetx + 4, 4 + descriptionheight), new PointF(w - 4, 4 + descriptionheight));
g.DrawLine(Pens.Black, new PointF(x2 - 2, y0 + 18 * (Stations.Count + 1)), new PointF(w - 4, y0 + 18 * (Stations.Count + 1)));
g.DrawLine(Pens.Black, new PointF(w - 4, 4), new PointF(w - 4, y0 + 18 * (Stations.Count + 1)));
g.DrawLine(Pens.Black, new PointF(x2 - 2, y0a + 18 * Tracks.Length - 1), new PointF(x2 - 2, y0 + 18 * (Stations.Count + 1)));
@@ -477,8 +480,8 @@ internal void RenderData(ref Texture timetableTexture)
{
t = Program.CurrentRoute.Information.DefaultTimetableDescription;
s = g.MeasureString(t, f, w - 16);
- descriptionWidth = s.Width;
- descriptionHeight = s.Height + 2;
+ descriptionwidth = s.Width;
+ descriptionheight = s.Height + 2;
h += (int) Math.Ceiling(s.Height) + 4;
}
f.Dispose();
@@ -489,9 +492,9 @@ internal void RenderData(ref Texture timetableTexture)
{
// measures
int nw = Program.Renderer.TextureManager.RoundUpToPowerOfTwo(w);
- xOffset = nw - w;
+ offsetx = nw - w;
w = nw;
- actualHeight = h;
+ actualheight = h;
h = Program.Renderer.TextureManager.RoundUpToPowerOfTwo(h);
}
else
@@ -540,7 +543,7 @@ internal static void UpdateCustomTimetable(Texture daytime, Texture nighttime) {
if (nighttime != null) {
CurrentCustomTimetableNighttimeTexture = nighttime;
}
- if (CurrentCustomTimetableDaytimeTexture != null || CurrentCustomTimetableNighttimeTexture != null) {
+ if (CurrentCustomTimetableDaytimeTexture != null | CurrentCustomTimetableNighttimeTexture != null) {
CustomTimetableAvailable = true;
} else {
CustomTimetableAvailable = false;
diff --git a/source/OpenBVE/Game/World.cs b/source/OpenBVE/Game/World.cs
index 5262b6f291..373cf3e78c 100644
--- a/source/OpenBVE/Game/World.cs
+++ b/source/OpenBVE/Game/World.cs
@@ -244,7 +244,7 @@ internal static void UpdateAbsoluteCamera(double TimeElapsed = 0.0) {
// cab pitch and yaw
Vector3 d2 = new Vector3(dF);
Vector3 u2 = new Vector3(uF);
- if (TrainManager.PlayerTrain != null && (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead)) {
+ if ((Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) & TrainManager.PlayerTrain != null) {
int c = TrainManager.PlayerTrain.DriverCar;
if (c >= 0) {
if (TrainManager.PlayerTrain.Cars[c].CarSections.ContainsKey(CarSectionType.Interior)) {
@@ -259,12 +259,16 @@ internal static void UpdateAbsoluteCamera(double TimeElapsed = 0.0) {
}
// yaw, pitch, roll
double headYaw = Program.Renderer.Camera.Alignment.Yaw + lookaheadYaw;
- if (TrainManager.PlayerTrain != null && (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead)) {
- headYaw += TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].DriverYaw;
+ if ((Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) & TrainManager.PlayerTrain != null) {
+ if (TrainManager.PlayerTrain.DriverCar >= 0) {
+ headYaw += TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].DriverYaw;
+ }
}
double headPitch = Program.Renderer.Camera.Alignment.Pitch + lookaheadPitch;
if ((Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) & TrainManager.PlayerTrain != null) {
- headPitch += TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].DriverPitch;
+ if (TrainManager.PlayerTrain.DriverCar >= 0) {
+ headPitch += TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].DriverPitch;
+ }
}
double headRoll = Program.Renderer.Camera.Alignment.Roll;
@@ -354,16 +358,6 @@ internal static void UpdateAbsoluteCamera(double TimeElapsed = 0.0) {
Program.Renderer.Camera.AbsoluteDirection = dF;
Program.Renderer.Camera.AbsoluteUp = uF;
Program.Renderer.Camera.AbsoluteSide = sF;
-
- if (Program.Renderer.Camera.ModeTransitionTimer < 1.0)
- {
- double transitionProgress = Program.Renderer.Camera.ModeTransitionTimer;
- var start = Program.Renderer.Camera.ModeTransitionStart;
- Program.Renderer.Camera.AbsolutePosition = Vector3.CosineInterpolate(start.Position, Program.Renderer.Camera.AbsolutePosition, transitionProgress);
- Program.Renderer.Camera.AbsoluteDirection = Vector3.CosineInterpolate(start.Direction, Program.Renderer.Camera.AbsoluteDirection, transitionProgress);
- Program.Renderer.Camera.AbsoluteUp = Vector3.CosineInterpolate(start.Up, Program.Renderer.Camera.AbsoluteUp, transitionProgress);
- Program.Renderer.Camera.AbsoluteSide = Vector3.CosineInterpolate(start.Side, Program.Renderer.Camera.AbsoluteSide, transitionProgress);
- }
}
}
}
diff --git a/source/OpenBVE/Graphics/Screen.cs b/source/OpenBVE/Graphics/Screen.cs
index 9a6d71b3a0..8b4ca67e83 100644
--- a/source/OpenBVE/Graphics/Screen.cs
+++ b/source/OpenBVE/Graphics/Screen.cs
@@ -48,7 +48,7 @@ internal static void Initialize()
GameWindowFlags.Default, GraphicsContextFlags.ForwardCompatible)
{
Visible = true,
- WindowState = WindowState.Fullscreen
+ WindowState = WindowState.Fullscreen,
};
}
else
@@ -57,7 +57,7 @@ internal static void Initialize()
GameWindowFlags.Default)
{
Visible = true,
- WindowState = WindowState.Fullscreen
+ WindowState = WindowState.Fullscreen,
};
}
diff --git a/source/OpenBVE/OpenBve.csproj b/source/OpenBVE/OpenBve.csproj
index 33f74fcc7e..17e81a06ec 100644
--- a/source/OpenBVE/OpenBve.csproj
+++ b/source/OpenBVE/OpenBve.csproj
@@ -104,13 +104,10 @@
AnyCPU
7.3
prompt
- Project
- /glmenu=true
+ Project
+ /glmenu=true
-
- ..\..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\netstandard2.0\Microsoft.Bcl.AsyncInterfaces.dll
-
..\..\packages\OpenTK-OpenBVE.1.0.4\lib\net20\OpenTK.dll
@@ -121,8 +118,8 @@
False
..\..\dependencies\PIEHid64Net.dll
-
- ..\..\packages\SharpCompress.0.48.0\lib\netstandard2.0\SharpCompress.dll
+
+ ..\..\packages\SharpCompress.0.32.2\lib\net461\SharpCompress.dll
@@ -139,11 +136,8 @@
..\..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
-
- ..\..\packages\System.Text.Encoding.CodePages.8.0.0\lib\netstandard2.0\System.Text.Encoding.CodePages.dll
-
-
- ..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
+
+ ..\..\packages\System.Text.Encoding.CodePages.6.0.0\lib\net461\System.Text.Encoding.CodePages.dll
..\..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll
diff --git a/source/OpenBVE/Parsers/Script/TrackFollowingObjectParser.cs b/source/OpenBVE/Parsers/Script/TrackFollowingObjectParser.cs
index 3e42a584bd..eb1d2ff4fd 100644
--- a/source/OpenBVE/Parsers/Script/TrackFollowingObjectParser.cs
+++ b/source/OpenBVE/Parsers/Script/TrackFollowingObjectParser.cs
@@ -344,43 +344,37 @@ private static TravelStopData ParseTravelStopBlock(Block 0.0 | doorBoth;
- }
- if (sectionElement.GetValue(TrackFollowingObjectKey.Direction, out string travelDirection))
- {
- int d;
- switch (travelDirection.ToLowerInvariant())
+ if (sectionElement.GetValue(TrackFollowingObjectKey.Direction, out string travelDirection))
{
- case "f":
- d = 1;
- break;
- case "r":
- d = -1;
- break;
- default:
- if (!NumberFormats.TryParseIntVb6(travelDirection, out d) ||
- !Enum.IsDefined(typeof(TravelDirection), d))
- {
- Interface.AddMessage(MessageType.Error, false,
- $"TravelDirection is invalid in {sectionElement.Key} in {sectionElement.FileName}");
+ int d;
+ switch (travelDirection.ToLowerInvariant())
+ {
+ case "f":
d = 1;
- }
+ break;
+ case "r":
+ d = -1;
+ break;
+ default:
+ if (!NumberFormats.TryParseIntVb6(travelDirection, out d) || !Enum.IsDefined(typeof(TravelDirection), d))
+ {
+ Interface.AddMessage(MessageType.Error, false, $"TravelDirection is invalid in {sectionElement.Key} in {sectionElement.FileName}");
+ d = 1;
+ }
+ break;
+ }
- break;
+ travelStopData.Direction = (TravelDirection)d;
}
- travelStopData.Direction = (TravelDirection)d;
+ travelStopData.OpenLeftDoors = doorSide < 0.0 | doorBoth;
+ travelStopData.OpenRightDoors = doorSide > 0.0 | doorBoth;
}
-
-
-
return travelStopData;
}
diff --git a/source/OpenBVE/System/GameWindow.cs b/source/OpenBVE/System/GameWindow.cs
index b87e92bf10..41e931bf0b 100644
--- a/source/OpenBVE/System/GameWindow.cs
+++ b/source/OpenBVE/System/GameWindow.cs
@@ -31,7 +31,6 @@
using OpenTK.Graphics.OpenGL;
using RouteManager2.MessageManager;
using SoundManager;
-using TrainManager.Car;
using TrainManager.Trains;
using Path = System.IO.Path;
using Vector2 = OpenTK.Vector2;
@@ -60,7 +59,7 @@ public OpenBVEGame(int width, int height, GraphicsMode currentGraphicsMode, Game
}
try
{
- string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+ var assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
Icon ico = new Icon(OpenBveApi.Path.CombineFile(OpenBveApi.Path.CombineDirectory(assemblyFolder, "Data"), "icon.ico"));
Icon = ico;
}
@@ -166,64 +165,10 @@ protected override void OnRenderFrame(FrameEventArgs e)
//We need to update the camera position in the render sequence
//Not doing this means that the camera doesn't move
// update in one piece
- CameraViewMode cameraMode = Program.Renderer.Camera.CurrentMode;
- if (cameraMode == CameraViewMode.Interior || cameraMode == CameraViewMode.InteriorLookAhead || cameraMode == CameraViewMode.Exterior)
+ if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead | Program.Renderer.Camera.CurrentMode == CameraViewMode.Exterior)
{
- CameraProperties cameraProperties = Program.Renderer.Camera;
- TrackFollower trackFollower = Program.Renderer.CameraTrackFollower;
-
- if (cameraProperties.IsTransitioning) cameraProperties.CameraCarTransitionTimer += RealTimeElapsed;
- if (cameraProperties.ModeTransitionTimer < 1.0) cameraProperties.ModeTransitionTimer += RealTimeElapsed / Interface.CurrentOptions.CameraTransitionSpeed;
- double carTransitionProgress = Math.Min(1.0, cameraProperties.CameraCarTransitionTimer / Interface.CurrentOptions.CameraTransitionSpeed);
- if ((cameraMode == CameraViewMode.Exterior && Interface.CurrentOptions.CameraExteriorTransition == false) || (cameraMode != CameraViewMode.Exterior && Interface.CurrentOptions.CameraInteriorTransition == false) || cameraMode == CameraViewMode.Interior)
- {
- // disabled transition
- carTransitionProgress = 1.0;
- cameraProperties.ModeTransitionTimer = 1.0;
- }
- if (carTransitionProgress >= 1.0)
- {
- cameraProperties.IsTransitioning = false;
- if (cameraProperties.TargetCameraCar != -1)
- {
- cameraProperties.PreviousCameraCar = TrainManager.PlayerTrain.CameraCar;
- TrainManager.PlayerTrain.CameraCar = cameraProperties.TargetCameraCar;
- cameraProperties.TargetCameraCar = -1;
- cameraProperties.IsTransitioning = true;
- cameraProperties.CameraCarTransitionTimer = 0.0;
- carTransitionProgress = 0.0;
- }
- }
-
- CarBase previousCar = (cameraProperties.IsTransitioning && cameraProperties.PreviousCameraCar != -1) ? TrainManager.PlayerTrain.Cars[cameraProperties.PreviousCameraCar] : null;
//Update the in-car camera based upon the current driver car (Cabview or passenger view)
- TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.CameraCar].UpdateCamera(previousCar, carTransitionProgress);
-
- if (cameraProperties.ModeTransitionTimer < 1.0)
- {
- double modeTransitionLinear = Math.Min(1.0, cameraProperties.ModeTransitionTimer);
- double modeTransitionCosine = (1.0 - Math.Cos(modeTransitionLinear * Math.PI)) / 2.0;
- var startAnchor = cameraProperties.ModeTransitionStart;
-
- trackFollower.WorldPosition = OpenBveApi.Math.Vector3.CosineInterpolate(startAnchor.Position, trackFollower.WorldPosition, modeTransitionLinear);
- trackFollower.WorldDirection = OpenBveApi.Math.Vector3.CosineInterpolate(startAnchor.Direction, trackFollower.WorldDirection, modeTransitionLinear);
- trackFollower.WorldDirection.Normalize();
- trackFollower.WorldUp = OpenBveApi.Math.Vector3.CosineInterpolate(startAnchor.Up, trackFollower.WorldUp, modeTransitionLinear);
- trackFollower.WorldUp.Normalize();
- trackFollower.WorldSide = OpenBveApi.Math.Vector3.CosineInterpolate(startAnchor.Side, trackFollower.WorldSide, modeTransitionLinear);
- trackFollower.WorldSide.Normalize();
- trackFollower.UpdateAbsolute(
- startAnchor.TrackPosition + (trackFollower.TrackPosition - startAnchor.TrackPosition) * modeTransitionCosine,
- false,
- false);
-
- // Smoothly decay alignment back to zero
- cameraProperties.AlignmentDirection.Yaw = startAnchor.Alignment.Yaw * (1.0 - modeTransitionCosine);
- cameraProperties.AlignmentDirection.Pitch = startAnchor.Alignment.Pitch * (1.0 - modeTransitionCosine);
- cameraProperties.AlignmentDirection.Roll = startAnchor.Alignment.Roll * (1.0 - modeTransitionCosine);
- cameraProperties.AlignmentDirection.Position = startAnchor.Alignment.Position * (1.0 - modeTransitionCosine);
- cameraProperties.AlignmentDirection.Zoom = startAnchor.Alignment.Zoom + (0.0 - startAnchor.Alignment.Zoom) * modeTransitionCosine;
- }
+ TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.CameraCar].UpdateCamera();
}
if (Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.NotAvailable || Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.Restricted3D)
@@ -447,7 +392,7 @@ protected override void OnLoad(EventArgs e)
if (w == Interface.CurrentOptions.WindowWidth && h == Interface.CurrentOptions.WindowHeight)
{
// If we are not in full-screen, but height and width are equal to resolution, hide taskbar
- // e.g. Borderless windowed full-screen
+ // e.g. Borderless windowed fulllscreen
int hwnd = FindWindow("Shell_TrayWnd","");
ShowWindow(hwnd,0);
int hstart = FindWindowEx(GetDesktopWindow(), 0, "button", 0);
diff --git a/source/OpenBVE/System/Input/Keyboard.cs b/source/OpenBVE/System/Input/Keyboard.cs
index 2a0de29337..119ab79a5b 100644
--- a/source/OpenBVE/System/Input/Keyboard.cs
+++ b/source/OpenBVE/System/Input/Keyboard.cs
@@ -47,7 +47,7 @@ internal static void KeyDownEvent(object sender, KeyboardKeyEventArgs e)
//Compare the current and previous keyboard states
//Only process if they are different
if (!Enum.IsDefined(typeof(OpenBveApi.Input.Key), Interface.CurrentControls[i].Key)) continue;
- if ((OpenBveApi.Input.Key)e.Key == Interface.CurrentControls[i].Key && Interface.CurrentControls[i].Modifier == CurrentKeyboardModifier)
+ if ((OpenBveApi.Input.Key)e.Key == Interface.CurrentControls[i].Key & Interface.CurrentControls[i].Modifier == CurrentKeyboardModifier)
{
Interface.CurrentControls[i].AnalogState = 1.0;
@@ -114,7 +114,7 @@ internal static void KeyUpEvent(object sender, KeyboardKeyEventArgs e)
//Compare the current and previous keyboard states
//Only process if they are different
if (!Enum.IsDefined(typeof(OpenBveApi.Input.Key), Interface.CurrentControls[i].Key)) continue;
- if ((OpenBveApi.Input.Key)e.Key == Interface.CurrentControls[i].Key && Interface.CurrentControls[i].AnalogState == 1.0 && Interface.CurrentControls[i].DigitalState > DigitalControlState.Released)
+ if ((OpenBveApi.Input.Key)e.Key == Interface.CurrentControls[i].Key & Interface.CurrentControls[i].AnalogState == 1.0 & Interface.CurrentControls[i].DigitalState > DigitalControlState.Released)
{
Interface.CurrentControls[i].AnalogState = 0.0;
Interface.CurrentControls[i].DigitalState = DigitalControlState.Released;
diff --git a/source/OpenBVE/System/Input/ProcessControls.Digital.cs b/source/OpenBVE/System/Input/ProcessControls.Digital.cs
index b4e00ddaeb..e1a410627c 100644
--- a/source/OpenBVE/System/Input/ProcessControls.Digital.cs
+++ b/source/OpenBVE/System/Input/ProcessControls.Digital.cs
@@ -61,9 +61,9 @@ private static void ProcessDigitalControl(double TimeElapsed, ref Control Contro
Game.Menu.PushMenu(MenuType.Quit);
break;
case Translations.Command.CameraInterior:
- // camera: interior (Handle camera transition from exterior mode to cab mode)
+ // camera: interior
SaveCameraSettings();
- if (Program.Renderer.Camera.CurrentMode != CameraViewMode.InteriorLookAhead && Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.NotAvailable)
+ if (Program.Renderer.Camera.CurrentMode != CameraViewMode.InteriorLookAhead & Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.NotAvailable)
{
MessageManager.AddMessage(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"notification","interior_lookahead"}),
MessageDependency.CameraView, GameMode.Expert,
@@ -77,35 +77,13 @@ private static void ProcessDigitalControl(double TimeElapsed, ref Control Contro
MessageColor.White, 2, null);
}
- bool hasCab = TrainManager.PlayerTrain.Cars[0].InteriorCamera != null || TrainManager.PlayerTrain.Cars[0].HasInteriorView;
- bool isAtCabCar = TrainManager.PlayerTrain.CameraCar == 0 || TrainManager.PlayerTrain.CameraCar == TrainManager.PlayerTrain.DriverCar;
- bool transition = false;
- // Transition only if switching from Exterior mode and at the head of the train (Car 0 or Driver Car)
- if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Exterior && isAtCabCar && hasCab && Interface.CurrentOptions.CameraInteriorTransition)
- {
- Program.Renderer.Camera.ModeTransitionStart = (
- Program.Renderer.Camera.AbsolutePosition,
- Program.Renderer.Camera.AbsoluteDirection,
- Program.Renderer.Camera.AbsoluteUp,
- Program.Renderer.Camera.AbsoluteSide,
- Program.Renderer.CameraTrackFollower.TrackPosition,
- new CameraAlignment(
- Program.Renderer.Camera.AlignmentDirection.Position,
- Program.Renderer.Camera.AlignmentDirection.Yaw,
- Program.Renderer.Camera.AlignmentDirection.Pitch,
- Program.Renderer.Camera.AlignmentDirection.Roll,
- Program.Renderer.Camera.AlignmentDirection.TrackPosition,
- Program.Renderer.Camera.AlignmentDirection.Zoom)
- );
- transition = true;
- }
Program.Renderer.Camera.CurrentMode = CameraViewMode.Interior;
RestoreCameraSettings();
for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
{
if (j == TrainManager.PlayerTrain.CameraCar)
{
- if (TrainManager.PlayerTrain.Cars[j].HasInteriorView)
+ if (TrainManager.PlayerTrain.Cars[j].CarSections.ContainsKey(CarSectionType.Interior))
{
TrainManager.PlayerTrain.Cars[j].ChangeCarSection(CarSectionType.Interior);
}
@@ -128,10 +106,7 @@ private static void ProcessDigitalControl(double TimeElapsed, ref Control Contro
TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].ChangeCarSection(CarSectionType.Interior);
}
- if (!hasCab)
- {
- Program.Renderer.Camera.AlignmentDirection = new CameraAlignment();
- }
+ Program.Renderer.Camera.AlignmentDirection = new CameraAlignment();
Program.Renderer.Camera.AlignmentSpeed = new CameraAlignment();
Program.Renderer.UpdateViewport(ViewportChangeMode.NoChange);
World.UpdateAbsoluteCamera(TimeElapsed);
@@ -148,11 +123,6 @@ private static void ProcessDigitalControl(double TimeElapsed, ref Control Contro
{
Program.Renderer.Camera.CurrentMode = CameraViewMode.InteriorLookAhead;
}
-
- if (transition)
- {
- Program.Renderer.Camera.ModeTransitionTimer = 0.0;
- }
break;
case Translations.Command.CameraHeadOutLeft:
case Translations.Command.CameraHeadOutRight:
@@ -286,29 +256,7 @@ private static void ProcessDigitalControl(double TimeElapsed, ref Control Contro
}
break;
case Translations.Command.CameraExterior:
- // camera: exterior (Handle camera transition from cab mode to exterior mode)
- bool hasCabLeaving = TrainManager.PlayerTrain.Cars[0].InteriorCamera != null || TrainManager.PlayerTrain.Cars[0].HasInteriorView;
- bool isAtCabCarLeaving = TrainManager.PlayerTrain.CameraCar == 0 || TrainManager.PlayerTrain.CameraCar == TrainManager.PlayerTrain.DriverCar;
- bool transitionLeaving = false;
- // Transition only if switching from Interior mode and at the head of the train
- if ((Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior || Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) && isAtCabCarLeaving && hasCabLeaving && Interface.CurrentOptions.CameraExteriorTransition)
- {
- Program.Renderer.Camera.ModeTransitionStart = (
- Program.Renderer.Camera.AbsolutePosition,
- Program.Renderer.Camera.AbsoluteDirection,
- Program.Renderer.Camera.AbsoluteUp,
- Program.Renderer.Camera.AbsoluteSide,
- Program.Renderer.CameraTrackFollower.TrackPosition,
- new CameraAlignment(
- Program.Renderer.Camera.AlignmentDirection.Position,
- Program.Renderer.Camera.AlignmentDirection.Yaw,
- Program.Renderer.Camera.AlignmentDirection.Pitch,
- Program.Renderer.Camera.AlignmentDirection.Roll,
- Program.Renderer.Camera.AlignmentDirection.TrackPosition,
- Program.Renderer.Camera.AlignmentDirection.Zoom)
- );
- transitionLeaving = true;
- }
+ // camera: exterior
SaveCameraSettings();
Program.Renderer.Camera.CurrentMode = CameraViewMode.Exterior;
RestoreCameraSettings();
@@ -334,11 +282,6 @@ private static void ProcessDigitalControl(double TimeElapsed, ref Control Contro
Program.Renderer.UpdateViewport(ViewportChangeMode.NoChange);
World.UpdateAbsoluteCamera(TimeElapsed);
Program.Renderer.UpdateViewingDistances(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance);
-
- if (transitionLeaving)
- {
- Program.Renderer.Camera.ModeTransitionTimer = 0.0;
- }
break;
case Translations.Command.CameraTrack:
case Translations.Command.CameraFlyBy:
@@ -715,7 +658,7 @@ private static void ProcessDigitalControl(double TimeElapsed, ref Control Contro
break;
case Translations.Command.UncoupleFront:
/*
- * Need to remember that the coupler we're talking about here is actually that on the rear of the preceding car, i.e. IDX - 1
+ * Need to remember that the coupler we're talking about here is actually that on the rear of the preceeding car, i.e. IDX - 1
* This connects to the following car and is therefore it's front coupler
*
* However, car indexing is zero-based, so we need to *add* one to get the correct display number
diff --git a/source/OpenBVE/System/Input/ProcessControls.cs b/source/OpenBVE/System/Input/ProcessControls.cs
index de7a9d7c72..2bf42c1fbb 100644
--- a/source/OpenBVE/System/Input/ProcessControls.cs
+++ b/source/OpenBVE/System/Input/ProcessControls.cs
@@ -65,7 +65,7 @@ internal static void ProcessControls(double TimeElapsed)
TrainManager.PlayerTrain.CameraCar = TrainManager.PlayerTrain.DriverCar;
SaveCameraSettings();
bool lookahead = false;
- if (Program.Renderer.Camera.CurrentMode != CameraViewMode.InteriorLookAhead && (Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.NotAvailable || Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.Restricted3D))
+ if (Program.Renderer.Camera.CurrentMode != CameraViewMode.InteriorLookAhead & (Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.NotAvailable || Program.Renderer.Camera.CurrentRestriction == CameraRestrictionMode.Restricted3D))
{
MessageManager.AddMessage(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"notification","interior_lookahead"}),
MessageDependency.CameraView, GameMode.Expert,
diff --git a/source/OpenBVE/System/Interface.cs b/source/OpenBVE/System/Interface.cs
index b58db909cb..0ca05cb2bc 100644
--- a/source/OpenBVE/System/Interface.cs
+++ b/source/OpenBVE/System/Interface.cs
@@ -31,7 +31,7 @@ internal static bool TryParseTime(string Expression, out double Value)
if (i >= 1) {
if (int.TryParse(Expression.Substring(0, i), NumberStyles.Integer, Culture, out int h)) {
int n = Expression.Length - i - 1;
- if (n == 1 || n == 2) {
+ if (n == 1 | n == 2) {
if (uint.TryParse(Expression.Substring(i + 1, n), NumberStyles.None, Culture, out uint m)) {
Value = 3600.0 * h + 60.0 * m;
return true;
diff --git a/source/OpenBVE/System/Loading.cs b/source/OpenBVE/System/Loading.cs
index 2874f65285..617c34988a 100644
--- a/source/OpenBVE/System/Loading.cs
+++ b/source/OpenBVE/System/Loading.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
@@ -81,7 +82,89 @@ internal static void LoadAsynchronously(string routeFile, Encoding routeEncoding
Loader.Start();
}
-
+ /// Gets the absolute Railway folder for a given route file
+ /// The absolute on-disk path of the railway folder
+ internal static string GetRailwayFolder(string routeFile) {
+ try
+ {
+ string currentFolder = Path.GetDirectoryName(routeFile);
+
+ while (true)
+ {
+ string Subfolder = Path.CombineDirectory(currentFolder, "Railway");
+ if (Directory.Exists(Subfolder))
+ {
+ if (Directory.EnumerateDirectories(Subfolder).Any() || Directory.EnumerateFiles(Subfolder).Any())
+ {
+ //HACK: Ignore completely empty directories
+ //Doesn't handle wrong directories, or those with stuff missing, TODO.....
+ Program.FileSystem.AppendToLogFile(Subfolder + " : Railway folder found.");
+ return Subfolder;
+ }
+
+ Program.FileSystem.AppendToLogFile(Subfolder + " : Railway folder candidate rejected- Directory empty.");
+ }
+
+ if (currentFolder == null) continue;
+ DirectoryInfo directoryInfo = Directory.GetParent(currentFolder);
+ if (directoryInfo == null) break;
+ currentFolder = directoryInfo.FullName;
+ }
+ }
+ catch
+ {
+ // ignored
+ }
+
+ // If the Route, Object and Sound folders exist, but are not in a railway folder.....
+ try
+ {
+ string currentFolder = Path.GetDirectoryName(routeFile);
+ if (currentFolder == null)
+ {
+ // Unlikely to work, but attempt to make the best of it
+ Program.FileSystem.AppendToLogFile("The route file appears to be stored on a root path- Returning the " + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"program","title"}) + " startup path.");
+ return Application.StartupPath;
+ }
+ string candidate = null;
+ while (true)
+ {
+ string routeFolder = Path.CombineDirectory(currentFolder, "Route");
+ string objectFolder = Path.CombineDirectory(currentFolder, "Object");
+ string soundFolder = Path.CombineDirectory(currentFolder, "Sound");
+ if (Directory.Exists(routeFolder) && Directory.Exists(objectFolder) && Directory.Exists(soundFolder))
+ {
+ Program.FileSystem.AppendToLogFile(currentFolder + " : Railway folder found.");
+ return currentFolder;
+ }
+
+ if (Directory.Exists(routeFolder) && Directory.Exists(objectFolder))
+ {
+ candidate = currentFolder;
+ }
+
+ DirectoryInfo directoryInfo = Directory.GetParent(currentFolder);
+ if (directoryInfo == null)
+ {
+ if (candidate != null)
+ {
+ Program.FileSystem.AppendToLogFile(currentFolder + " : The best candidate for the Railway folder has been selected- Sound folder not detected.");
+ return candidate;
+ }
+
+ break;
+ }
+
+ currentFolder = directoryInfo.FullName;
+ }
+ }
+ catch
+ {
+ // ignored
+ }
+ Program.FileSystem.AppendToLogFile("No Railway folder found- Returning the " + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"program","title"}) + " startup path.");
+ return Application.StartupPath;
+ }
/// Gets the default train folder for a given route file
/// The absolute on-disk path of the train folder
@@ -242,7 +325,7 @@ private static void LoadThreaded() {
}
private static void LoadEverythingThreaded() {
- string railwayFolder = Program.FileSystem.GetRailwayFolder(CurrentRouteFile, Application.StartupPath);
+ string railwayFolder = GetRailwayFolder(CurrentRouteFile);
string objectFolder = Path.CombineDirectory(railwayFolder, "Object");
string soundFolder = Path.CombineDirectory(railwayFolder, "Sound");
Game.Reset(true);
diff --git a/source/OpenBVE/System/Options.cs b/source/OpenBVE/System/Options.cs
index db2bd96ce3..1fcf0a48fa 100644
--- a/source/OpenBVE/System/Options.cs
+++ b/source/OpenBVE/System/Options.cs
@@ -105,13 +105,6 @@ internal class Options : BaseOptions
internal int FPSLimit;
internal bool DailyBuildUpdates;
-
- /// Whether smooth transitions are enabled for interior camera modes
- internal bool CameraInteriorTransition;
- /// Whether smooth transitions are enabled for exterior camera modes
- internal bool CameraExteriorTransition;
- /// The duration of camera transitions in seconds
- internal double CameraTransitionSpeed;
/// Creates a new instance of the options class with default values set
internal Options()
@@ -186,9 +179,6 @@ internal Options()
UseGDIDecoders = false;
EnableBve5ScriptedTrain = true;
UserInterfaceScaleFactor = 1;
- CameraInteriorTransition = true;
- CameraExteriorTransition = true;
- CameraTransitionSpeed = 0.4;
CultureInfo currentCultureInfo = CultureInfo.CurrentCulture;
switch (Program.CurrentHost.Platform)
{
@@ -302,9 +292,6 @@ public override void Save(string fileName)
Builder.AppendLine("isUseNewRenderer = " + (IsUseNewRenderer ? "true" : "false"));
Builder.AppendLine("forwardsCompatibleContext = " + (ForceForwardsCompatibleContext ? "true" : "false"));
Builder.AppendLine("uiscalefactor = " + UserInterfaceScaleFactor);
- Builder.AppendLine("cameraInteriorTransition = " + (CameraInteriorTransition ? "true" : "false"));
- Builder.AppendLine("cameraExteriorTransition = " + (CameraExteriorTransition ? "true" : "false"));
- Builder.AppendLine("cameraTransitionSpeed = " + CameraTransitionSpeed.ToString(Culture));
Builder.AppendLine();
Builder.AppendLine("[quality]");
Builder.AppendLine("interpolation = " + Interpolation);
@@ -325,7 +312,6 @@ public override void Save(string fileName)
Builder.AppendLine("shadowstrength = " + ShadowStrength.ToString(Culture));
Builder.AppendLine("shadowbias = " + ShadowBias.ToString(Culture));
Builder.AppendLine("shadownormalbias = " + ShadowNormalBias.ToString(Culture));
- Builder.AppendLine("shadowfiltercascades = " + (ShadowFilterCascades ? "true" : "false"));
Builder.AppendLine("fpslimit = " + FPSLimit.ToString(Culture));
Builder.AppendLine();
Builder.AppendLine("[objectOptimization]");
@@ -470,7 +456,6 @@ internal static void LoadOptions()
block.GetValue(OptionsKey.DailyBuildUpdates, out Interface.CurrentOptions.DailyBuildUpdates);
break;
case OptionsSection.Display:
- {
block.GetValue(OptionsKey.PreferNativeBackend, out CurrentOptions.PreferNativeBackend);
block.GetValue(OptionsKey.Mode, out string m);
CurrentOptions.FullscreenMode = string.Compare(m, "fullscreen", StringComparison.OrdinalIgnoreCase) == 0;
@@ -500,35 +485,16 @@ internal static void LoadOptions()
}
block.TryGetValue(OptionsKey.UIScaleFactor, ref CurrentOptions.UserInterfaceScaleFactor);
- block.GetValue(OptionsKey.CameraInteriorTransition, out CurrentOptions.CameraInteriorTransition);
- block.GetValue(OptionsKey.CameraExteriorTransition, out CurrentOptions.CameraExteriorTransition);
- block.TryGetValue(OptionsKey.CameraTransitionSpeed, ref CurrentOptions.CameraTransitionSpeed, NumberRange.Positive);
- if (CurrentOptions.CameraTransitionSpeed == 0)
- {
- CurrentOptions.CameraTransitionSpeed = 0.4;
- }
break;
- }
case OptionsSection.Quality:
- {
block.GetEnumValue(OptionsKey.Interpolation, out Interface.CurrentOptions.Interpolation);
block.TryGetValue(OptionsKey.AnisotropicFilteringMaximum, ref CurrentOptions.AnisotropicFilteringMaximum);
block.TryGetValue(OptionsKey.AnisotropicFilteringLevel, ref Interface.CurrentOptions.AnisotropicFilteringLevel);
block.TryGetValue(OptionsKey.AntiAliasingLevel, ref Interface.CurrentOptions.AntiAliasingLevel);
block.GetEnumValue(OptionsKey.TransparencyMode, out Interface.CurrentOptions.TransparencyMode);
block.GetValue(OptionsKey.OldTransparencyMode, out CurrentOptions.OldTransparencyMode);
- block.TryGetValue(OptionsKey.ViewingDistance, ref Interface.CurrentOptions.ViewingDistance, NumberRange.Positive);
- block.TryGetValue(OptionsKey.QuadLeafSize, ref Interface.CurrentOptions.QuadTreeLeafSize, NumberRange.Positive);
- block.TryGetValue(OptionsKey.NearClipScenery, ref Interface.CurrentOptions.NearClipScenery, NumberRange.Positive);
- block.TryGetValue(OptionsKey.NearClipCab, ref Interface.CurrentOptions.NearClipCab, NumberRange.Positive);
- block.TryGetValue(OptionsKey.NearClipBase, ref Interface.CurrentOptions.NearClipBase, NumberRange.Positive);
- // ensure viewing distance is greater than the near clipping plane to avoid rendering issues
- double maxNearClip = Math.Max(Interface.CurrentOptions.NearClipScenery, Math.Max(Interface.CurrentOptions.NearClipCab, Interface.CurrentOptions.NearClipBase));
-
- if (Interface.CurrentOptions.ViewingDistance <= maxNearClip)
- {
- Interface.CurrentOptions.ViewingDistance = (int)Math.Ceiling(maxNearClip) + 1;
- }
+ block.TryGetValue(OptionsKey.ViewingDistance, ref Interface.CurrentOptions.ViewingDistance);
+ block.TryGetValue(OptionsKey.QuadLeafSize, ref CurrentOptions.QuadTreeLeafSize);
block.GetEnumValue(OptionsKey.MotionBlur, out CurrentOptions.MotionBlur);
block.TryGetEnumValue(OptionsKey.ShadowResolution, ref Interface.CurrentOptions.ShadowResolution);
block.TryGetEnumValue(OptionsKey.ShadowDrawDistance, ref Interface.CurrentOptions.ShadowDrawDistance);
@@ -539,7 +505,6 @@ internal static void LoadOptions()
if (CurrentOptions.ShadowBias > 1.0) CurrentOptions.ShadowBias = 1.0;
block.TryGetValue(OptionsKey.ShadowNormalBias, ref CurrentOptions.ShadowNormalBias);
if (CurrentOptions.ShadowNormalBias < 0.0) CurrentOptions.ShadowNormalBias = 0.0;
- block.GetValue(OptionsKey.ShadowFilterCascades, out Interface.CurrentOptions.ShadowFilterCascades);
block.GetValue(OptionsKey.FPSLimit, out CurrentOptions.FPSLimit);
if (CurrentOptions.FPSLimit < 0)
{
@@ -547,14 +512,11 @@ internal static void LoadOptions()
}
break;
- }
case OptionsSection.ObjectOptimization:
- {
block.GetValue(OptionsKey.BasicThreshold, out CurrentOptions.ObjectOptimizationBasicThreshold);
block.GetValue(OptionsKey.FullThreshold, out CurrentOptions.ObjectOptimizationFullThreshold);
block.GetValue(OptionsKey.VertexCulling, out CurrentOptions.ObjectOptimizationVertexCulling);
break;
- }
case OptionsSection.Simulation:
block.GetValue(OptionsKey.Toppling, out CurrentOptions.Toppling);
block.GetValue(OptionsKey.Collisions, out CurrentOptions.Collisions);
diff --git a/source/OpenBVE/System/Scripting.cs b/source/OpenBVE/System/Scripting.cs
index b8cc61f7a0..f2d9a53b82 100644
--- a/source/OpenBVE/System/Scripting.cs
+++ b/source/OpenBVE/System/Scripting.cs
@@ -29,19 +29,20 @@ public static int CurrentAspect(TrainBase Train, int SectionIndex, bool IsPartOf
if (IsPartOfTrain)
{
int nextSectionIndex = Train.CurrentSectionIndex + 1;
- if (nextSectionIndex >= 0 && nextSectionIndex < Program.CurrentRoute.Sections.Length)
+ if (nextSectionIndex >= 0 & nextSectionIndex < Program.CurrentRoute.Sections.Length)
{
int a = Program.CurrentRoute.Sections[nextSectionIndex].CurrentAspect;
- if (a >= 0 && a < Program.CurrentRoute.Sections[nextSectionIndex].Aspects.Length)
+ if (a >= 0 & a < Program.CurrentRoute.Sections[nextSectionIndex].Aspects.Length)
{
return Program.CurrentRoute.Sections[nextSectionIndex].Aspects[a].Number;
}
+ return 0;
}
}
- else if (SectionIndex >= 0 && SectionIndex < Program.CurrentRoute.Sections.Length)
+ else if (SectionIndex >= 0 & SectionIndex < Program.CurrentRoute.Sections.Length)
{
int a = Program.CurrentRoute.Sections[SectionIndex].CurrentAspect;
- if (a >= 0 && a < Program.CurrentRoute.Sections[SectionIndex].Aspects.Length)
+ if (a >= 0 & a < Program.CurrentRoute.Sections[SectionIndex].Aspects.Length)
{
return Program.CurrentRoute.Sections[SectionIndex].Aspects[a].Number;
}
diff --git a/source/OpenBVE/UserInterface/formBugReport.cs b/source/OpenBVE/UserInterface/formBugReport.cs
index 25090a3f6e..aa8d549932 100644
--- a/source/OpenBVE/UserInterface/formBugReport.cs
+++ b/source/OpenBVE/UserInterface/formBugReport.cs
@@ -44,8 +44,8 @@ private void ApplyLanguage() {
private void buttonViewLog_Click(object sender, EventArgs e)
{
try
- {
- string file = OpenBveApi.Path.CombineFile(Program.FileSystem.SettingsFolder, "log.txt");
+ {
+ var file = OpenBveApi.Path.CombineFile(Program.FileSystem.SettingsFolder, "log.txt");
if(File.Exists(file))
{
if (Program.CurrentHost.Platform == HostPlatform.MicrosoftWindows)
@@ -73,8 +73,8 @@ private void buttonViewCrashLog_Click(object sender, EventArgs e)
{
try
{
- DirectoryInfo directory = new DirectoryInfo(Program.FileSystem.SettingsFolder);
- FileInfo file = directory.GetFiles("OpenBVE Crash*.log").OrderByDescending(f => f.LastWriteTime).First();
+ var directory = new DirectoryInfo(Program.FileSystem.SettingsFolder);
+ var file = directory.GetFiles("OpenBVE Crash*.log").OrderByDescending(f => f.LastWriteTime).First();
if (Program.CurrentHost.Platform == HostPlatform.MicrosoftWindows)
{
Process.Start(file.FullName);
@@ -98,7 +98,7 @@ private void buttonReportProblem_Click(object sender, EventArgs e)
{
using (var ProblemReport = File.OpenWrite(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), fileName)))
{
- using (var zipWriter = WriterFactory.OpenWriter(ProblemReport, ArchiveType.Zip, new WriterOptions(CompressionType.LZMA)))
+ using (var zipWriter = WriterFactory.Open(ProblemReport, ArchiveType.Zip, CompressionType.LZMA))
{
//Add log file to the archive
var file = OpenBveApi.Path.CombineFile(Program.FileSystem.SettingsFolder, "log.txt");
diff --git a/source/OpenBVE/UserInterface/formMain.Designer.cs b/source/OpenBVE/UserInterface/formMain.Designer.cs
index 2918843547..06cb2d0921 100644
--- a/source/OpenBVE/UserInterface/formMain.Designer.cs
+++ b/source/OpenBVE/UserInterface/formMain.Designer.cs
@@ -162,11 +162,6 @@ private void InitializeComponent() {
this.groupboxSound = new System.Windows.Forms.GroupBox();
this.updownSoundNumber = new System.Windows.Forms.NumericUpDown();
this.labelSoundNumber = new System.Windows.Forms.Label();
- this.groupboxCamera = new System.Windows.Forms.GroupBox();
- this.checkboxCameraInteriorTransition = new System.Windows.Forms.CheckBox();
- this.checkboxCameraExteriorTransition = new System.Windows.Forms.CheckBox();
- this.labelCameraTransitionSpeed = new System.Windows.Forms.Label();
- this.updownCameraTransitionSpeed = new System.Windows.Forms.NumericUpDown();
this.panelOptionsPage2 = new System.Windows.Forms.Panel();
this.groupboxDistance = new System.Windows.Forms.GroupBox();
this.updownNearClipBase = new System.Windows.Forms.NumericUpDown();
@@ -183,7 +178,6 @@ private void InitializeComponent() {
this.groupboxShadows = new System.Windows.Forms.GroupBox();
this.labelShadowResolution = new System.Windows.Forms.Label();
this.comboboxShadowResolution = new System.Windows.Forms.ComboBox();
- this.checkboxShadowFilterCascades = new System.Windows.Forms.CheckBox();
this.labelShadowDistance = new System.Windows.Forms.Label();
this.comboboxShadowDistance = new System.Windows.Forms.ComboBox();
this.labelShadowCascades = new System.Windows.Forms.Label();
@@ -542,8 +536,6 @@ private void InitializeComponent() {
this.groupboxSimulation.SuspendLayout();
this.groupboxSound.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.updownSoundNumber)).BeginInit();
- this.groupboxCamera.SuspendLayout();
- ((System.ComponentModel.ISupportInitialize)(this.updownCameraTransitionSpeed)).BeginInit();
this.panelOptionsPage2.SuspendLayout();
this.groupboxDistance.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.updownNearClipBase)).BeginInit();
@@ -1590,6 +1582,7 @@ private void InitializeComponent() {
this.panelOptionsLeft.Controls.Add(this.groupboxDisplayMode);
this.panelOptionsLeft.Controls.Add(this.groupboxWindow);
this.panelOptionsLeft.Controls.Add(this.groupboxFullscreen);
+ this.panelOptionsLeft.Controls.Add(this.groupboxInterpolation);
this.panelOptionsLeft.Location = new System.Drawing.Point(8, 72);
this.panelOptionsLeft.Name = "panelOptionsLeft";
this.panelOptionsLeft.Size = new System.Drawing.Size(316, 576);
@@ -1940,9 +1933,9 @@ private void InitializeComponent() {
this.groupboxInterpolation.Controls.Add(this.labelInterpolation);
this.groupboxInterpolation.Controls.Add(this.trackbarTransparency);
this.groupboxInterpolation.ForeColor = System.Drawing.Color.Black;
- this.groupboxInterpolation.Location = new System.Drawing.Point(0, 158);
+ this.groupboxInterpolation.Location = new System.Drawing.Point(0, 381);
this.groupboxInterpolation.Name = "groupboxInterpolation";
- this.groupboxInterpolation.Size = new System.Drawing.Size(321, 160);
+ this.groupboxInterpolation.Size = new System.Drawing.Size(316, 160);
this.groupboxInterpolation.TabIndex = 7;
this.groupboxInterpolation.TabStop = false;
this.groupboxInterpolation.Text = "Interpolation";
@@ -2073,7 +2066,7 @@ private void InitializeComponent() {
this.panelOptionsRight.Controls.Add(this.groupBoxRailDriver);
this.panelOptionsRight.Controls.Add(this.groupboxControls);
this.panelOptionsRight.Controls.Add(this.groupboxVerbosity);
- this.panelOptionsRight.Controls.Add(this.groupBoxKioskMode);
+ this.panelOptionsRight.Controls.Add(this.groupboxSimulation);
this.panelOptionsRight.Controls.Add(this.groupboxSound);
this.panelOptionsRight.Location = new System.Drawing.Point(360, 72);
this.panelOptionsRight.Name = "panelOptionsRight";
@@ -2087,7 +2080,7 @@ private void InitializeComponent() {
this.groupBoxOther.Controls.Add(this.comboBoxTimeTableDisplayMode);
this.groupBoxOther.Controls.Add(this.labelTimeTableDisplayMode);
this.groupBoxOther.ForeColor = System.Drawing.Color.Black;
- this.groupBoxOther.Location = new System.Drawing.Point(0, 365);
+ this.groupBoxOther.Location = new System.Drawing.Point(0, 347);
this.groupBoxOther.Name = "groupBoxOther";
this.groupBoxOther.Size = new System.Drawing.Size(316, 48);
this.groupBoxOther.TabIndex = 19;
@@ -2246,7 +2239,7 @@ private void InitializeComponent() {
this.groupboxVerbosity.Controls.Add(this.checkboxErrorMessages);
this.groupboxVerbosity.Controls.Add(this.checkboxWarningMessages);
this.groupboxVerbosity.ForeColor = System.Drawing.Color.Black;
- this.groupboxVerbosity.Location = new System.Drawing.Point(0, 298);
+ this.groupboxVerbosity.Location = new System.Drawing.Point(0, 283);
this.groupboxVerbosity.Name = "groupboxVerbosity";
this.groupboxVerbosity.Size = new System.Drawing.Size(316, 64);
this.groupboxVerbosity.TabIndex = 12;
@@ -2293,9 +2286,9 @@ private void InitializeComponent() {
this.groupboxSimulation.Controls.Add(this.checkboxCollisions);
this.groupboxSimulation.Controls.Add(this.checkboxToppling);
this.groupboxSimulation.ForeColor = System.Drawing.Color.Black;
- this.groupboxSimulation.Location = new System.Drawing.Point(330, 485);
+ this.groupboxSimulation.Location = new System.Drawing.Point(0, 203);
this.groupboxSimulation.Name = "groupboxSimulation";
- this.groupboxSimulation.Size = new System.Drawing.Size(321, 80);
+ this.groupboxSimulation.Size = new System.Drawing.Size(316, 80);
this.groupboxSimulation.TabIndex = 11;
this.groupboxSimulation.TabStop = false;
this.groupboxSimulation.Text = "Detail of simulation";
@@ -2407,13 +2400,8 @@ private void InitializeComponent() {
// panelOptionsPage2
//
this.panelOptionsPage2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(243)))), ((int)(((byte)(255)))), ((int)(((byte)(243)))));
- this.panelOptionsPage2.Controls.Add(this.groupboxCamera);
this.panelOptionsPage2.Controls.Add(this.groupboxDistance);
this.panelOptionsPage2.Controls.Add(this.groupboxShadows);
- this.panelOptionsPage2.Controls.Add(this.groupboxInterpolation);
- this.panelOptionsPage2.Controls.Add(this.groupBoxAdvancedOptions);
- this.panelOptionsPage2.Controls.Add(this.groupBoxObjectParser);
- this.panelOptionsPage2.Controls.Add(this.groupboxSimulation);
this.panelOptionsPage2.Location = new System.Drawing.Point(0, 72);
this.panelOptionsPage2.Name = "panelOptionsPage2";
this.panelOptionsPage2.Size = new System.Drawing.Size(683, 583);
@@ -2644,86 +2632,14 @@ private void InitializeComponent() {
this.groupboxShadows.Controls.Add(this.updownShadowBias);
this.groupboxShadows.Controls.Add(this.labelShadowNormalBias);
this.groupboxShadows.Controls.Add(this.updownShadowNormalBias);
- this.groupboxShadows.Controls.Add(this.checkboxShadowFilterCascades);
this.groupboxShadows.ForeColor = System.Drawing.Color.Black;
- this.groupboxShadows.Location = new System.Drawing.Point(330, 0);
+ this.groupboxShadows.Location = new System.Drawing.Point(0, 155);
this.groupboxShadows.Name = "groupboxShadows";
- this.groupboxShadows.Size = new System.Drawing.Size(321, 240);
+ this.groupboxShadows.Size = new System.Drawing.Size(321, 210);
this.groupboxShadows.TabIndex = 30;
this.groupboxShadows.TabStop = false;
this.groupboxShadows.Text = "Shadows";
//
- // groupboxCamera
- //
- this.groupboxCamera.Controls.Add(this.checkboxCameraInteriorTransition);
- this.groupboxCamera.Controls.Add(this.checkboxCameraExteriorTransition);
- this.groupboxCamera.Controls.Add(this.labelCameraTransitionSpeed);
- this.groupboxCamera.Controls.Add(this.updownCameraTransitionSpeed);
- this.groupboxCamera.ForeColor = System.Drawing.Color.Black;
- this.groupboxCamera.Location = new System.Drawing.Point(330, 245);
- this.groupboxCamera.Name = "groupboxCamera";
- this.groupboxCamera.Size = new System.Drawing.Size(321, 120);
- this.groupboxCamera.TabIndex = 22;
- this.groupboxCamera.TabStop = false;
- this.groupboxCamera.Text = "Camera options";
- //
- // checkboxCameraInteriorTransition
- //
- this.checkboxCameraInteriorTransition.AutoSize = true;
- this.checkboxCameraInteriorTransition.Location = new System.Drawing.Point(8, 21);
- this.checkboxCameraInteriorTransition.Name = "checkboxCameraInteriorTransition";
- this.checkboxCameraInteriorTransition.Size = new System.Drawing.Size(150, 17);
- this.checkboxCameraInteriorTransition.TabIndex = 0;
- this.checkboxCameraInteriorTransition.Text = "Smooth interior transition";
- this.checkboxCameraInteriorTransition.UseVisualStyleBackColor = true;
- //
- // checkboxCameraExteriorTransition
- //
- this.checkboxCameraExteriorTransition.AutoSize = true;
- this.checkboxCameraExteriorTransition.Location = new System.Drawing.Point(8, 44);
- this.checkboxCameraExteriorTransition.Name = "checkboxCameraExteriorTransition";
- this.checkboxCameraExteriorTransition.Size = new System.Drawing.Size(150, 17);
- this.checkboxCameraExteriorTransition.TabIndex = 1;
- this.checkboxCameraExteriorTransition.Text = "Smooth exterior transition";
- this.checkboxCameraExteriorTransition.UseVisualStyleBackColor = true;
- //
- // labelCameraTransitionSpeed
- //
- this.labelCameraTransitionSpeed.AutoSize = true;
- this.labelCameraTransitionSpeed.Location = new System.Drawing.Point(8, 73);
- this.labelCameraTransitionSpeed.Name = "labelCameraTransitionSpeed";
- this.labelCameraTransitionSpeed.Size = new System.Drawing.Size(130, 13);
- this.labelCameraTransitionSpeed.TabIndex = 2;
- this.labelCameraTransitionSpeed.Text = "Transition duration (sec):";
- //
- // updownCameraTransitionSpeed
- //
- this.updownCameraTransitionSpeed.DecimalPlaces = 1;
- this.updownCameraTransitionSpeed.Increment = new decimal(new int[] {
- 1,
- 0,
- 0,
- 65536});
- this.updownCameraTransitionSpeed.Location = new System.Drawing.Point(200, 71);
- this.updownCameraTransitionSpeed.Maximum = new decimal(new int[] {
- 50,
- 0,
- 0,
- 65536});
- this.updownCameraTransitionSpeed.Minimum = new decimal(new int[] {
- 1,
- 0,
- 0,
- 65536});
- this.updownCameraTransitionSpeed.Name = "updownCameraTransitionSpeed";
- this.updownCameraTransitionSpeed.Size = new System.Drawing.Size(52, 20);
- this.updownCameraTransitionSpeed.TabIndex = 3;
- this.updownCameraTransitionSpeed.Value = new decimal(new int[] {
- 4,
- 0,
- 0,
- 65536});
- //
// labelShadowResolution
//
this.labelShadowResolution.AutoSize = true;
@@ -2749,16 +2665,6 @@ private void InitializeComponent() {
this.comboboxShadowResolution.TabIndex = 1;
this.comboboxShadowResolution.SelectedIndexChanged += new System.EventHandler(this.comboboxShadowResolution_SelectedIndexChanged);
//
- // checkboxShadowFilterCascades
- //
- this.checkboxShadowFilterCascades.AutoSize = true;
- this.checkboxShadowFilterCascades.Location = new System.Drawing.Point(8, 215);
- this.checkboxShadowFilterCascades.Name = "checkboxShadowFilterCascades";
- this.checkboxShadowFilterCascades.Size = new System.Drawing.Size(150, 17);
- this.checkboxShadowFilterCascades.TabIndex = 14;
- this.checkboxShadowFilterCascades.Text = "Per-cascade culling";
- this.checkboxShadowFilterCascades.UseVisualStyleBackColor = true;
- //
// labelShadowDistance
//
this.labelShadowDistance.AutoSize = true;
@@ -2922,7 +2828,7 @@ private void InitializeComponent() {
this.buttonOptionsNext.TabIndex = 18;
this.buttonOptionsNext.Text = "Next Page...";
this.buttonOptionsNext.UseVisualStyleBackColor = true;
- this.buttonOptionsNext.Click += new System.EventHandler(this.buttonOptionsNext_Click);
+ this.buttonOptionsNext.Click += new System.EventHandler(this.buttonOptionsPrevious_Click);
//
// panelOptionsPage3
//
@@ -2930,6 +2836,9 @@ private void InitializeComponent() {
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panelOptionsPage3.Controls.Add(this.groupBoxInputDevice);
+ this.panelOptionsPage3.Controls.Add(this.groupBoxObjectParser);
+ this.panelOptionsPage3.Controls.Add(this.groupBoxKioskMode);
+ this.panelOptionsPage3.Controls.Add(this.groupBoxAdvancedOptions);
this.panelOptionsPage3.Controls.Add(this.groupBoxPackageOptions);
this.panelOptionsPage3.Location = new System.Drawing.Point(0, 72);
this.panelOptionsPage3.Name = "panelOptionsPage3";
@@ -2946,9 +2855,9 @@ private void InitializeComponent() {
this.groupBoxInputDevice.Controls.Add(this.checkBoxInputDeviceEnable);
this.groupBoxInputDevice.Controls.Add(this.buttonInputDeviceConfig);
this.groupBoxInputDevice.ForeColor = System.Drawing.Color.Black;
- this.groupBoxInputDevice.Location = new System.Drawing.Point(0, 190);
+ this.groupBoxInputDevice.Location = new System.Drawing.Point(6, 396);
this.groupBoxInputDevice.Name = "groupBoxInputDevice";
- this.groupBoxInputDevice.Size = new System.Drawing.Size(674, 385);
+ this.groupBoxInputDevice.Size = new System.Drawing.Size(674, 181);
this.groupBoxInputDevice.TabIndex = 24;
this.groupBoxInputDevice.TabStop = false;
this.groupBoxInputDevice.Text = "Input Device Plugin";
@@ -2983,7 +2892,7 @@ private void InitializeComponent() {
this.listviewInputDevice.MultiSelect = false;
this.listviewInputDevice.Name = "listviewInputDevice";
this.listviewInputDevice.ShowGroups = false;
- this.listviewInputDevice.Size = new System.Drawing.Size(658, 303);
+ this.listviewInputDevice.Size = new System.Drawing.Size(658, 103);
this.listviewInputDevice.TabIndex = 1;
this.listviewInputDevice.UseCompatibleStateImageBehavior = false;
this.listviewInputDevice.View = System.Windows.Forms.View.Details;
@@ -3015,7 +2924,7 @@ private void InitializeComponent() {
//
this.checkBoxInputDeviceEnable.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.checkBoxInputDeviceEnable.Enabled = false;
- this.checkBoxInputDeviceEnable.Location = new System.Drawing.Point(8, 344);
+ this.checkBoxInputDeviceEnable.Location = new System.Drawing.Point(8, 144);
this.checkBoxInputDeviceEnable.Name = "checkBoxInputDeviceEnable";
this.checkBoxInputDeviceEnable.Size = new System.Drawing.Size(230, 34);
this.checkBoxInputDeviceEnable.TabIndex = 2;
@@ -3029,7 +2938,7 @@ private void InitializeComponent() {
this.buttonInputDeviceConfig.BackColor = System.Drawing.SystemColors.ButtonFace;
this.buttonInputDeviceConfig.Enabled = false;
this.buttonInputDeviceConfig.ForeColor = System.Drawing.SystemColors.ControlText;
- this.buttonInputDeviceConfig.Location = new System.Drawing.Point(270, 352);
+ this.buttonInputDeviceConfig.Location = new System.Drawing.Point(270, 148);
this.buttonInputDeviceConfig.MaximumSize = new System.Drawing.Size(106, 25);
this.buttonInputDeviceConfig.Name = "buttonInputDeviceConfig";
this.buttonInputDeviceConfig.Size = new System.Drawing.Size(106, 25);
@@ -3046,9 +2955,9 @@ private void InitializeComponent() {
this.groupBoxObjectParser.Controls.Add(this.labelXparser);
this.groupBoxObjectParser.Controls.Add(this.comboBoxXparser);
this.groupBoxObjectParser.ForeColor = System.Drawing.Color.Black;
- this.groupBoxObjectParser.Location = new System.Drawing.Point(330, 370);
+ this.groupBoxObjectParser.Location = new System.Drawing.Point(377, 288);
this.groupBoxObjectParser.Name = "groupBoxObjectParser";
- this.groupBoxObjectParser.Size = new System.Drawing.Size(321, 110);
+ this.groupBoxObjectParser.Size = new System.Drawing.Size(305, 110);
this.groupBoxObjectParser.TabIndex = 23;
this.groupBoxObjectParser.TabStop = false;
this.groupBoxObjectParser.Text = "Object Parser";
@@ -3098,15 +3007,14 @@ private void InitializeComponent() {
//
// groupBoxKioskMode
//
- this.groupBoxKioskMode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupBoxKioskMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.groupBoxKioskMode.Controls.Add(this.labelKioskTimeout);
this.groupBoxKioskMode.Controls.Add(this.numericUpDownKioskTimeout);
this.groupBoxKioskMode.Controls.Add(this.checkBoxEnableKiosk);
this.groupBoxKioskMode.ForeColor = System.Drawing.Color.Black;
- this.groupBoxKioskMode.Location = new System.Drawing.Point(0, 203);
+ this.groupBoxKioskMode.Location = new System.Drawing.Point(377, 190);
this.groupBoxKioskMode.Name = "groupBoxKioskMode";
- this.groupBoxKioskMode.Size = new System.Drawing.Size(316, 92);
+ this.groupBoxKioskMode.Size = new System.Drawing.Size(305, 92);
this.groupBoxKioskMode.TabIndex = 22;
this.groupBoxKioskMode.TabStop = false;
this.groupBoxKioskMode.Text = "Kiosk Mode";
@@ -3159,9 +3067,9 @@ private void InitializeComponent() {
this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxIsUseNewRenderer);
this.groupBoxAdvancedOptions.Controls.Add(this.checkBoxLoadInAdvance);
this.groupBoxAdvancedOptions.ForeColor = System.Drawing.Color.Black;
- this.groupBoxAdvancedOptions.Location = new System.Drawing.Point(0, 323);
+ this.groupBoxAdvancedOptions.Location = new System.Drawing.Point(8, 190);
this.groupBoxAdvancedOptions.Name = "groupBoxAdvancedOptions";
- this.groupBoxAdvancedOptions.Size = new System.Drawing.Size(321, 208);
+ this.groupBoxAdvancedOptions.Size = new System.Drawing.Size(358, 208);
this.groupBoxAdvancedOptions.TabIndex = 21;
this.groupBoxAdvancedOptions.TabStop = false;
this.groupBoxAdvancedOptions.Text = "Advanced Options";
@@ -6475,9 +6383,6 @@ private void InitializeComponent() {
this.groupboxSimulation.PerformLayout();
this.groupboxSound.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.updownSoundNumber)).EndInit();
- this.groupboxCamera.ResumeLayout(false);
- this.groupboxCamera.PerformLayout();
- ((System.ComponentModel.ISupportInitialize)(this.updownCameraTransitionSpeed)).EndInit();
this.panelOptionsPage2.ResumeLayout(false);
this.groupboxDistance.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.updownNearClipBase)).EndInit();
@@ -6579,7 +6484,6 @@ private void InitializeComponent() {
private System.Windows.Forms.Panel panelOptionsRight;
private System.Windows.Forms.Label labelShadowResolution;
private System.Windows.Forms.ComboBox comboboxShadowResolution;
- private System.Windows.Forms.CheckBox checkboxShadowFilterCascades;
private System.Windows.Forms.Label labelShadowDistance;
private System.Windows.Forms.ComboBox comboboxShadowDistance;
private System.Windows.Forms.Label labelShadowCascades;
@@ -7031,11 +6935,6 @@ private void InitializeComponent() {
private System.Windows.Forms.Button buttonMSTSTrainsetDirectory;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textBoxMSTSTrainsetDirectory;
- private System.Windows.Forms.GroupBox groupboxCamera;
- private System.Windows.Forms.CheckBox checkboxCameraInteriorTransition;
- private System.Windows.Forms.CheckBox checkboxCameraExteriorTransition;
- private System.Windows.Forms.Label labelCameraTransitionSpeed;
- private System.Windows.Forms.NumericUpDown updownCameraTransitionSpeed;
private System.Windows.Forms.Panel panelOptionsPage2;
}
}
diff --git a/source/OpenBVE/UserInterface/formMain.Options.cs b/source/OpenBVE/UserInterface/formMain.Options.cs
index d6322bd841..f63c0e7512 100644
--- a/source/OpenBVE/UserInterface/formMain.Options.cs
+++ b/source/OpenBVE/UserInterface/formMain.Options.cs
@@ -53,22 +53,21 @@ private void comboboxShadowResolution_SelectedIndexChanged(object sender, EventA
labelShadowStrengthValue.Enabled = shadowEnabled;
updownShadowBias.Enabled = shadowEnabled;
updownShadowNormalBias.Enabled = shadowEnabled;
- checkboxShadowFilterCascades.Enabled = shadowEnabled;
if (!shadowEnabled)
{
// Visual hint: grey out the strength label
- labelShadowStrengthValue.Text = @"—";
+ labelShadowStrengthValue.Text = "—";
}
else
{
- labelShadowStrengthValue.Text = trackbarShadowStrength.Value + @"%";
+ labelShadowStrengthValue.Text = trackbarShadowStrength.Value + "%";
}
}
private void trackbarShadowStrength_Scroll(object sender, EventArgs e)
{
- labelShadowStrengthValue.Text = trackbarShadowStrength.Value + @"%";
+ labelShadowStrengthValue.Text = trackbarShadowStrength.Value + "%";
}
private void updownShadowBias_ValueChanged(object sender, EventArgs e)
diff --git a/source/OpenBVE/UserInterface/formMain.Packages.cs b/source/OpenBVE/UserInterface/formMain.Packages.cs
index f551704b74..7a9fc4087d 100644
--- a/source/OpenBVE/UserInterface/formMain.Packages.cs
+++ b/source/OpenBVE/UserInterface/formMain.Packages.cs
@@ -663,9 +663,21 @@ private void dataGridViewPackages_SelectionChanged(object sender, EventArgs e)
private void buttonUninstallPackage_Click(object sender, EventArgs e)
{
- if (currentPackage != null && currentPackage.PackageType != PackageType.NotFound)
+ if (currentPackage != null)
{
- UninstallPackage(currentPackage);
+ switch (currentPackage.PackageType)
+ {
+ case PackageType.Route:
+ UninstallPackage(currentPackage);
+ break;
+ case PackageType.Train:
+ UninstallPackage(currentPackage);
+ break;
+ case PackageType.Other:
+ case PackageType.Loksim3D:
+ UninstallPackage(currentPackage);
+ break;
+ }
}
else
{
@@ -1083,6 +1095,7 @@ private void Q1_CheckedChanged(object sender, EventArgs e)
panelReplacePackage.Hide();
panelNewPackage.Show();
panelNewPackage.Enabled = true;
+ string GUID = Guid.NewGuid().ToString();
currentPackage = new Package
{
Name = textBoxPackageName.Text,
@@ -1090,7 +1103,7 @@ private void Q1_CheckedChanged(object sender, EventArgs e)
Description = textBoxPackageDescription.Text.Replace("\r\n", "\\r\\n"),
//TODO:
//Website = linkLabelPackageWebsite.Links[0],
- GUID = Guid.NewGuid().ToString(),
+ GUID = GUID,
PackageVersion = new Version(0, 0, 0, 0),
PackageType = newPackageType
};
@@ -1448,13 +1461,13 @@ private void addPackageItemsButton_Click(object sender, EventArgs e)
{
filesToPackageBox.Text += folderDisplay + Environment.NewLine;
- List tempList = new List();
+ var tempList = new List();
for (int i = 0; i < files.Length; i++)
{
- PackageFile tempFile = new PackageFile
+ var tempFile = new PackageFile
{
absolutePath = files[i],
- relativePath = files[i].Replace(folder, "")
+ relativePath = files[i].Replace(folder, ""),
};
tempList.Add(tempFile);
}
diff --git a/source/OpenBVE/UserInterface/formMain.Review.cs b/source/OpenBVE/UserInterface/formMain.Review.cs
index 61b1efde35..660c0149a3 100644
--- a/source/OpenBVE/UserInterface/formMain.Review.cs
+++ b/source/OpenBVE/UserInterface/formMain.Review.cs
@@ -59,7 +59,7 @@ private void ShowScoreLog(bool penaltiesOnly) {
int sum = 0;
for (int i = 0; i < Game.ScoreLogs.Count; i++) {
sum += Game.ScoreLogs[i].Value;
- if (!penaltiesOnly || Game.ScoreLogs[i].Value < 0) {
+ if (!penaltiesOnly | Game.ScoreLogs[i].Value < 0) {
double x = Game.ScoreLogs[i].Time;
int h = (int)Math.Floor(x / 3600.0);
x -= 3600.0 * h;
diff --git a/source/OpenBVE/UserInterface/formMain.Start.cs b/source/OpenBVE/UserInterface/formMain.Start.cs
index 8d9aa06c8a..3f74913701 100644
--- a/source/OpenBVE/UserInterface/formMain.Start.cs
+++ b/source/OpenBVE/UserInterface/formMain.Start.cs
@@ -1269,7 +1269,7 @@ private void PreviewLoadRoute(LaunchParameters result)
// ReSharper disable once RedundantCast
object route = (object)Program.CurrentRoute; //must cast to allow us to use the ref keyword.
- string railwayFolder = Program.FileSystem.GetRailwayFolder(result.RouteFile, Application.StartupPath);
+ string railwayFolder = Loading.GetRailwayFolder(result.RouteFile);
string objectFolder = Path.CombineDirectory(railwayFolder, "Object");
string soundFolder = Path.CombineDirectory(railwayFolder, "Sound");
@@ -1346,9 +1346,9 @@ private void ShowRouteInformation(Exception e)
}
// description
- string routeDescription = Program.CurrentRoute.Comment.ConvertNewlinesToCrLf();
- textboxRouteDescription.Text = routeDescription.Length != 0 ? routeDescription : System.IO.Path.GetFileNameWithoutExtension(Result.RouteFile);
- textboxRouteEncodingPreview.Text = routeDescription.ConvertNewlinesToCrLf();
+ string Description = Program.CurrentRoute.Comment.ConvertNewlinesToCrLf();
+ textboxRouteDescription.Text = Description.Length != 0 ? Description : System.IO.Path.GetFileNameWithoutExtension(Result.RouteFile);
+ textboxRouteEncodingPreview.Text = Description.ConvertNewlinesToCrLf();
if (Interface.CurrentOptions.TrainName != null)
{
checkboxTrainDefault.Text = $@"{Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"start","train_usedefault"})} ({Interface.CurrentOptions.TrainName})";
@@ -1414,7 +1414,7 @@ internal void DisposePreviewRouteThread()
// show route
- private void ShowRoute(bool userSelectedEncoding)
+ private void ShowRoute(bool UserSelectedEncoding)
{
Cursor = System.Windows.Forms.Cursors.WaitCursor;
TryLoadImage(pictureboxRouteImage, "loading.png");
@@ -1422,7 +1422,7 @@ private void ShowRoute(bool userSelectedEncoding)
textboxRouteDescription.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"start","route_processing"});
// determine encoding
- if (!userSelectedEncoding)
+ if (!UserSelectedEncoding)
{
Result.RouteEncoding = TextEncoding.GetSystemEncodingFromFile(Result.RouteFile);
comboboxRouteEncoding.Tag = new object();
@@ -1469,7 +1469,7 @@ private void ShowRoute(bool userSelectedEncoding)
}
// show train
- private void ShowTrain(bool userSelectedEncoding)
+ private void ShowTrain(bool UserSelectedEncoding)
{
lock (previewLock)
{
@@ -1487,7 +1487,7 @@ private void ShowTrain(bool userSelectedEncoding)
{
canLoad = true;
trainImage = Program.CurrentHost.Plugins[i].Train.GetImage(Result.TrainFolder);
- if (!userSelectedEncoding)
+ if (!UserSelectedEncoding)
{
string descriptionFile = Path.CombineFile(Result.TrainFolder, "train.txt");
if (!File.Exists(descriptionFile))
diff --git a/source/OpenBVE/UserInterface/formMain.cs b/source/OpenBVE/UserInterface/formMain.cs
index f48c5853a9..b929c7d81c 100644
--- a/source/OpenBVE/UserInterface/formMain.cs
+++ b/source/OpenBVE/UserInterface/formMain.cs
@@ -29,7 +29,6 @@ internal partial class formMain : Form
private formMain()
{
InitializeComponent();
- toolTip = new ToolTip(components);
}
public sealed override string Text
@@ -40,25 +39,24 @@ public sealed override string Text
internal static LaunchParameters ShowMainDialog(LaunchParameters initial)
{
- using (formMain mainDialog = new formMain())
+ using (formMain Dialog = new formMain())
{
- mainDialog.Result = initial;
- mainDialog.ShowDialog();
- LaunchParameters result = mainDialog.Result;
+ Dialog.Result = initial;
+ Dialog.ShowDialog();
+ LaunchParameters result = Dialog.Result;
//Dispose of the worker thread when closing the form
//If it's still running, it attempts to update a non-existent form and crashes nastily
- mainDialog.DisposePreviewRouteThread();
+ Dialog.DisposePreviewRouteThread();
if (!OpenTK.Configuration.RunningOnMacOS)
{
- mainDialog.trainWatcher.Dispose();
- mainDialog.routeWatcher.Dispose();
+ Dialog.trainWatcher.Dispose();
+ Dialog.routeWatcher.Dispose();
}
return result;
}
}
// members
- private readonly ToolTip toolTip;
private LaunchParameters Result;
private int[] EncodingCodepages;
private Image JoystickImage;
@@ -75,11 +73,11 @@ internal static LaunchParameters ShowMainDialog(LaunchParameters initial)
private void formMain_Load(object sender, EventArgs e)
{
MinimumSize = Size;
- if (Interface.CurrentOptions.MainMenuWidth == -1 && Interface.CurrentOptions.MainMenuHeight == -1)
+ if (Interface.CurrentOptions.MainMenuWidth == -1 & Interface.CurrentOptions.MainMenuHeight == -1)
{
WindowState = FormWindowState.Maximized;
}
- else if (Interface.CurrentOptions.MainMenuWidth > 0 && Interface.CurrentOptions.MainMenuHeight > 0)
+ else if (Interface.CurrentOptions.MainMenuWidth > 0 & Interface.CurrentOptions.MainMenuHeight > 0)
{
Size = new Size(Interface.CurrentOptions.MainMenuWidth, Interface.CurrentOptions.MainMenuHeight);
CenterToScreen();
@@ -493,15 +491,13 @@ private void formMain_Load(object sender, EventArgs e)
}
// Shadow Strength
trackbarShadowStrength.Value = (int)(Interface.CurrentOptions.ShadowStrength * 100.0);
- labelShadowStrengthValue.Text = trackbarShadowStrength.Value + @"%";
+ labelShadowStrengthValue.Text = trackbarShadowStrength.Value + "%";
updownShadowBias.Value = (decimal)Interface.CurrentOptions.ShadowBias;
updownShadowNormalBias.Value = (decimal)Interface.CurrentOptions.ShadowNormalBias;
- checkboxShadowFilterCascades.Checked = Interface.CurrentOptions.ShadowFilterCascades;
// Enable/disable shadow sub-controls based on resolution setting
bool shadowEnabled = Interface.CurrentOptions.ShadowResolution != ShadowMapResolution.Off;
comboboxShadowDistance.Enabled = shadowEnabled;
comboboxShadowCascades.Enabled = shadowEnabled;
- checkboxShadowFilterCascades.Enabled = shadowEnabled;
trackbarShadowStrength.Enabled = shadowEnabled;
updownShadowBias.Enabled = shadowEnabled;
updownShadowNormalBias.Enabled = shadowEnabled;
@@ -526,9 +522,6 @@ private void formMain_Load(object sender, EventArgs e)
checkBoxEnableKiosk.Checked = Interface.CurrentOptions.KioskMode;
numericUpDownKioskTimeout.Value = (decimal)Interface.CurrentOptions.KioskModeTimer;
checkBoxAccessibility.Checked = Interface.CurrentOptions.Accessibility;
- checkboxCameraInteriorTransition.Checked = Interface.CurrentOptions.CameraInteriorTransition;
- checkboxCameraExteriorTransition.Checked = Interface.CurrentOptions.CameraExteriorTransition;
- updownCameraTransitionSpeed.Value = (decimal)Interface.CurrentOptions.CameraTransitionSpeed;
ListInputDevicePlugins();
if (Program.CurrentHost.MonoRuntime)
{
@@ -779,10 +772,6 @@ private void ApplyLanguage()
comboboxShadowCascades.Items[2] = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "shadows_cascades_4" });
//Simulation
groupboxSimulation.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","misc_simulation"});
- groupboxCamera.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","camera"});
- checkboxCameraInteriorTransition.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","camera_interior_transition"});
- checkboxCameraExteriorTransition.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","camera_exterior_transition"});
- labelCameraTransitionSpeed.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","camera_transition_duration"});
checkboxToppling.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","misc_simulation_toppling"});
checkboxCollisions.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","misc_simulation_collisions"});
checkboxDerailments.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","misc_simulation_derailments"});
@@ -934,7 +923,7 @@ private void ApplyLanguage()
case GameMode.Arcade: labelRatingModeValue.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"mode","arcade"}); break;
case GameMode.Normal: labelRatingModeValue.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"mode","normal"}); break;
case GameMode.Expert: labelRatingModeValue.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"mode","expert"}); break;
- default: labelRatingModeValue.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"mode","unknown"}); break;
+ default: labelRatingModeValue.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"mode","unkown"}); break;
}
{
double ratio = Game.CurrentScore.Maximum == 0 ? 0.0 : (double)Game.CurrentScore.CurrentValue / Game.CurrentScore.Maximum;
@@ -1163,32 +1152,6 @@ private void ApplyLanguage()
}
-
- ApplyToolTips();
- }
-
- /// Applies tooltips to the various controls on the form
- private void ApplyToolTips()
- {
- SetToolTip("interpolation", labelInterpolation, comboboxInterpolation);
- SetToolTip("anisotropic", labelAnisotropic, updownAnisotropic);
- SetToolTip("antialiasing", labelAntiAliasing, updownAntiAliasing);
- SetToolTip("transparency", labelTransparency, trackbarTransparency);
- SetToolTip("viewingdistance", labelDistance, updownDistance);
- SetToolTip("motionblur", labelMotionBlur, comboboxMotionBlur);
- SetToolTip("new_renderer", checkBoxIsUseNewRenderer);
- }
-
- /// Sets the tooltip for one or more controls using a translation key
- /// The translation key in the 'tooltips' group
- /// The controls to apply the tooltip to
- private void SetToolTip(string key, params Control[] controls)
- {
- string text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "tooltips", key });
- foreach (Control control in controls)
- {
- toolTip.SetToolTip(control, text);
- }
}
// form closing
@@ -1263,7 +1226,6 @@ private void formMain_FormClosing()
Interface.CurrentOptions.ShadowStrength = trackbarShadowStrength.Value / 100.0;
Interface.CurrentOptions.ShadowBias = (double)updownShadowBias.Value;
Interface.CurrentOptions.ShadowNormalBias = (double)updownShadowNormalBias.Value;
- Interface.CurrentOptions.ShadowFilterCascades = checkboxShadowFilterCascades.Checked;
Interface.CurrentOptions.GameMode = (GameMode)comboboxMode.SelectedIndex;
Interface.CurrentOptions.BlackBox = checkboxBlackBox.Checked;
Interface.CurrentOptions.LoadingSway = checkBoxLoadingSway.Checked;
@@ -1283,9 +1245,6 @@ private void formMain_FormClosing()
Interface.CurrentOptions.CurrentObjParser = (ObjParsers)comboBoxObjparser.SelectedIndex;
Interface.CurrentOptions.Panel2ExtendedMode = checkBoxPanel2Extended.Checked;
Interface.CurrentOptions.Accessibility = checkBoxAccessibility.Checked;
- Interface.CurrentOptions.CameraInteriorTransition = checkboxCameraInteriorTransition.Checked;
- Interface.CurrentOptions.CameraExteriorTransition = checkboxCameraExteriorTransition.Checked;
- Interface.CurrentOptions.CameraTransitionSpeed = (double)updownCameraTransitionSpeed.Value;
switch (trackBarHUDSize.Value)
{
case 0:
@@ -1570,7 +1529,7 @@ private void formMain_Shown(object sender, EventArgs e)
if (WindowState != FormWindowState.Maximized)
{
System.Windows.Forms.Screen s = System.Windows.Forms.Screen.FromControl(this);
- if (Width >= 0.95 * s.WorkingArea.Width || Height >= 0.95 * s.WorkingArea.Height)
+ if (Width >= 0.95 * s.WorkingArea.Width | Height >= 0.95 * s.WorkingArea.Height)
{
WindowState = FormWindowState.Maximized;
}
@@ -1667,10 +1626,6 @@ private void radiobuttonOptions_CheckedChanged(object sender, EventArgs e)
panelPackages.Visible = false;
pictureboxJoysticks.Visible = false;
UpdatePanelColor();
- if (radiobuttonOptions.Checked)
- {
- SetOptionsPage(0);
- }
}
private void radioButtonPackages_CheckedChanged(object sender, EventArgs e)
{
@@ -2091,50 +2046,26 @@ private void linkLabelCheckUpdates_Click(object sender, EventArgs e)
CheckForUpdate();
}
- private Control[][] optionsPages;
- private int currentOptionsPage = 0;
-
- private void SetOptionsPage(int pageIndex)
+ private void buttonOptionsPrevious_Click(object sender, EventArgs e)
{
- if (optionsPages == null)
- {
- optionsPages = new[] {
- new Control[] { panelOptionsLeft, panelOptionsRight },
- new Control[] { panelOptionsPage2 },
- new Control[] { panelOptionsPage3 }
- };
- }
- currentOptionsPage = pageIndex;
- for (int i = 0; i < optionsPages.Length; i++)
- {
- for (int j = 0; j < optionsPages[i].Length; j++)
- {
- optionsPages[i][j].Visible = (i == pageIndex);
- }
- }
- buttonOptionsPrevious.Enabled = (currentOptionsPage > 0);
- buttonOptionsNext.Enabled = (currentOptionsPage < optionsPages.Length - 1);
-
- if (panelOptionsPage2.Visible)
+ if (panelOptionsLeft.Visible)
{
+ panelOptionsLeft.Hide();
+ panelOptionsRight.Hide();
+ panelOptionsPage2.Show();
//HACK: Column Header in list view won't appear in Mono without resizing it...
listviewInputDevice.AutoResizeColumns(ColumnHeaderAutoResizeStyle.None);
}
- }
-
- private void buttonOptionsPrevious_Click(object sender, EventArgs e)
- {
- if (currentOptionsPage > 0)
+ else if(panelOptionsPage2.Visible)
{
- SetOptionsPage(currentOptionsPage - 1);
+ panelOptionsPage2.Hide();
+ panelOptionsPage3.Show();
}
- }
-
- private void buttonOptionsNext_Click(object sender, EventArgs e)
- {
- if (currentOptionsPage < optionsPages.Length - 1)
+ else
{
- SetOptionsPage(currentOptionsPage + 1);
+ panelOptionsPage3.Hide();
+ panelOptionsLeft.Show();
+ panelOptionsRight.Show();
}
}
diff --git a/source/OpenBVE/UserInterface/formViewLog.cs b/source/OpenBVE/UserInterface/formViewLog.cs
index c5a13ba4d1..d21b568a78 100644
--- a/source/OpenBVE/UserInterface/formViewLog.cs
+++ b/source/OpenBVE/UserInterface/formViewLog.cs
@@ -17,7 +17,7 @@ public FormViewLog(string text)
private void SetText(string text)
{
- string originalTitle = Text;
+ var originalTitle = Text;
Text += Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"message","loading"});
Shown += (sender, e) => {
textBoxLog.Text = text;
diff --git a/source/OpenBVE/app.config b/source/OpenBVE/app.config
index 4495e3fe51..e5213d2369 100644
--- a/source/OpenBVE/app.config
+++ b/source/OpenBVE/app.config
@@ -17,10 +17,6 @@
-
-
-
-
diff --git a/source/OpenBVE/packages.config b/source/OpenBVE/packages.config
index a179bdd455..ad7c03cd92 100644
--- a/source/OpenBVE/packages.config
+++ b/source/OpenBVE/packages.config
@@ -1,13 +1,11 @@
-
-
+
-
-
+
\ No newline at end of file
diff --git a/source/OpenBveApi/FunctionScripts/FunctionScript.cs b/source/OpenBveApi/FunctionScripts/FunctionScript.cs
index d9db77f7c4..b56beb3149 100644
--- a/source/OpenBveApi/FunctionScripts/FunctionScript.cs
+++ b/source/OpenBveApi/FunctionScripts/FunctionScript.cs
@@ -449,11 +449,7 @@ public FunctionScript(HostInterface Host, string Expression, bool Infix)
if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1);
InstructionSet[n] = Instructions.CameraView;
n++; s++; if (s >= m) m = s; break;
- case "cameracar":
- if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1);
- InstructionSet[n] = Instructions.CameraCar;
- n++; s++; if (s >= m) m = s; break;
- // train
+ // train
case "playertrain":
if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1);
InstructionSet[n] = Instructions.PlayerTrain;
diff --git a/source/OpenBveApi/FunctionScripts/Instructions.cs b/source/OpenBveApi/FunctionScripts/Instructions.cs
index 355a66bd00..2e59b542f7 100644
--- a/source/OpenBveApi/FunctionScripts/Instructions.cs
+++ b/source/OpenBveApi/FunctionScripts/Instructions.cs
@@ -17,7 +17,7 @@ public enum Instructions {
SystemHalt, SystemValue, SystemDelta,
StackCopy, StackSwap,
MathRandom, MathRandomInt,
- TimeSecondsSinceMidnight, TimeHourDigit, TimeMinuteDigit, TimeSecondDigit, CameraDistance, CameraXDistance, CameraYDistance, CameraZDistance, CameraView, CameraCar,
+ TimeSecondsSinceMidnight, TimeHourDigit, TimeMinuteDigit, TimeSecondDigit, CameraDistance, CameraXDistance, CameraYDistance, CameraZDistance,CameraView,
TrainCars, TrainCarNumber, TrainDestination, PlayerTrain, TrainLength,
TrainSpeed, TrainSpeedometer, TrainAcceleration, TrainAccelerationMotor,
diff --git a/source/OpenBveApi/Interface/Input/InputDevice.cs b/source/OpenBveApi/Interface/Input/InputDevice.cs
index 6d1bb7c790..64dc837c38 100644
--- a/source/OpenBveApi/Interface/Input/InputDevice.cs
+++ b/source/OpenBveApi/Interface/Input/InputDevice.cs
@@ -19,7 +19,7 @@ public class InputEventArgs : EventArgs
/// Control's information
public InputEventArgs(InputControl control)
{
- Control = control;
+ this.Control = control;
}
///
@@ -232,7 +232,7 @@ public static void LoadPlugins(FileSystem.FileSystem fileSystem)
Assembly Plugin;
try
{
- Plugin = Assembly.LoadFile(File);
+ Plugin = Assembly.LoadFrom(File);
}
catch
{
diff --git a/source/OpenBveApi/Math/Vectors/Vector3.cs b/source/OpenBveApi/Math/Vectors/Vector3.cs
index a37d5453ea..9d9b5a98dd 100644
--- a/source/OpenBveApi/Math/Vectors/Vector3.cs
+++ b/source/OpenBveApi/Math/Vectors/Vector3.cs
@@ -1,3 +1,4 @@
+using System;
using System.Globalization;
using OpenBveApi.World;
// ReSharper disable UnusedMember.Global
diff --git a/source/OpenBveApi/Objects/Helpers/MeshBuilder.cs b/source/OpenBveApi/Objects/Helpers/MeshBuilder.cs
index 404c1be8b7..3d54a2fed7 100644
--- a/source/OpenBveApi/Objects/Helpers/MeshBuilder.cs
+++ b/source/OpenBveApi/Objects/Helpers/MeshBuilder.cs
@@ -39,11 +39,6 @@ public MeshBuilder(Hosts.HostInterface Host)
/// Applies the MeshBuilder's data to a StaticObject
public void Apply(ref StaticObject Object, bool EnableHacks = false, bool IgnoreW = true)
{
- if (Vertices.Count == 0)
- {
- return;
- }
-
if (TransformMatrix != Matrix4D.NoTransformation)
{
for (int i = 0; i < Vertices.Count; i++)
diff --git a/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject/AnimatedObject.cs b/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject/AnimatedObject.cs
index e2afba0157..d367e317a8 100644
--- a/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject/AnimatedObject.cs
+++ b/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject/AnimatedObject.cs
@@ -719,7 +719,6 @@ public void Update(AbstractTrain Train, int CarIndex, double TrackPosition, Vect
double dz = -Camera.Alignment.Position.Z;
Vector3 add = Camera.AbsolutePosition + dx * Camera.AbsoluteSide + dy * Camera.AbsoluteUp + dz * Camera.AbsoluteDirection;
internalObject.Translation = Matrix4D.CreateTranslation(add.X, add.Y, -add.Z);
- internalObject.WorldPosition = add;
}
else
{
@@ -728,7 +727,6 @@ public void Update(AbstractTrain Train, int CarIndex, double TrackPosition, Vect
// translate
internalObject.Translation = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z);
- internalObject.WorldPosition = Position;
}
if (ColorFunction != null && Colors != null)
diff --git a/source/OpenBveApi/Objects/ObjectTypes/UnifiedObject.cs b/source/OpenBveApi/Objects/ObjectTypes/UnifiedObject.cs
index a628858d01..c768351ce6 100644
--- a/source/OpenBveApi/Objects/ObjectTypes/UnifiedObject.cs
+++ b/source/OpenBveApi/Objects/ObjectTypes/UnifiedObject.cs
@@ -8,7 +8,9 @@ public abstract class UnifiedObject
{
/// Creates the object within the worldspace without using track based transforms
/// The world position
- /// The parameters to use when creating the object
+ /// The track distance at which this is displayed by the renderer
+ /// The track distance at which this hidden by the renderer
+ /// The absolute track position at which this object is placed
public void CreateObject(Vector3 Position, ObjectCreationParameters Parameters)
{
CreateObject(Position, Transformation.NullTransformation, Transformation.NullTransformation, Parameters);
@@ -17,7 +19,9 @@ public void CreateObject(Vector3 Position, ObjectCreationParameters Parameters)
/// Creates the object within the worldspace using a single track based transforms
/// The world position
/// The world transformation to apply (e.g. ground, rail)
- /// The parameters to use when creating the object
+ /// The track distance at which this is displayed by the renderer
+ /// The track distance at which this hidden by the renderer
+ /// The absolute track position at which this object is placed
public void CreateObject(Vector3 Position, Transformation WorldTransformation, ObjectCreationParameters Parameters)
{
CreateObject(Position, WorldTransformation, Transformation.NullTransformation, Parameters);
@@ -27,7 +31,9 @@ public void CreateObject(Vector3 Position, Transformation WorldTransformation, O
/// The world position
/// The world transformation to apply (e.g. ground, rail)
/// The local transformation to apply in order to rotate the model
- /// The parameters to use when creating the object
+ /// The track distance at which this is displayed by the renderer
+ /// The track distance at which this hidden by the renderer
+ /// The absolute track position at which this object is placed
public abstract void CreateObject(Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, ObjectCreationParameters Parameters);
/// Call this method to optimize the object
diff --git a/source/OpenBveApi/OpenBveApi.csproj b/source/OpenBveApi/OpenBveApi.csproj
index c75e05d797..29d2f7ef65 100644
--- a/source/OpenBveApi/OpenBveApi.csproj
+++ b/source/OpenBveApi/OpenBveApi.csproj
@@ -70,12 +70,9 @@
..\..\packages\CS-Script.lib.3.30.3\lib\net46\CSScriptLibrary.dll
-
- ..\..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\netstandard2.0\Microsoft.Bcl.AsyncInterfaces.dll
-
-
- ..\..\packages\SharpCompress.0.48.0\lib\netstandard2.0\SharpCompress.dll
+
+ ..\..\packages\SharpCompress.0.32.2\lib\net461\SharpCompress.dll
@@ -93,11 +90,8 @@
-
- ..\..\packages\System.Text.Encoding.CodePages.8.0.0\lib\netstandard2.0\System.Text.Encoding.CodePages.dll
-
-
- ..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
+
+ ..\..\packages\System.Text.Encoding.CodePages.6.0.0\lib\net461\System.Text.Encoding.CodePages.dll
..\..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll
diff --git a/source/OpenBveApi/Packages/Packages.Loksim3D.cs b/source/OpenBveApi/Packages/Packages.Loksim3D.cs
index 0fafa37c50..0d1afcf5de 100644
--- a/source/OpenBveApi/Packages/Packages.Loksim3D.cs
+++ b/source/OpenBveApi/Packages/Packages.Loksim3D.cs
@@ -67,6 +67,7 @@ internal static Package Parse(XmlDocument currentXML, string fileName, ref strin
}
break;
case "DeleteFiles":
+ break;
case "DeinstallPackages":
break;
}
diff --git a/source/OpenBveApi/Packages/Packages.cs b/source/OpenBveApi/Packages/Packages.cs
index 2d525b710c..b6a5d50f28 100644
--- a/source/OpenBveApi/Packages/Packages.cs
+++ b/source/OpenBveApi/Packages/Packages.cs
@@ -239,7 +239,7 @@ public static void ExtractPackage(Package currentPackage, string extractionDirec
using (Stream stream = File.OpenRead(currentPackage.PackageFile))
{
- var reader = ArchiveFactory.OpenArchive(stream);
+ var reader = ArchiveFactory.Open(stream);
List PackageFiles = new List();
j = reader.Entries.Count();
foreach (var archiveEntry in reader.Entries)
@@ -256,7 +256,7 @@ public static void ExtractPackage(Package currentPackage, string extractionDirec
else
{
//Extract everything else, preserving directory structure
- archiveEntry.WriteToDirectory(extractionDirectory, new ExtractionOptions(true, true));
+ archiveEntry.WriteToDirectory(extractionDirectory, new ExtractionOptions { ExtractFullPath = true, Overwrite = true });
//We don't want to add directories to the list of files
if (!archiveEntry.IsDirectory)
{
@@ -308,7 +308,7 @@ public static void CreatePackage(Package currentPackage, CompressionType compres
string fp = string.Empty;
try
{
- using (FileStream zip = File.OpenWrite(packageFile))
+ using (var zip = File.OpenWrite(packageFile))
{
ArchiveType type;
SharpCompress.Common.CompressionType compression;
@@ -331,7 +331,7 @@ public static void CreatePackage(Package currentPackage, CompressionType compres
compression = SharpCompress.Common.CompressionType.LZMA;
break;
}
- using (var zipWriter = WriterFactory.OpenWriter(zip, type, new WriterOptions(compression)))
+ using (var zipWriter = WriterFactory.Open(zip, type, compression))
{
if (packageFiles != null && packageFiles.Count > 0)
{
@@ -455,14 +455,14 @@ public static Package ReadPackage(string packageFile)
{
try
{
- var reader = ReaderFactory.OpenReader(stream);
+ var reader = ReaderFactory.Open(stream);
while (reader.MoveToNextEntry())
{
//Search for the package.xml file- This must be located in the archive root
if (reader.Entry.Key.ToLowerInvariant() == "package.xml" && !InfoFound)
{
- reader.WriteEntryToDirectory(TempDirectory, new ExtractionOptions(true, true));
+ reader.WriteEntryToDirectory(TempDirectory, new ExtractionOptions { ExtractFullPath = true, Overwrite = true });
//Load the XML file
InfoFound = true;
XmlSerializer listReader = new XmlSerializer(typeof(SerializedPackage));
@@ -474,7 +474,7 @@ public static Package ReadPackage(string packageFile)
if (reader.Entry.Key.ToLowerInvariant() == "packageinfo.xml" &&
packageFile.ToLowerInvariant().EndsWith(".l3dpack") && !InfoFound)
{
- reader.WriteEntryToDirectory(TempDirectory, new ExtractionOptions(true, true));
+ reader.WriteEntryToDirectory(TempDirectory, new ExtractionOptions { ExtractFullPath = true, Overwrite = true });
//Load the XML file
try
{
@@ -496,7 +496,7 @@ public static Package ReadPackage(string packageFile)
if (reader.Entry.Key.ToLowerInvariant() == ImageFile && currentPackage.PackageImage == null)
{
//Extract the package.png to the uniquely assigned temp directory
- reader.WriteEntryToDirectory(TempDirectory, new ExtractionOptions(true, true));
+ reader.WriteEntryToDirectory(TempDirectory, new ExtractionOptions { ExtractFullPath = true, Overwrite = true });
try
{
packageImage = Image.FromFile(Path.CombineFile(TempDirectory, ImageFile));
@@ -515,7 +515,7 @@ public static Package ReadPackage(string packageFile)
if (reader.Entry.Key.ToLowerInvariant() == "package.rtf")
{
//Extract the package.rtf description file to the uniquely assigned temp directory
- reader.WriteEntryToDirectory(TempDirectory, new ExtractionOptions(true, true));
+ reader.WriteEntryToDirectory(TempDirectory, new ExtractionOptions { ExtractFullPath = true, Overwrite = true });
//PackageDescription.LoadFile(OpenBveApi.Path.CombineFile(TempDirectory, "package.rtf"));
}
diff --git a/source/OpenBveApi/Runtime/Train/AIData.cs b/source/OpenBveApi/Runtime/Train/AIData.cs
index 05a5566f02..e744ab19ed 100644
--- a/source/OpenBveApi/Runtime/Train/AIData.cs
+++ b/source/OpenBveApi/Runtime/Train/AIData.cs
@@ -17,9 +17,9 @@ public class AIData
/// The driver handles.
public AIData(Handles handles)
{
- MyHandles = handles;
- MyResponse = AIResponse.None;
- TimeElapsed = 0;
+ this.MyHandles = handles;
+ this.MyResponse = AIResponse.None;
+ this.TimeElapsed = 0;
}
/// Creates a new instance of this class.
@@ -27,9 +27,9 @@ public AIData(Handles handles)
/// The elapsed time
public AIData(Handles handles, double timeElapsed)
{
- MyHandles = handles;
- MyResponse = AIResponse.None;
- TimeElapsed = timeElapsed;
+ this.MyHandles = handles;
+ this.MyResponse = AIResponse.None;
+ this.TimeElapsed = timeElapsed;
}
/// Gets or sets the driver handles.
diff --git a/source/OpenBveApi/Sounds/Sounds.cs b/source/OpenBveApi/Sounds/Sounds.cs
index c6e670d4e8..0d767e515e 100644
--- a/source/OpenBveApi/Sounds/Sounds.cs
+++ b/source/OpenBveApi/Sounds/Sounds.cs
@@ -10,16 +10,17 @@ namespace OpenBveApi.Sounds {
* Modifications can be made at will.
* ---------------------------------------- */
+ // --- structures ---
+
/// Represents a sound.
- public class Sound
- {
+ public class Sound {
+ // --- members ---
/// The number of samples per second.
- public readonly int SampleRate;
+ private readonly int MySampleRate;
/// The number of bits per sample. Allowed values are 8 or 16.
- public readonly int BitsPerSample;
+ private readonly int MyBitsPerSample;
/// The PCM sound data per channel. For 8 bits per sample, samples are unsigned from 0 to 255. For 16 bits per sample, samples are signed from -32768 to 32767 and in little endian byte order.
- public readonly byte[][] Bytes;
-
+ private readonly byte[][] MyBytes;
// --- constructors ---
/// Creates a new instance of this class.
/// The number of samples per second.
@@ -53,13 +54,22 @@ public Sound(int sampleRate, int bitsPerSample, byte[][] bytes) {
throw new ArgumentException("The data bytes of the channels are of unequal length.");
}
}
- SampleRate = sampleRate;
- BitsPerSample = bitsPerSample;
- Bytes = bytes;
+ MySampleRate = sampleRate;
+ MyBitsPerSample = bitsPerSample;
+ MyBytes = bytes;
}
-
+ // --- properties ---
+ /// Gets the number of samples per second.
+ public int SampleRate => MySampleRate;
+
+ /// Gets the number of bits per sample. Allowed values are 8 or 16.
+ public int BitsPerSample => MyBitsPerSample;
+
+ /// Gets the PCM sound data per channel. For 8 bits per sample, samples are unsigned from 0 to 255. For 16 bits per sample, samples are signed from -32768 to 32767 and in little endian byte order.
+ public byte[][] Bytes => MyBytes;
+
/// Gets the duration of the sound in seconds.
- public double Duration => 8.0 * Bytes[0].Length / BitsPerSample / SampleRate;
+ public double Duration => 8.0 * MyBytes[0].Length / MyBitsPerSample / MySampleRate;
// --- operators ---
/// Checks whether two sound are equal.
@@ -70,13 +80,13 @@ public Sound(int sampleRate, int bitsPerSample, byte[][] bytes) {
if (ReferenceEquals(a, b)) return true;
if (a is null) return false;
if (b is null) return false;
- if (a.SampleRate != b.SampleRate) return false;
- if (a.BitsPerSample != b.BitsPerSample) return false;
- if (a.Bytes.Length != b.Bytes.Length) return false;
- for (int i = 0; i < a.Bytes.Length; i++) {
- if (a.Bytes[i].Length != b.Bytes[i].Length) return false;
- for (int j = 0; j < a.Bytes[i].Length; j++) {
- if (a.Bytes[i][j] != b.Bytes[i][j]) return false;
+ if (a.MySampleRate != b.MySampleRate) return false;
+ if (a.MyBitsPerSample != b.MyBitsPerSample) return false;
+ if (a.MyBytes.Length != b.MyBytes.Length) return false;
+ for (int i = 0; i < a.MyBytes.Length; i++) {
+ if (a.MyBytes[i].Length != b.MyBytes[i].Length) return false;
+ for (int j = 0; j < a.MyBytes[i].Length; j++) {
+ if (a.MyBytes[i][j] != b.MyBytes[i][j]) return false;
}
}
return true;
@@ -89,13 +99,13 @@ public Sound(int sampleRate, int bitsPerSample, byte[][] bytes) {
if (ReferenceEquals(a, b)) return false;
if (a is null) return true;
if (b is null) return true;
- if (a.SampleRate != b.SampleRate) return true;
- if (a.BitsPerSample != b.BitsPerSample) return true;
- if (a.Bytes.Length != b.Bytes.Length) return true;
- for (int i = 0; i < a.Bytes.Length; i++) {
- if (a.Bytes[i].Length != b.Bytes[i].Length) return true;
- for (int j = 0; j < a.Bytes[i].Length; j++) {
- if (a.Bytes[i][j] != b.Bytes[i][j]) return true;
+ if (a.MySampleRate != b.MySampleRate) return true;
+ if (a.MyBitsPerSample != b.MyBitsPerSample) return true;
+ if (a.MyBytes.Length != b.MyBytes.Length) return true;
+ for (int i = 0; i < a.MyBytes.Length; i++) {
+ if (a.MyBytes[i].Length != b.MyBytes[i].Length) return true;
+ for (int j = 0; j < a.MyBytes[i].Length; j++) {
+ if (a.MyBytes[i][j] != b.MyBytes[i][j]) return true;
}
}
return false;
@@ -108,13 +118,13 @@ public override bool Equals(object obj) {
if (obj is null) return false;
if (!(obj is Sound)) return false;
Sound x = (Sound)obj;
- if (SampleRate != x.SampleRate) return false;
- if (BitsPerSample != x.BitsPerSample) return false;
- if (Bytes.Length != x.Bytes.Length) return false;
- for (int i = 0; i < Bytes.Length; i++) {
- if (Bytes[i].Length != x.Bytes[i].Length) return false;
- for (int j = 0; j < Bytes[i].Length; j++) {
- if (Bytes[i][j] != x.Bytes[i][j]) return false;
+ if (MySampleRate != x.MySampleRate) return false;
+ if (MyBitsPerSample != x.MyBitsPerSample) return false;
+ if (MyBytes.Length != x.MyBytes.Length) return false;
+ for (int i = 0; i < MyBytes.Length; i++) {
+ if (MyBytes[i].Length != x.MyBytes[i].Length) return false;
+ for (int j = 0; j < MyBytes[i].Length; j++) {
+ if (MyBytes[i][j] != x.MyBytes[i][j]) return false;
}
}
return true;
@@ -131,32 +141,32 @@ public byte[] GetMonoMix()
* Convert integer samples to floating-point samples.
*/
float[][] samples;
- if (Bytes.Length == 1 || Bytes[0].Length == 0)
+ if (MyBytes.Length == 1 || MyBytes[0].Length == 0)
{
- return Bytes[0];
+ return MyBytes[0];
}
switch (BitsPerSample)
{
case 8:
- samples = new float[Bytes.Length][];
- for (int i = 0; i < Bytes.Length; i++)
+ samples = new float[MyBytes.Length][];
+ for (int i = 0; i < MyBytes.Length; i++)
{
- samples[i] = new float[Bytes[i].Length];
- for (int j = 0; j < Bytes[i].Length; j++)
+ samples[i] = new float[MyBytes[i].Length];
+ for (int j = 0; j < MyBytes[i].Length; j++)
{
- byte value = Bytes[i][j];
+ byte value = MyBytes[i][j];
samples[i][j] = (value - 128.0f) / (value < 128 ? 128.0f : 127.0f);
}
}
break;
case 16:
- samples = new float[Bytes.Length][];
- for (int i = 0; i < Bytes.Length; i++)
+ samples = new float[MyBytes.Length][];
+ for (int i = 0; i < MyBytes.Length; i++)
{
- samples[i] = new float[Bytes[i].Length >> 1];
- for (int j = 0; j + 1 < Bytes[i].Length; j += 2)
+ samples[i] = new float[MyBytes[i].Length >> 1];
+ for (int j = 0; j + 1 < MyBytes[i].Length; j += 2)
{
- short value = (short)(ushort)(Bytes[i][j] | (Bytes[i][j + 1] << 8));
+ short value = (short)(ushort)(MyBytes[i][j] | (MyBytes[i][j + 1] << 8));
samples[i][j >> 1] = value / (value < 0 ? 32768.0f : 32767.0f);
}
}
diff --git a/source/OpenBveApi/System/BaseOptions.OptionsKey.cs b/source/OpenBveApi/System/BaseOptions.OptionsKey.cs
index 9d93fac265..2854a9c98d 100644
--- a/source/OpenBveApi/System/BaseOptions.OptionsKey.cs
+++ b/source/OpenBveApi/System/BaseOptions.OptionsKey.cs
@@ -38,9 +38,6 @@ public enum OptionsKey
NearClipCab,
NearClipBase,
AutoReloadObjects,
- CameraInteriorTransition,
- CameraExteriorTransition,
- CameraTransitionSpeed,
// Quality
Interpolation,
AnisotropicFilteringLevel,
@@ -56,7 +53,6 @@ public enum OptionsKey
ShadowStrength,
ShadowBias,
ShadowNormalBias,
- ShadowFilterCascades,
LightAzimuth,
LightElevation,
diff --git a/source/OpenBveApi/System/BaseOptions.cs b/source/OpenBveApi/System/BaseOptions.cs
index 135f660222..f295d687b3 100644
--- a/source/OpenBveApi/System/BaseOptions.cs
+++ b/source/OpenBveApi/System/BaseOptions.cs
@@ -1,4 +1,3 @@
-using OpenBveApi.Colors;
using OpenBveApi.Graphics;
using OpenBveApi.Objects;
using OpenBveApi.Routes;
@@ -91,11 +90,9 @@ public abstract class BaseOptions
/// Shadow darkness strength. 0.0 = invisible, 1.0 = full black.
public double ShadowStrength = 0.7;
/// Shadow bias to prevent shadow acne.
- public double ShadowBias = 0.000005; // default synced to 0.000005
+ public double ShadowBias = 0.000050; // default synced to 0.000050
/// Shadow normal bias (slope scale multiplier) to perfectly cure acne on curved/thin meshes.
public double ShadowNormalBias = 2.0;
- /// Whether to filter shadow casters per cascade to improve performance.
- public bool ShadowFilterCascades = true;
/// The sun azimuth in degrees
@@ -144,9 +141,6 @@ public abstract class BaseOptions
public double NearClipCab = 0.025;
/// The near clipping plane for the base renderer
public double NearClipBase = 0.2;
- /// The color used by the renderer when issuing GL.Clear()
- /// Not saved
- public Color24 ClearColor = new Color24(170, 170, 170);
/// Saves the options to the specified filename
/// The filename to save the options to
diff --git a/source/OpenBveApi/System/FileSystem.cs b/source/OpenBveApi/System/FileSystem.cs
index fbe2236259..c25d4146b3 100644
--- a/source/OpenBveApi/System/FileSystem.cs
+++ b/source/OpenBveApi/System/FileSystem.cs
@@ -1,12 +1,10 @@
-using Microsoft.Win32;
-using OpenBveApi.Hosts;
-using OpenBveApi.Interface;
using System;
using System.IO;
-using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
+using Microsoft.Win32;
+using OpenBveApi.Hosts;
// ReSharper disable PossibleNullReferenceException
// ReSharper disable AssignNullToNotNullAttribute
@@ -508,90 +506,5 @@ public void AppendToLogFile(string text, bool addTimestamp = true) {
// ignored
}
}
-
- /// Gets the absolute Railway folder for a given route file
- /// The absolute on-disk path of the railway folder
- public string GetRailwayFolder(string routeFile, string startupPath)
- {
- try
- {
- string currentFolder = Path.GetDirectoryName(routeFile);
-
- while (true)
- {
- string Subfolder = Path.CombineDirectory(currentFolder, "Railway");
- if (Directory.Exists(Subfolder))
- {
- if (Directory.EnumerateDirectories(Subfolder).Any() || Directory.EnumerateFiles(Subfolder).Any())
- {
- //HACK: Ignore completely empty directories
- //Doesn't handle wrong directories, or those with stuff missing, TODO.....
- AppendToLogFile(Subfolder + " : Railway folder found.");
- return Subfolder;
- }
-
- AppendToLogFile(Subfolder + " : Railway folder candidate rejected- Directory empty.");
- }
-
- if (currentFolder == null) continue;
- DirectoryInfo directoryInfo = Directory.GetParent(currentFolder);
- if (directoryInfo == null) break;
- currentFolder = directoryInfo.FullName;
- }
- }
- catch
- {
- // ignored
- }
-
- // If the Route, Object and Sound folders exist, but are not in a railway folder.....
- try
- {
- string currentFolder = Path.GetDirectoryName(routeFile);
- if (currentFolder == null)
- {
- // Unlikely to work, but attempt to make the best of it
- AppendToLogFile("The route file appears to be stored on a root path- Returning the " + Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "program", "title" }) + " startup path.");
- return Application.StartupPath;
- }
- string candidate = null;
- while (true)
- {
- string routeFolder = Path.CombineDirectory(currentFolder, "Route");
- string objectFolder = Path.CombineDirectory(currentFolder, "Object");
- string soundFolder = Path.CombineDirectory(currentFolder, "Sound");
- if (Directory.Exists(routeFolder) && Directory.Exists(objectFolder) && Directory.Exists(soundFolder))
- {
- AppendToLogFile(currentFolder + " : Railway folder found.");
- return currentFolder;
- }
-
- if (Directory.Exists(routeFolder) && Directory.Exists(objectFolder))
- {
- candidate = currentFolder;
- }
-
- DirectoryInfo directoryInfo = Directory.GetParent(currentFolder);
- if (directoryInfo == null)
- {
- if (candidate != null)
- {
- AppendToLogFile(currentFolder + " : The best candidate for the Railway folder has been selected- Sound folder not detected.");
- return candidate;
- }
-
- break;
- }
-
- currentFolder = directoryInfo.FullName;
- }
- }
- catch
- {
- // ignored
- }
- AppendToLogFile("No Railway folder found- Returning the " + Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "program", "title" }) + " startup path.");
- return startupPath;
- }
}
}
diff --git a/source/OpenBveApi/System/Text.cs b/source/OpenBveApi/System/Text.cs
index 285a4cdb09..ed29b15a10 100644
--- a/source/OpenBveApi/System/Text.cs
+++ b/source/OpenBveApi/System/Text.cs
@@ -109,10 +109,6 @@ public static bool IsJapanese(this string Name) {
/// The string for which all line-endings should be converted to CR-LF
/// The converted StringBuilder
public static string ConvertNewlinesToCrLf(this string Text) {
- if (string.IsNullOrEmpty(Text))
- {
- return string.Empty;
- }
StringBuilder Builder = new StringBuilder();
for (int i = 0; i < Text.Length; i++) {
int a = char.ConvertToUtf32(Text, i);
diff --git a/source/OpenBveApi/Textures/Textures.ClipRegion.cs b/source/OpenBveApi/Textures/Textures.ClipRegion.cs
index b2db977b0e..39e79ec0d1 100644
--- a/source/OpenBveApi/Textures/Textures.ClipRegion.cs
+++ b/source/OpenBveApi/Textures/Textures.ClipRegion.cs
@@ -7,14 +7,27 @@ namespace OpenBveApi.Textures
/// Represents a region in a texture to be extracted.
public class TextureClipRegion
{
+ // --- members ---
+ /// The left coordinate.
+ private readonly int MyLeft;
+ /// The top coordinate.
+ private readonly int MyTop;
+ /// The width.
+ private readonly int MyWidth;
+ /// The height.
+ private readonly int MyHeight;
+ // --- properties ---
/// Gets the left coordinate.
- public readonly int Left;
+ public int Left => MyLeft;
+
/// Gets the top coordinate.
- public readonly int Top;
+ public int Top => MyTop;
+
/// Gets the width.
- public readonly int Width;
+ public int Width => MyWidth;
+
/// Gets the height.
- public readonly int Height;
+ public int Height => MyHeight;
// --- constructors ---
/// Creates a new clip region.
@@ -36,10 +49,10 @@ public TextureClipRegion(int left, int top, int width, int height)
throw new ArgumentException("The width or height are non-positive.");
}
- Left = left;
- Top = top;
- Width = width;
- Height = height;
+ MyLeft = left;
+ MyTop = top;
+ MyWidth = width;
+ MyHeight = height;
}
// --- operators ---
@@ -52,10 +65,10 @@ public TextureClipRegion(int left, int top, int width, int height)
if (ReferenceEquals(a, b)) return true;
if (a is null) return false;
if (b is null) return false;
- if (a.Left != b.Left) return false;
- if (a.Top != b.Top) return false;
- if (a.Width != b.Width) return false;
- if (a.Height != b.Height) return false;
+ if (a.MyLeft != b.MyLeft) return false;
+ if (a.MyTop != b.MyTop) return false;
+ if (a.MyWidth != b.MyWidth) return false;
+ if (a.MyHeight != b.MyHeight) return false;
return true;
}
@@ -68,10 +81,10 @@ public TextureClipRegion(int left, int top, int width, int height)
if (ReferenceEquals(a, b)) return false;
if (a is null) return true;
if (b is null) return true;
- if (a.Left != b.Left) return true;
- if (a.Top != b.Top) return true;
- if (a.Width != b.Width) return true;
- if (a.Height != b.Height) return true;
+ if (a.MyLeft != b.MyLeft) return true;
+ if (a.MyTop != b.MyTop) return true;
+ if (a.MyWidth != b.MyWidth) return true;
+ if (a.MyHeight != b.MyHeight) return true;
return false;
}
@@ -84,10 +97,10 @@ public override bool Equals(object obj)
if (obj is null) return false;
if (!(obj is TextureClipRegion)) return false;
TextureClipRegion x = (TextureClipRegion) obj;
- if (Left != x.Left) return false;
- if (Top != x.Top) return false;
- if (Width != x.Width) return false;
- if (Height != x.Height) return false;
+ if (MyLeft != x.MyLeft) return false;
+ if (MyTop != x.MyTop) return false;
+ if (MyWidth != x.MyWidth) return false;
+ if (MyHeight != x.MyHeight) return false;
return true;
}
}
diff --git a/source/OpenBveApi/Textures/Textures.Functions.cs b/source/OpenBveApi/Textures/Textures.Functions.cs
index db5f18ddda..6449a27fce 100644
--- a/source/OpenBveApi/Textures/Textures.Functions.cs
+++ b/source/OpenBveApi/Textures/Textures.Functions.cs
@@ -52,15 +52,8 @@ internal static Texture ExtractClipRegion(Texture texture, TextureClipRegion reg
throw new ArgumentException();
}
int width = texture.Width;
- byte[] bytes;
- if (texture.Bytes == null)
- {
- texture.Origin.GetTexture(out texture);
- }
-
- bytes = texture.Bytes;
-
- int clipLeft = region.Left;
+ byte[] bytes = texture.Bytes;
+ int clipLeft = region.Left;
int clipTop = region.Top;
int clipWidth = region.Width;
int clipHeight = region.Height;
@@ -187,7 +180,6 @@ internal static Texture ApplyTransparentColor(Texture texture, Color24? color)
newFrames[i] = ApplyTransparentColor(texture.Bytes, texture.PixelFormat, texture.Width, texture.Height, color.Value, ref usedTransparentColor);
texture.CurrentFrame++;
}
- texture.CurrentFrame = 0;
if (usedTransparentColor)
{
@@ -216,57 +208,33 @@ private static byte[] ApplyTransparentTexture(byte[] source, PixelFormat pixelFo
case PixelFormat.Grayscale:
for (int i = 0; i < source.Length; i++, targetIndex += 4)
{
-
+ Color24 c = transparencyTexture.GetPixel(i);
target[targetIndex] = source[i];
target[targetIndex + 1] = source[i];
target[targetIndex + 2] = source[i];
- if (transparencyTexture.PixelFormat == PixelFormat.Grayscale || transparencyTexture.PixelFormat == PixelFormat.RGB)
- {
- Color24 c = transparencyTexture.GetPixel(i);
- target[targetIndex + 3] = (byte)(255 * c.GetBrightness());
- }
- else
- {
- target[i + 3] = System.Math.Min(source[i + 1], transparencyTexture.GetAlpha(i));
- }
-
+ target[targetIndex + 3] = (byte)(255 * c.GetBrightness());
}
break;
case PixelFormat.GrayscaleAlpha:
for (int i = 0; i < source.Length; i += 2, targetIndex += 4)
{
int pix = i / 2;
+ Color24 c = transparencyTexture.GetPixel(pix);
target[targetIndex] = source[i];
target[targetIndex + 1] = source[i];
target[targetIndex + 2] = source[i];
- if (transparencyTexture.PixelFormat == PixelFormat.Grayscale || transparencyTexture.PixelFormat == PixelFormat.RGB)
- {
- Color24 c = transparencyTexture.GetPixel(pix);
- target[targetIndex + 3] = (byte)(255 * c.GetBrightness());
- }
- else
- {
- target[i + 3] = System.Math.Min(source[i + 1], transparencyTexture.GetAlpha(pix));
- }
+ target[targetIndex + 3] = (byte)(255 * c.GetBrightness());
}
break;
case PixelFormat.RGB:
for (int i = 0; i < source.Length; i += 3, targetIndex += 4)
{
int pix = i / 3;
+ Color24 c = transparencyTexture.GetPixel(pix);
target[targetIndex] = source[i];
target[targetIndex + 1] = source[i + 1];
target[targetIndex + 2] = source[i + 2];
- if (transparencyTexture.PixelFormat == PixelFormat.Grayscale ||
- transparencyTexture.PixelFormat == PixelFormat.RGB)
- {
- Color24 c = transparencyTexture.GetPixel(pix);
- target[targetIndex + 3] = (byte)(255 * c.GetBrightness());
- }
- else
- {
- target[i + 3] = System.Math.Min(source[i + 3], transparencyTexture.GetAlpha(pix));
- }
+ target[targetIndex + 3] = (byte)(255 * c.GetBrightness());
}
break;
case PixelFormat.RGBAlpha:
@@ -279,19 +247,11 @@ private static byte[] ApplyTransparentTexture(byte[] source, PixelFormat pixelFo
for (int i = 4; i < source.Length; i += 4)
{
int pix = i / 4;
+ Color24 c = transparencyTexture.GetPixel(pix);
target[i + 0] = source[i + 0];
target[i + 1] = source[i + 1];
target[i + 2] = source[i + 2];
- if (transparencyTexture.PixelFormat == PixelFormat.Grayscale || transparencyTexture.PixelFormat == PixelFormat.RGB)
- {
- Color24 c = transparencyTexture.GetPixel(pix);
- target[i + 3] = (byte)(255 * c.GetBrightness());
- }
- else
- {
- target[i + 3] = System.Math.Min(source[i + 3], transparencyTexture.GetAlpha(pix));
- }
-
+ target[i + 3] = (byte)(255 * c.GetBrightness());
}
break;
}
diff --git a/source/OpenBveApi/Textures/Textures.TextureParameters.cs b/source/OpenBveApi/Textures/Textures.TextureParameters.cs
index 468ff19726..605e4f97b6 100644
--- a/source/OpenBveApi/Textures/Textures.TextureParameters.cs
+++ b/source/OpenBveApi/Textures/Textures.TextureParameters.cs
@@ -9,11 +9,20 @@ public class TextureParameters
{
// --- members ---
/// The region in the texture to be extracted, or a null reference for the entire texture.
- public readonly TextureClipRegion ClipRegion;
+ private readonly TextureClipRegion myClipRegion;
/// The color in the texture that should become transparent, or a null reference for no transparent color.
- public readonly Color24? TransparentColor;
+ private readonly Color24? myTransparentColor;
/// The alpha channel texture
- public Texture TransparencyTexture;
+ private readonly Texture myTransparencyTexture;
+ // --- properties ---
+ /// Gets the region in the texture to be extracted, or a null reference for the entire texture.
+ public TextureClipRegion ClipRegion => myClipRegion;
+
+ /// Gets the color in the texture that should become transparent, or a null reference for no transparent color.
+ public Color24? TransparentColor => myTransparentColor;
+
+ /// Gets the separate alpha channel texture
+ public Texture TransparencyTexture => myTransparencyTexture;
/// Texture parameters, which apply no changes.
public static TextureParameters NoChange = new TextureParameters(null, null);
@@ -24,9 +33,9 @@ public class TextureParameters
/// The texture to be applied to the alpha channel
public TextureParameters(TextureClipRegion clipRegion, Color24? transparentColor, Texture transparencyTexture = null)
{
- ClipRegion = clipRegion;
- TransparentColor = transparentColor;
- TransparencyTexture = transparencyTexture;
+ myClipRegion = clipRegion;
+ myTransparentColor = transparentColor;
+ myTransparencyTexture = transparencyTexture;
}
// --- operators ---
@@ -39,8 +48,8 @@ public TextureParameters(TextureClipRegion clipRegion, Color24? transparentColor
if (ReferenceEquals(a, b)) return true;
if (a is null) return false;
if (b is null) return false;
- if (a.ClipRegion != b.ClipRegion) return false;
- if (a.TransparentColor != b.TransparentColor) return false;
+ if (a.myClipRegion != b.myClipRegion) return false;
+ if (a.myTransparentColor != b.myTransparentColor) return false;
return true;
}
@@ -53,8 +62,8 @@ public TextureParameters(TextureClipRegion clipRegion, Color24? transparentColor
if (ReferenceEquals(a, b)) return false;
if (a is null) return true;
if (b is null) return true;
- if (a.ClipRegion != b.ClipRegion) return true;
- if (a.TransparentColor != b.TransparentColor) return true;
+ if (a.myClipRegion != b.myClipRegion) return true;
+ if (a.myTransparentColor != b.myTransparentColor) return true;
return false;
}
@@ -67,8 +76,8 @@ public override bool Equals(object obj)
if (obj is null) return false;
if (!(obj is TextureParameters)) return false;
TextureParameters x = (TextureParameters) obj;
- if (ClipRegion != x.ClipRegion) return false;
- if (TransparentColor != x.TransparentColor) return false;
+ if (myClipRegion != x.myClipRegion) return false;
+ if (myTransparentColor != x.myTransparentColor) return false;
return true;
}
}
diff --git a/source/OpenBveApi/Textures/Textures.TransparencyType.cs b/source/OpenBveApi/Textures/Textures.TransparencyType.cs
index 318dd63684..b4efe25af0 100644
--- a/source/OpenBveApi/Textures/Textures.TransparencyType.cs
+++ b/source/OpenBveApi/Textures/Textures.TransparencyType.cs
@@ -8,8 +8,6 @@ public enum TextureTransparencyType
/// All pixels in the texture are either fully opaque or fully transparent.
Partial = 2,
/// Some pixels in the texture are neither fully opaque nor fully transparent.
- Alpha = 3,
- /// All pixels in the texture are fully transparent
- Transparent
+ Alpha = 3
}
}
diff --git a/source/OpenBveApi/Textures/Textures.cs b/source/OpenBveApi/Textures/Textures.cs
index 6e029c0f54..7e78be0188 100644
--- a/source/OpenBveApi/Textures/Textures.cs
+++ b/source/OpenBveApi/Textures/Textures.cs
@@ -11,13 +11,13 @@ namespace OpenBveApi.Textures {
public class Texture
{
/// The size of the texture in pixels
- public Vector2 Size;
+ private Vector2 MySize;
/// The pixel format of the texture.
- public readonly PixelFormat PixelFormat;
+ private readonly PixelFormat MyPixelFormat;
/// The texture data. Pixels are stored row-based from top to bottom, and within a row from left to right. For 32 bits per pixel, four bytes are used in the order red, green, blue and alpha.
private readonly byte[][] MyBytes;
/// The restricted color palette for this texture, or a null reference if the texture was 24/ 32 bit originally
- public readonly Color24[] Palette;
+ private readonly Color24[] MyPalette;
/// Whether the texture is invalid and should be ignored
/// Set when loading the texture fails unexpectedly
public bool Ignore;
@@ -49,7 +49,7 @@ public class Texture
/// The frame
public Color24 GetPixel(int pix, int frame = 0)
{
- if (pix > Size.X * Size.Y)
+ if (pix > MySize.X * MySize.Y)
{
throw new ArgumentException("Pixel is outside the bounds of the image");
}
@@ -59,39 +59,20 @@ public Color24 GetPixel(int pix, int frame = 0)
{
case PixelFormat.Grayscale:
firstByte = pix;
- return new Color24(MyBytes[frame][firstByte], MyBytes[frame][firstByte], MyBytes[frame][firstByte]);
+ break;
case PixelFormat.GrayscaleAlpha:
firstByte = 2 * pix;
- return new Color24(MyBytes[frame][firstByte], MyBytes[frame][firstByte], MyBytes[frame][firstByte]);
+ break;
case PixelFormat.RGB:
firstByte = 3 * pix;
- return new Color24(MyBytes[frame][firstByte], MyBytes[frame][firstByte + 1], MyBytes[frame][firstByte + 2]);
+ break;
case PixelFormat.RGBAlpha:
firstByte = 4 * pix;
- return new Color24(MyBytes[frame][firstByte], MyBytes[frame][firstByte + 1], MyBytes[frame][firstByte + 2]);
+ break;
default:
throw new Exception("Unable to get a pixel value with invalid data.");
}
- }
-
- /// Gets the alpha value of the given pixel
- /// The pixel index
- /// The frame
- ///
- public byte GetAlpha(int pix, int frame = 0)
- {
- switch (PixelFormat)
- {
- case PixelFormat.Grayscale:
- case PixelFormat.RGB:
- return 255;
- case PixelFormat.GrayscaleAlpha:
- return MyBytes[frame][2 * pix + 1];
- case PixelFormat.RGBAlpha:
- return MyBytes[frame][4 * pix + 3];
- default:
- return 255;
- }
+ return new Color24(MyBytes[frame][firstByte], MyBytes[frame][firstByte + 1], MyBytes[frame][firstByte + 2]);
}
/// Creates a new instance of this class.
@@ -117,12 +98,12 @@ public Texture(int width, int height, PixelFormat pixelFormat, byte[] bytes, Col
this.Origin = new ByteArrayOrigin(width, height, bytes);
this.MyOpenGlTextures = new OpenGlTexture[1][];
this.MyOpenGlTextures[0] = new[] {new OpenGlTexture(), new OpenGlTexture(), new OpenGlTexture(), new OpenGlTexture()};
- this.Size.X = width;
- this.Size.Y = height;
- this.PixelFormat = pixelFormat;
+ this.MySize.X = width;
+ this.MySize.Y = height;
+ this.MyPixelFormat = pixelFormat;
this.MyBytes = new byte[1][];
this.MyBytes[0] = bytes;
- this.Palette = palette;
+ this.MyPalette = palette;
}
/// Creates a new instance of this class.
@@ -147,11 +128,11 @@ public Texture(int width, int height, PixelFormat pixelFormat, byte[][] bytes, d
}
Origin = new ByteArrayOrigin(width, height, bytes, frameInterval);
- Size.X = width;
- Size.Y = height;
- PixelFormat = pixelFormat;
+ MySize.X = width;
+ MySize.Y = height;
+ MyPixelFormat = pixelFormat;
MyBytes = bytes;
- Palette = null;
+ MyPalette = null;
MultipleFrames = true;
FrameInterval = frameInterval;
TotalFrames = bytes.Length;
@@ -169,8 +150,6 @@ public Texture(int width, int height, PixelFormat pixelFormat, byte[][] bytes, d
public Texture(string path, TextureParameters parameters, Hosts.HostInterface currentHost)
{
Origin = new PathOrigin(path, parameters, currentHost);
- Origin.GetTexture(out Texture t);
- PixelFormat = t.PixelFormat;
MyOpenGlTextures = new OpenGlTexture[1][];
MyOpenGlTextures[0] = new[] {new OpenGlTexture(), new OpenGlTexture(), new OpenGlTexture(), new OpenGlTexture()};
@@ -216,29 +195,37 @@ public Texture(TextureOrigin origin)
/// Gets the width of the texture in pixels.
public int Width
{
- get => (int)Size.X;
- set => Size.X = value;
+ get => (int)MySize.X;
+ set => MySize.X = value;
}
/// Gets the height of the texture in pixels.
public int Height
{
- get => (int)Size.Y;
- set => Size.Y = value;
+ get => (int)MySize.Y;
+ set => MySize.Y = value;
+ }
+
+ /// Gets the size of the texture in pixels
+ public Vector2 Size
+ {
+ get => MySize;
+ set => MySize = value;
}
-
+
/// Gets the aspect ratio of the texture
- public double AspectRatio => Size.X / Size.Y;
-
+ public double AspectRatio => MySize.X / MySize.Y;
+
+ /// Gets the pixel format.
+ public PixelFormat PixelFormat => MyPixelFormat;
+
+ /// Gets the restricted color palette for this texture, or a null reference if not applicable
+ public Color24[] Palette => MyPalette;
+
/// Gets the texture data. Pixels are stored row-based from top to bottom, and within a row from left to right. For 32 bits per pixel, four bytes are used in the order red, green, blue and alpha.
public byte[] Bytes
{
get
{
- if (MyBytes == null && Origin != null)
- {
- Origin.GetTexture(out Texture t);
- return t.Bytes;
- }
if (MultipleFrames == false)
{
return MyBytes[0];
@@ -272,8 +259,9 @@ public OpenGlTexture[] OpenGlTextures
if (b is null) return false;
if (a.MultipleFrames != b.MultipleFrames) return false;
if (a.Origin != b.Origin) return false;
- if (a.Size != b.Size) return false;
- if (a.PixelFormat != b.PixelFormat) return false;
+ if (a.MySize.X != b.MySize.X) return false;
+ if (a.MySize.Y != b.MySize.Y) return false;
+ if (a.MyPixelFormat != b.MyPixelFormat) return false;
if (a.MyBytes.Length != b.MyBytes.Length) return false;
for (int i = 0; i < a.MyBytes.Length; i++)
{
@@ -293,8 +281,9 @@ public OpenGlTexture[] OpenGlTextures
if (b is null) return true;
if (a.MultipleFrames != b.MultipleFrames) return true;
if (a.Origin != b.Origin) return true;
- if (a.Size != b.Size) return true;
- if (a.PixelFormat != b.PixelFormat) return true;
+ if (a.MySize.X != b.MySize.X) return true;
+ if (a.MySize.Y != b.MySize.Y) return true;
+ if (a.MyPixelFormat != b.MyPixelFormat) return true;
if (a.MyBytes == null)
{
return b.MyBytes != null;
@@ -317,8 +306,9 @@ public override bool Equals(object obj)
if (!(obj is Texture x)) return false;
if (MultipleFrames != x.MultipleFrames) return false;
if (Origin != x.Origin) return false;
- if (Size != x.Size) return false;
- if (PixelFormat != x.PixelFormat) return false;
+ if (MySize.X != x.MySize.X) return false;
+ if (MySize.Y != x.MySize.Y) return false;
+ if (MyPixelFormat != x.MyPixelFormat) return false;
if (MyBytes == null)
{
return x.MyBytes == null;
@@ -353,46 +343,30 @@ public TextureTransparencyType GetTransparencyType()
}
knownTransparencyType = true;
- switch (PixelFormat)
+ switch (MyPixelFormat)
{
case PixelFormat.RGB:
transparencyType = TextureTransparencyType.Opaque;
break;
case PixelFormat.RGBAlpha:
- transparencyType = TextureTransparencyType.Opaque;
for (int i = 3; i < this.MyBytes[CurrentFrame].Length; i += 4)
{
-
- switch (MyBytes[CurrentFrame][i])
+ if (this.MyBytes[CurrentFrame][i] != 255)
{
- case 0:
- if (i == 3)
+ for (int j = i; j < this.MyBytes[CurrentFrame].Length; j += 4)
+ {
+ if (this.MyBytes[CurrentFrame][j] != 0 & this.MyBytes[CurrentFrame][j] != 255)
{
- transparencyType = TextureTransparencyType.Transparent;
+ transparencyType = TextureTransparencyType.Alpha;
+ return TextureTransparencyType.Alpha;
}
- else
- {
- if (transparencyType == TextureTransparencyType.Opaque)
- {
- transparencyType = TextureTransparencyType.Partial;
- }
- }
- break;
- case 255:
- if (transparencyType != TextureTransparencyType.Opaque)
- {
- transparencyType = TextureTransparencyType.Partial;
- }
- // nothing
- break;
- default:
- transparencyType = TextureTransparencyType.Alpha;
- return transparencyType;
+ }
+
+ transparencyType = TextureTransparencyType.Partial;
+ return TextureTransparencyType.Partial;
}
}
-
- return transparencyType;
-
+ break;
}
return TextureTransparencyType.Opaque;
}
diff --git a/source/OpenBveApi/app.config b/source/OpenBveApi/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/OpenBveApi/app.config
+++ b/source/OpenBveApi/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/OpenBveApi/packages.config b/source/OpenBveApi/packages.config
index 82cc9c0a41..c9d8226501 100644
--- a/source/OpenBveApi/packages.config
+++ b/source/OpenBveApi/packages.config
@@ -1,14 +1,12 @@
-
-
+
-
-
+
\ No newline at end of file
diff --git a/source/Plugins/Formats.Msts/app.config b/source/Plugins/Formats.Msts/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Formats.Msts/app.config
+++ b/source/Plugins/Formats.Msts/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Formats.OpenBve/Block.cs b/source/Plugins/Formats.OpenBve/Block.cs
index 4dd330866d..04b96797a6 100644
--- a/source/Plugins/Formats.OpenBve/Block.cs
+++ b/source/Plugins/Formats.OpenBve/Block.cs
@@ -178,7 +178,7 @@ public bool TryGetValue(T2 key, ref double value, NumberRange range = NumberRang
value = newValue;
return true;
}
- currentHost.AddMessage(MessageType.Warning, false, "Value " + s.Value + " is not a positive double in Key " + key + " in Section " + Key + " at line " + s.Key);
+ currentHost.AddMessage(MessageType.Warning, false, "Value " + s + " is not a positive double in Key " + key + " in Section " + Key + " at line " + s.Key);
return false;
case NumberRange.NonNegative:
if (newValue >= 0)
@@ -186,7 +186,7 @@ public bool TryGetValue(T2 key, ref double value, NumberRange range = NumberRang
value = newValue;
return true;
}
- currentHost.AddMessage(MessageType.Warning, false, "Value " + s.Value + " is not a non-negative double in Key " + key + " in Section " + Key + " at line " + s.Key);
+ currentHost.AddMessage(MessageType.Warning, false, "Value " + s + " is not a non-negative double in Key " + key + " in Section " + Key + " at line " + s.Key);
return false;
case NumberRange.NonZero:
if (newValue != 0)
@@ -194,11 +194,11 @@ public bool TryGetValue(T2 key, ref double value, NumberRange range = NumberRang
value = newValue;
return true;
}
- currentHost.AddMessage(MessageType.Warning, false, "Value " + s.Value + " is not a non-zero double in Key " + key + " in Section " + Key + " at line " + s.Key);
+ currentHost.AddMessage(MessageType.Warning, false, "Value " + s + " is not a non-zero double in Key " + key + " in Section " + Key + " at line " + s.Key);
return false;
}
}
- currentHost.AddMessage(MessageType.Warning, false, "Value " + s.Value + " is not a valid double in Key " + key + " in Section " + Key + " at line " + s.Key);
+ currentHost.AddMessage(MessageType.Warning, false, "Value " + s + " is not a valid double in Key " + key + " in Section " + Key + " at line " + s.Key);
}
return false;
}
@@ -233,7 +233,7 @@ public virtual bool TryGetValue(T2 key, ref int value, NumberRange range = Numbe
value = newValue;
return true;
}
- currentHost.AddMessage(MessageType.Warning, false, "Value " + s.Value + " is not a positive integer in Key " + key + " in Section " + Key + " at line " + s.Key);
+ currentHost.AddMessage(MessageType.Warning, false, "Value " + s + " is not a positive integer in Key " + key + " in Section " + Key + " at line " + s.Key);
return false;
case NumberRange.NonNegative:
if (newValue >= 0)
@@ -241,7 +241,7 @@ public virtual bool TryGetValue(T2 key, ref int value, NumberRange range = Numbe
value = newValue;
return true;
}
- currentHost.AddMessage(MessageType.Warning, false, "Value " + s.Value + " is not a non-negative integer in Key " + key + " in Section " + Key + " at line " + s.Key);
+ currentHost.AddMessage(MessageType.Warning, false, "Value " + s + " is not a non-negative integer in Key " + key + " in Section " + Key + " at line " + s.Key);
return false;
case NumberRange.NonZero:
if (newValue != 0)
@@ -249,7 +249,7 @@ public virtual bool TryGetValue(T2 key, ref int value, NumberRange range = Numbe
value = newValue;
return true;
}
- currentHost.AddMessage(MessageType.Warning, false, "Value " + s.Value + " is not a non-zero integer in Key " + key + " in Section " + Key + " at line " + s.Key);
+ currentHost.AddMessage(MessageType.Warning, false, "Value " + s + " is not a non-zero integer in Key " + key + " in Section " + Key + " at line " + s.Key);
return false;
}
}
@@ -291,7 +291,7 @@ public virtual bool GetIndexedPath(string absolutePath, out int index, out strin
try
{
- finalPath = value.Value != string.Empty ? Path.CombineFile(absolutePath, value.Value) : string.Empty;
+ finalPath = Path.CombineFile(absolutePath, value.Value);
}
catch
{
diff --git a/source/Plugins/Formats.OpenBve/CFG/ConfigFile.cs b/source/Plugins/Formats.OpenBve/CFG/ConfigFile.cs
index 3151ac637b..198a44ad1a 100644
--- a/source/Plugins/Formats.OpenBve/CFG/ConfigFile.cs
+++ b/source/Plugins/Formats.OpenBve/CFG/ConfigFile.cs
@@ -317,7 +317,7 @@ public override bool GetPath(T2 key, string absolutePath, out string finalPath)
string relativePath = value.Value;
try
{
- finalPath = relativePath != string.Empty ? Path.CombineFile(absolutePath, relativePath) : string.Empty;
+ finalPath = Path.CombineFile(absolutePath, relativePath);
}
catch
{
diff --git a/source/Plugins/Formats.OpenBve/Enums/TrainXML/TrainXMLKey.cs b/source/Plugins/Formats.OpenBve/Enums/TrainXML/TrainXMLKey.cs
index 670983a936..9a43e8df80 100644
--- a/source/Plugins/Formats.OpenBve/Enums/TrainXML/TrainXMLKey.cs
+++ b/source/Plugins/Formats.OpenBve/Enums/TrainXML/TrainXMLKey.cs
@@ -117,7 +117,6 @@ public enum TrainXMLKey
StageTwoSpeed,
StageTwoExponent,
Multiplier,
- MotorBrakeNotch,
- Function
+ MotorBrakeNotch
}
}
diff --git a/source/Plugins/Formats.OpenBve/Formats.OpenBve.csproj b/source/Plugins/Formats.OpenBve/Formats.OpenBve.csproj
index cd27f74dfb..a41dc09369 100644
--- a/source/Plugins/Formats.OpenBve/Formats.OpenBve.csproj
+++ b/source/Plugins/Formats.OpenBve/Formats.OpenBve.csproj
@@ -95,8 +95,6 @@
OpenBveApi
-
-
-
+
\ No newline at end of file
diff --git a/source/Plugins/Formats.OpenBve/XML/XMLFile.cs b/source/Plugins/Formats.OpenBve/XML/XMLFile.cs
index d3de072a4c..2b231fd0a0 100644
--- a/source/Plugins/Formats.OpenBve/XML/XMLFile.cs
+++ b/source/Plugins/Formats.OpenBve/XML/XMLFile.cs
@@ -120,55 +120,6 @@ public XMLFile(XDocument currentXML, string fileName, string rootPath, HostInter
}
- public override bool GetPath(T2 key, string absolutePath, out string finalPath)
- {
- if (keyValuePairs.TryRemove(key, out var value))
- {
- if (!Path.ContainsInvalidChars(value.Value))
- {
-
- string relativePath = value.Value;
- try
- {
- finalPath = Path.CombineFile(absolutePath, relativePath);
- }
- catch
- {
- finalPath = string.Empty;
- }
-
- if (File.Exists(finalPath))
- {
- return true;
- }
-
- try
- {
- finalPath = Path.CombineFile(absolutePath, relativePath);
- }
- catch
- {
- finalPath = string.Empty;
- return false;
- }
-
- if (File.Exists(finalPath))
- {
- return true;
- }
-
- currentHost.AddMessage(MessageType.Warning, false, "File " + value.Value + " was not found in Key " + key + " in Section " + Key + " at line " + value.Key);
- finalPath = string.Empty;
- return false;
-
- }
-
- currentHost.AddMessage(MessageType.Warning, false, "Path contains invalid characters for " + key + " in Section " + Key + " at line " + value.Key);
- }
- finalPath = string.Empty;
- return false;
- }
-
public override Block ReadNextBlock()
{
Block block = subBlocks[0];
diff --git a/source/Plugins/Formats.OpenBve/app.config b/source/Plugins/Formats.OpenBve/app.config
deleted file mode 100644
index 7afad42acb..0000000000
--- a/source/Plugins/Formats.OpenBve/app.config
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Object.Animated/app.config b/source/Plugins/Object.Animated/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Object.Animated/app.config
+++ b/source/Plugins/Object.Animated/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Object.CsvB3d/app.config b/source/Plugins/Object.CsvB3d/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Object.CsvB3d/app.config
+++ b/source/Plugins/Object.CsvB3d/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Object.DirectX/Parsers/NewXParser.cs b/source/Plugins/Object.DirectX/Parsers/NewXParser.cs
index 656ee7f9ec..c43e416dda 100644
--- a/source/Plugins/Object.DirectX/Parsers/NewXParser.cs
+++ b/source/Plugins/Object.DirectX/Parsers/NewXParser.cs
@@ -26,6 +26,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Runtime.Remoting.Messaging;
using System.Text;
using Object.DirectX;
using OpenBve.Formats.DirectX;
diff --git a/source/Plugins/Object.DirectX/app.config b/source/Plugins/Object.DirectX/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Object.DirectX/app.config
+++ b/source/Plugins/Object.DirectX/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Object.LokSim/app.config b/source/Plugins/Object.LokSim/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Object.LokSim/app.config
+++ b/source/Plugins/Object.LokSim/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Object.Msts/Object.Msts.csproj b/source/Plugins/Object.Msts/Object.Msts.csproj
index c8916e9c8e..8194f5e2a8 100644
--- a/source/Plugins/Object.Msts/Object.Msts.csproj
+++ b/source/Plugins/Object.Msts/Object.Msts.csproj
@@ -48,11 +48,8 @@
prompt
-
- ..\..\..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\netstandard2.0\Microsoft.Bcl.AsyncInterfaces.dll
-
-
- ..\..\..\packages\SharpCompress.0.48.0\lib\netstandard2.0\SharpCompress.dll
+
+ ..\..\..\packages\SharpCompress.0.32.2\lib\net461\SharpCompress.dll
@@ -70,11 +67,8 @@
..\..\..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
-
- ..\..\..\packages\System.Text.Encoding.CodePages.8.0.0\lib\netstandard2.0\System.Text.Encoding.CodePages.dll
-
-
- ..\..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
+
+ ..\..\..\packages\System.Text.Encoding.CodePages.6.0.0\lib\net461\System.Text.Encoding.CodePages.dll
diff --git a/source/Plugins/Object.Msts/app.config b/source/Plugins/Object.Msts/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Object.Msts/app.config
+++ b/source/Plugins/Object.Msts/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Object.Msts/packages.config b/source/Plugins/Object.Msts/packages.config
index c0bb4d9ebb..5d2acb5f31 100644
--- a/source/Plugins/Object.Msts/packages.config
+++ b/source/Plugins/Object.Msts/packages.config
@@ -1,11 +1,9 @@
-
-
+
-
-
+
\ No newline at end of file
diff --git a/source/Plugins/Object.Wavefront/Parsers/AssimpObjParser.cs b/source/Plugins/Object.Wavefront/Parsers/AssimpObjParser.cs
index 427c8d0fc8..e6d6af7c6f 100644
--- a/source/Plugins/Object.Wavefront/Parsers/AssimpObjParser.cs
+++ b/source/Plugins/Object.Wavefront/Parsers/AssimpObjParser.cs
@@ -24,6 +24,7 @@
using System;
using System.Collections.Generic;
+using System.Drawing.Text;
using OpenBveApi.Colors;
using OpenBveApi.Interface;
using OpenBveApi.Math;
@@ -31,11 +32,10 @@
using AssimpNET.Obj;
using OpenBveApi;
using Material = AssimpNET.Obj.Material;
-using Mesh = AssimpNET.Obj.Mesh;
namespace Plugin
{
- internal class AssimpObjParser
+ class AssimpObjParser
{
private static string currentFolder;
@@ -47,99 +47,119 @@ internal static StaticObject ReadObject(string fileName)
ObjFileParser parser = new ObjFileParser(System.IO.File.ReadAllLines(fileName), null, System.IO.Path.GetFileNameWithoutExtension(fileName), fileName);
Model model = parser.GetModel();
- StaticObject obj = new StaticObject(Plugin.CurrentHost);
- MeshBuilder builder = new MeshBuilder(Plugin.CurrentHost);
+ StaticObject obj = new StaticObject(Plugin.currentHost);
+ MeshBuilder builder = new MeshBuilder(Plugin.currentHost);
+
+ List allVertices = new List();
+ foreach (var vertex in model.Vertices)
+ {
+ allVertices.Add(new Vertex(vertex * model.ScaleFactor));
+ }
+
+ List allTexCoords = new List();
+ foreach (var texCoord in model.TextureCoord)
+ {
+ Vector2 textureCoordinate = new Vector2(texCoord.X, texCoord.Y);
+ switch (model.Exporter)
+ {
+ case ModelExporter.SketchUp:
+ textureCoordinate.X *= -1.0;
+ textureCoordinate.Y *= -1.0;
+ break;
+ case ModelExporter.Blender:
+ case ModelExporter.BlockBench:
+ textureCoordinate.Y *= -1.0;
+ break;
+ }
+ allTexCoords.Add(textureCoordinate);
+
+ }
+
+ List allNormals = new List();
+ foreach (var normal in model.Normals)
+ {
+ allNormals.Add(new Vector3(normal.X, normal.Y, normal.Z));
+ }
+
Material lastMaterial = null;
- foreach (Mesh mesh in model.Meshes)
+ foreach (AssimpNET.Obj.Mesh mesh in model.Meshes)
{
- //mesh.Faces.GroupBy(x => x.Material).OrderByDescending(g => g.Count()).SelectMany(x => x).ToList();
foreach (Face face in mesh.Faces)
{
- if (face.Material != lastMaterial)
- {
- builder.Apply(ref obj);
- builder = new MeshBuilder(Plugin.CurrentHost);
- uint materialIndex = mesh.MaterialIndex;
- if (materialIndex != Mesh.NoMaterial)
- {
- Material material = model.MaterialMap[model.MaterialLib[(int)materialIndex]];
- builder.Materials[0].Color = new Color32(material.Diffuse);
-#pragma warning disable 0219
- //Current openBVE renderer does not support specular color
- // ReSharper disable once UnusedVariable
- Color24 mSpecular = new Color24(material.Specular);
-#pragma warning restore 0219
- // Wrap Color24 in Color32 for RGBA support; alpha defaults to 255 (opaque)
- builder.Materials[0].EmissiveColor = new Color32(new Color24(material.Emissive));
- builder.Materials[0].Flags |= MaterialFlags.Emissive; //TODO: Check exact behaviour
- if (material.TransparentUsed)
- {
- builder.Materials[0].TransparentColor = new Color24(material.Transparent);
- builder.Materials[0].Flags |= MaterialFlags.TransparentColor;
- }
-
- if (material.Texture != null)
- {
- builder.Materials[0].DaytimeTexture = Path.CombineFile(currentFolder, material.Texture);
- if (!System.IO.File.Exists(builder.Materials[0].DaytimeTexture))
- {
- Plugin.CurrentHost.AddMessage(MessageType.Error, true, "Texture " + builder.Materials[0].DaytimeTexture + " was not found in file " + fileName);
- builder.Materials[0].DaytimeTexture = null;
- }
- }
- }
- }
-
- if (face.Vertices.Count == 0)
+ int nVerts = face.Vertices.Count;
+ int bVerts = builder.Vertices.Count;
+ if (nVerts == 0)
{
throw new Exception("nVertices must be greater than zero");
}
- int startingVertex = builder.Vertices.Count;
- for (int i = 0; i < face.Vertices.Count; i++)
+ for (int i = 0; i < nVerts; i++)
{
- VertexTemplate v = new Vertex(model.Vertices[(int)face.Vertices[i]] * model.ScaleFactor);
-
- if (model.TextureCoord.Count > 0 && i <= model.TextureCoord.Count && face.TexturCoords.Count > 0 && i <= face.TexturCoords.Count)
+ VertexTemplate v = allVertices[(int)face.Vertices[i]].Clone();
+ if (allTexCoords.Count > 0 && i <= allTexCoords.Count && face.TexturCoords.Count > 0 && i <= face.TexturCoords.Count)
{
- Vector2 textureCoordinate = new Vector2(model.TextureCoord[i].X, model.TextureCoord[i].Y);
- switch (model.Exporter)
- {
- case ModelExporter.SketchUp:
- textureCoordinate.X *= -1.0;
- textureCoordinate.Y *= -1.0;
- break;
- case ModelExporter.Blender:
- case ModelExporter.BlockBench:
- textureCoordinate.Y *= -1.0;
- break;
- }
- v.TextureCoordinates = textureCoordinate;
+ v.TextureCoordinates = allTexCoords[(int)face.TexturCoords[i]];
}
-
builder.Vertices.Add(v);
}
- MeshFace f = new MeshFace(face.Vertices.Count);
-
- for (int i = 0; i < face.Vertices.Count; i++)
+ MeshFace f = new MeshFace(nVerts);
+ for (int i = 0; i < nVerts; i++)
{
- f.Vertices[i].Index = startingVertex + i;
+ f.Vertices[i].Index = bVerts + i;
if (face.Normals.Count > i)
{
- f.Vertices[i].Normal = model.Normals[(int)face.Normals[i]];
+ f.Vertices[i].Normal = allNormals[(int)face.Normals[i]];
}
}
-
- f.Material = 0;
- f.Flags |= FaceFlags.Face2Mask;
+ f.Material = 1;
builder.Faces.Add(f);
+
+ int m = builder.Materials.Length;
+ Array.Resize(ref builder.Materials, m + 1);
+ builder.Materials[m] = new OpenBveApi.Objects.Material();
+ uint materialIndex = mesh.MaterialIndex;
+ if (materialIndex != AssimpNET.Obj.Mesh.NoMaterial)
+ {
+ AssimpNET.Obj.Material material = model.MaterialMap[model.MaterialLib[(int)materialIndex]];
+ builder.Materials[m].Color = new Color32(material.Diffuse);
+#pragma warning disable 0219
+ //Current openBVE renderer does not support specular color
+ // ReSharper disable once UnusedVariable
+ Color24 mSpecular = new Color24(material.Specular);
+#pragma warning restore 0219
+ // Wrap Color24 in Color32 for RGBA support; alpha defaults to 255 (opaque)
+ builder.Materials[m].EmissiveColor = new Color32(new Color24(material.Emissive));
+ builder.Materials[m].Flags |= MaterialFlags.Emissive; //TODO: Check exact behaviour
+ if (material.TransparentUsed)
+ {
+ builder.Materials[m].TransparentColor = new Color24(material.Transparent);
+ builder.Materials[m].Flags |= MaterialFlags.TransparentColor;
+ }
+
+ if (material.Texture != null)
+ {
+ builder.Materials[m].DaytimeTexture = Path.CombineFile(currentFolder, material.Texture);
+ if (!System.IO.File.Exists(builder.Materials[m].DaytimeTexture))
+ {
+ Plugin.currentHost.AddMessage(MessageType.Error, true, "Texture " + builder.Materials[m].DaytimeTexture + " was not found in file " + fileName);
+ builder.Materials[m].DaytimeTexture = null;
+ }
+ }
+ }
+
if (model.Exporter >= ModelExporter.UnknownLeftHanded)
{
Array.Reverse(builder.Faces[builder.Faces.Count -1].Vertices, 0, builder.Faces[builder.Faces.Count -1].Vertices.Length);
}
+
+ if (face.Material != lastMaterial)
+ {
+ builder.Apply(ref obj);
+ builder = new MeshBuilder(Plugin.currentHost);
+ }
lastMaterial = face.Material;
}
}
@@ -149,7 +169,7 @@ internal static StaticObject ReadObject(string fileName)
}
catch (Exception e)
{
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, e.Message + " in " + fileName);
+ Plugin.currentHost.AddMessage(MessageType.Error, false, e.Message + " in " + fileName);
return null;
}
}
diff --git a/source/Plugins/Object.Wavefront/Parsers/Commands.cs b/source/Plugins/Object.Wavefront/Parsers/Commands.cs
index 54d1ae6b39..4e430ffbc7 100644
--- a/source/Plugins/Object.Wavefront/Parsers/Commands.cs
+++ b/source/Plugins/Object.Wavefront/Parsers/Commands.cs
@@ -16,7 +16,7 @@ internal enum WavefrontObjCommands
/// Adds a face
F,
/// Creates a new object
- /// Roughly analogous to a new MeshBuilder
+ /// Rougly analagous to a new MeshBuilder
O,
/// Starts a new face group
/// Usually applies a new texture
@@ -28,7 +28,7 @@ internal enum WavefrontObjCommands
///
/// Uses a material from the library
///
- UseMtl
+ UseMtl,
}
internal enum WavefrontMtlCommands
diff --git a/source/Plugins/Object.Wavefront/Parsers/WavefrontObjParser.cs b/source/Plugins/Object.Wavefront/Parsers/WavefrontObjParser.cs
index 7cc1c39c07..8db3d83626 100644
--- a/source/Plugins/Object.Wavefront/Parsers/WavefrontObjParser.cs
+++ b/source/Plugins/Object.Wavefront/Parsers/WavefrontObjParser.cs
@@ -35,6 +35,8 @@ namespace Plugin
{
internal static class WavefrontObjParser
{
+
+
/// Loads a Wavefront object from a file.
/// The text file to load the object from. Must be an absolute file name.
/// The encoding the file is saved in.
@@ -42,9 +44,9 @@ internal static class WavefrontObjParser
internal static StaticObject ReadObject(string fileName, System.Text.Encoding encoding)
{
ModelExporter modelExporter = ModelExporter.Unknown;
- StaticObject parsedObject = new StaticObject(Plugin.CurrentHost);
+ StaticObject parsedObject = new StaticObject(Plugin.currentHost);
- MeshBuilder meshBuilder = new MeshBuilder(Plugin.CurrentHost);
+ MeshBuilder meshBuilder = new MeshBuilder(Plugin.currentHost);
/*
* Temporary arrays
@@ -105,7 +107,7 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
currentScale = 1.0;
break;
default:
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Unrecognised units value " + units + " at line "+ i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unrecognised units value " + units + " at line "+ i);
break;
}
}
@@ -137,15 +139,15 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
Vector3 vertex = new Vector3();
if (!double.TryParse(arguments[1], out vertex.X))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid X co-ordinate in Vertex at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid X co-ordinate in Vertex at Line " + i);
}
if (!double.TryParse(arguments[2], out vertex.Y))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid Y co-ordinate in Vertex at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid Y co-ordinate in Vertex at Line " + i);
}
if (!double.TryParse(arguments[3], out vertex.Z))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid Z co-ordinate in Vertex at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid Z co-ordinate in Vertex at Line " + i);
}
vertex *= currentScale;
tempVertices.Add(vertex);
@@ -154,11 +156,11 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
Vector2 coords = new Vector2();
if (!double.TryParse(arguments[1], out coords.X))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid X co-ordinate in Texture Co-ordinates at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid X co-ordinate in Texture Co-ordinates at Line " + i);
}
if (!double.TryParse(arguments[2], out coords.Y))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid X co-ordinate in Texture Co-Ordinates at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid X co-ordinate in Texture Co-Ordinates at Line " + i);
}
tempCoords.Add(coords);
break;
@@ -166,15 +168,15 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
Vector3 normal = new Vector3();
if (!double.TryParse(arguments[1], out normal.X))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid X co-ordinate in Vertex Normal at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid X co-ordinate in Vertex Normal at Line " + i);
}
if (!double.TryParse(arguments[2], out normal.Y))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid Y co-ordinate in Vertex Normal at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid Y co-ordinate in Vertex Normal at Line " + i);
}
if (!double.TryParse(arguments[3], out normal.Z))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid Z co-ordinate in Vertex Normal at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid Z co-ordinate in Vertex Normal at Line " + i);
}
tempNormals.Add(normal);
break;
@@ -182,8 +184,8 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
throw new NotSupportedException("Parameter space verticies are not supported by this parser");
case WavefrontObjCommands.F:
//Create the temp list to hook out the vertices
-
- MeshFaceVertex[] meshVerticies = new MeshFaceVertex[arguments.Count - 1];
+ List vertices = new List();
+ List normals = new List();
for (int f = 1; f < arguments.Count; f++)
{
Vertex newVertex = new Vertex();
@@ -191,7 +193,7 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
int idx;
if (!int.TryParse(faceArguments[0], out idx))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid Vertex index in Face " + f + " at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid Vertex index in Face " + f + " at Line " + i);
continue;
}
@@ -208,7 +210,7 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
}
if (currentVertex > tempVertices.Count)
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Vertex index " + idx + " was greater than the available number of vertices in Face " + f + " at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Vertex index " + idx + " was greater than the available number of vertices in Face " + f + " at Line " + i);
continue;
}
newVertex.Coordinates = tempVertices[currentVertex - 1];
@@ -216,17 +218,18 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
{
newVertex.Coordinates.X *= -1.0;
}
-
-
- if (faceArguments.Length > 1)
+ if (faceArguments.Length <= 1)
+ {
+ normals.Add(new Vector3());
+ }
+ else
{
if (!int.TryParse(faceArguments[1], out idx))
{
if (!string.IsNullOrEmpty(faceArguments[1]))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid Texture Co-ordinate index in Face " + f + " at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid Texture Co-ordinate index in Face " + f + " at Line " + i);
}
-
newVertex.TextureCoordinates = new Vector2();
}
else
@@ -244,7 +247,7 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
}
if (currentCoord > tempCoords.Count)
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Texture Co-ordinate index " + currentCoord + " was greater than the available number of texture co-ordinates in Face " + f + " at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Texture Co-ordinate index " + currentCoord + " was greater than the available number of texture co-ordinates in Face " + f + " at Line " + i);
}
else
{
@@ -264,15 +267,19 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
}
}
}
- Vector3 vertexNormal = new Vector3();
- if (faceArguments.Length > 2)
+ if (faceArguments.Length <= 2)
+ {
+ normals.Add(new Vector3());
+ }
+ else
{
if (!int.TryParse(faceArguments[2], out idx))
{
if (!string.IsNullOrEmpty(faceArguments[2]))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid Vertex Normal index in Face " + f + " at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid Vertex Normal index in Face " + f + " at Line " + i);
}
+ normals.Add(new Vector3());
}
else
{
@@ -289,19 +296,24 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
}
if (currentNormal > tempNormals.Count)
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Vertex Normal index " + currentNormal + " was greater than the available number of normals in Face " + f + " at Line " + i);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Vertex Normal index " + currentNormal + " was greater than the available number of normals in Face " + f + " at Line " + i);
+ normals.Add(new Vector3());
}
else
{
- vertexNormal = tempNormals[currentNormal - 1];
+ normals.Add(tempNormals[currentNormal - 1]);
}
}
}
- meshBuilder.Vertices.Add(newVertex);
- meshVerticies[f - 1].Index = meshBuilder.Vertices.Count - 1;
- meshVerticies[f - 1].Normal = vertexNormal;
+ vertices.Add(newVertex);
+ }
+ MeshFaceVertex[] meshVerticies = new MeshFaceVertex[vertices.Count];
+ for (int k = 0; k < vertices.Count; k++)
+ {
+ meshBuilder.Vertices.Add(vertices[k]);
+ meshVerticies[k].Index = (ushort)(meshBuilder.Vertices.Count -1);
+ meshVerticies[k].Normal = normals[k];
}
-
int materialIndex = -1;
if (currentMaterial != string.Empty)
{
@@ -317,33 +329,28 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
if (materialIndex == -1)
{
- if (currentMaterial != string.Empty)
+ materialIndex = meshBuilder.Materials.Length;
+ Array.Resize(ref meshBuilder.Materials, meshBuilder.Materials.Length + 1);
+ if (tempMaterials.ContainsKey(currentMaterial))
{
- materialIndex = meshBuilder.Materials.Length;
- Array.Resize(ref meshBuilder.Materials, meshBuilder.Materials.Length + 1);
- if (tempMaterials.ContainsKey(currentMaterial))
- {
- meshBuilder.Materials[materialIndex] = tempMaterials[currentMaterial];
- }
- else
- {
- meshBuilder.Materials[materialIndex] = new Material();
- }
+ meshBuilder.Materials[materialIndex] = tempMaterials[currentMaterial];
+ }
+ else
+ {
+ meshBuilder.Materials[materialIndex] = new Material();
}
+
}
if (modelExporter >= ModelExporter.UnknownLeftHanded)
{
Array.Reverse(meshVerticies, 0, meshVerticies.Length);
}
-
- MeshFace face = currentMaterial == string.Empty ? new MeshFace(meshVerticies, 0) : new MeshFace(meshVerticies, (ushort)materialIndex);
- face.Flags |= FaceFlags.Face2Mask;
- meshBuilder.Faces.Add(face);
+ meshBuilder.Faces.Add(currentMaterial == string.Empty ? new MeshFace(meshVerticies, 0) : new MeshFace(meshVerticies, (ushort)materialIndex));
break;
case WavefrontObjCommands.O:
case WavefrontObjCommands.G:
meshBuilder.Apply(ref parsedObject);
- meshBuilder = new MeshBuilder(Plugin.CurrentHost);
+ meshBuilder = new MeshBuilder(Plugin.currentHost);
break;
case WavefrontObjCommands.S:
/*
@@ -367,22 +374,17 @@ internal static StaticObject ReadObject(string fileName, System.Text.Encoding en
}
break;
case WavefrontObjCommands.UseMtl:
- string lastMaterial = currentMaterial;
currentMaterial = arguments[1].ToLowerInvariant();
if (!tempMaterials.ContainsKey(currentMaterial))
{
currentMaterial = string.Empty;
- Plugin.CurrentHost.AddMessage(MessageType.Error, true, "Material " + arguments[1] + " was not found.");
- }
-
- if (lastMaterial != currentMaterial)
- {
- meshBuilder.Apply(ref parsedObject);
- meshBuilder = new MeshBuilder(Plugin.CurrentHost);
+ Plugin.currentHost.AddMessage(MessageType.Error, true, "Material " + arguments[1] + " was not found.");
}
+ meshBuilder.Apply(ref parsedObject);
+ meshBuilder = new MeshBuilder(Plugin.currentHost);
break;
default:
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Unrecognised command " + arguments[0]);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unrecognised command " + arguments[0]);
break;
}
}
@@ -428,7 +430,7 @@ private static void LoadMaterials(string fileName, ref Dictionary= 2 && !double.TryParse(arguments[1], out r))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid Ambient Color R in Material Definition for " + currentKey);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid Ambient Color R in Material Definition for " + currentKey);
}
if (arguments.Count >= 3 && !double.TryParse(arguments[2], out g))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid Ambient Color G in Material Definition for " + currentKey);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid Ambient Color G in Material Definition for " + currentKey);
}
if (arguments.Count >= 4 && !double.TryParse(arguments[3], out b))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid Ambient Color B in Material Definition for " + currentKey);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid Ambient Color B in Material Definition for " + currentKey);
}
r = 255 * r;
g = 255 * g;
@@ -465,7 +467,7 @@ private static void LoadMaterials(string fileName, ref Dictionary= 2 && !double.TryParse(arguments[1], out a))
{
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Invalid Alpha in Material Definition for " + currentKey);
+ Plugin.currentHost.AddMessage(MessageType.Warning, false, "Invalid Alpha in Material Definition for " + currentKey);
}
materials[currentKey].Color.A = (byte)(a * 255);
break;
@@ -474,7 +476,7 @@ private static void LoadMaterials(string fileName, ref Dictionary 2)
- {
- // HACK: re-join the split array (minus command) in case of spaces in folder names
- arguments.RemoveAt(0);
- string arg = string.Join(" ", arguments.ToArray());
- try
- {
- tday = OpenBveApi.Path.CombineFile(Path.GetDirectoryName(fileName), arg);
- }
- catch
- {
- // ignored
- }
-
- if (File.Exists(tday))
- {
- materials[currentKey].DaytimeTexture = tday;
- }
- else
- {
- Plugin.CurrentHost.AddMessage(MessageType.Error, true, "Material texture file " + arg + " was not found.");
- }
- }
- else
- {
- Plugin.CurrentHost.AddMessage(MessageType.Error, true, "Material texture file " + arguments[arguments.Count - 1] + " was not found.");
- }
-
+ Plugin.currentHost.AddMessage(MessageType.Error, true, "Material texture file " + arguments[arguments.Count -1] + " was not found.");
}
break;
diff --git a/source/Plugins/Object.Wavefront/Plugin.cs b/source/Plugins/Object.Wavefront/Plugin.cs
index d0775523e8..f18579b8f4 100644
--- a/source/Plugins/Object.Wavefront/Plugin.cs
+++ b/source/Plugins/Object.Wavefront/Plugin.cs
@@ -33,13 +33,13 @@ namespace Plugin
{
public class Plugin : ObjectInterface
{
- internal static HostInterface CurrentHost;
+ internal static HostInterface currentHost;
private static ObjParsers currentObjParser = ObjParsers.Original;
public override string[] SupportedStaticObjectExtensions => new[] { ".obj" };
public override void Load(HostInterface host, FileSystem fileSystem) {
- CurrentHost = host;
+ currentHost = host;
}
public override void SetObjectParser(object parserType)
@@ -56,7 +56,11 @@ public override bool CanLoadObject(string path)
{
return false;
}
- return path.EndsWith(".obj", StringComparison.InvariantCultureIgnoreCase);
+ if (path.EndsWith(".obj", StringComparison.InvariantCultureIgnoreCase))
+ {
+ return true;
+ }
+ return false;
}
public override bool LoadObject(string path, System.Text.Encoding textEncoding, out UnifiedObject unifiedObject)
@@ -71,7 +75,7 @@ public override bool LoadObject(string path, System.Text.Encoding textEncoding,
}
catch (Exception ex)
{
- CurrentHost.AddMessage(MessageType.Error, false, "The new Obj parser raised the following exception: " + ex);
+ currentHost.AddMessage(MessageType.Error, false, "The new Obj parser raised the following exception: " + ex);
}
}
try
@@ -82,7 +86,7 @@ public override bool LoadObject(string path, System.Text.Encoding textEncoding,
catch
{
unifiedObject = null;
- CurrentHost.AddMessage(MessageType.Error, false, "An unexpected error occured whilst attempting to load the following object: " + path);
+ currentHost.AddMessage(MessageType.Error, false, "An unexpected error occured whilst attempting to load the following object: " + path);
}
return false;
}
diff --git a/source/Plugins/Object.Wavefront/app.config b/source/Plugins/Object.Wavefront/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Object.Wavefront/app.config
+++ b/source/Plugins/Object.Wavefront/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/OpenBveAts/app.config b/source/Plugins/OpenBveAts/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/OpenBveAts/app.config
+++ b/source/Plugins/OpenBveAts/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Route.Bve5/MapParser/ConfirmComponents.cs b/source/Plugins/Route.Bve5/MapParser/ConfirmComponents.cs
index a2c139688e..01b148d6f0 100644
--- a/source/Plugins/Route.Bve5/MapParser/ConfirmComponents.cs
+++ b/source/Plugins/Route.Bve5/MapParser/ConfirmComponents.cs
@@ -587,13 +587,10 @@ private static void ConfirmRepeater(bool PreviewOnly, MapData ParseData, RouteDa
Repeater.ObjectKeys = new string[d.StructureKeys.Count];
- HashSet missingObjectKeys = new HashSet();
d.StructureKeys.CopyTo(Repeater.ObjectKeys, 0);
for (int i = 0; i < Repeater.ObjectKeys.Length; i++)
{
- // empty string == no object placed
- // also only add the error once per position (even if the object appears multiple times in the cycle)
- if (!RouteData.Objects.ContainsKey(Repeater.ObjectKeys[i]) && missingObjectKeys.Add(Repeater.ObjectKeys[i]) && !string.IsNullOrEmpty(Repeater.ObjectKeys[i]))
+ if (!RouteData.Objects.ContainsKey(Repeater.ObjectKeys[i]))
{
Plugin.CurrentHost.AddMessage(MessageType.Error, false, "BVE5: Structure " + Repeater.ObjectKeys[i] + " was not found in Repeater " + Statement.Key + " on track " + d.TrackKey + " at track position " + Statement.Distance + "m");
}
diff --git a/source/Plugins/Route.Bve5/Plugin.cs b/source/Plugins/Route.Bve5/Plugin.cs
index b666f34c59..39770a8000 100644
--- a/source/Plugins/Route.Bve5/Plugin.cs
+++ b/source/Plugins/Route.Bve5/Plugin.cs
@@ -25,7 +25,6 @@
using System;
using System.Text;
using OpenBveApi;
-using OpenBveApi.Colors;
using OpenBveApi.FileSystem;
using OpenBveApi.Hosts;
using OpenBveApi.Objects;
@@ -104,7 +103,6 @@ public override bool LoadRoute(string path, Encoding textEncoding, string trainP
}
}
- CurrentOptions.ClearColor = Color24.Black;
return true;
}
diff --git a/source/Plugins/Route.Bve5/Route.Bve5.csproj b/source/Plugins/Route.Bve5/Route.Bve5.csproj
index 425e1fd4c1..f6d5fcf95e 100644
--- a/source/Plugins/Route.Bve5/Route.Bve5.csproj
+++ b/source/Plugins/Route.Bve5/Route.Bve5.csproj
@@ -44,8 +44,8 @@
..\..\..\packages\Antlr4.Runtime.4.6.6\lib\net45\Antlr4.Runtime.dll
-
- ..\..\..\packages\Bve5_Parsing.OpenBVE.1.1.19\lib\net45\Bve5_Parsing.dll
+
+ ..\..\..\packages\Bve5_Parsing.OpenBVE.1.1.17\lib\net45\Bve5_Parsing.dll
diff --git a/source/Plugins/Route.Bve5/ScenarioParser.cs b/source/Plugins/Route.Bve5/ScenarioParser.cs
index d370174072..8b927f7f0a 100644
--- a/source/Plugins/Route.Bve5/ScenarioParser.cs
+++ b/source/Plugins/Route.Bve5/ScenarioParser.cs
@@ -90,7 +90,7 @@ internal static void ParseScenario(string fileName, bool previewOnly)
ScenarioGrammarParser Parser = new ScenarioGrammarParser();
ScenarioData Data = Parser.Parse(File.ReadAllText(fileName, Encoding));
- Plugin.CurrentRoute.Comment = Data.Comment ?? string.Empty;
+ Plugin.CurrentRoute.Comment = Data.Comment;
Plugin.CurrentRoute.Stations = Array.Empty();
CurrentStation = 0;
if (!string.IsNullOrEmpty(Data.Image))
diff --git a/source/Plugins/Route.Bve5/app.config b/source/Plugins/Route.Bve5/app.config
index a7c51ba61e..da8aeea264 100644
--- a/source/Plugins/Route.Bve5/app.config
+++ b/source/Plugins/Route.Bve5/app.config
@@ -10,10 +10,6 @@
-
-
-
-
diff --git a/source/Plugins/Route.Bve5/packages.config b/source/Plugins/Route.Bve5/packages.config
index 6df1c162d8..ebd841fae1 100644
--- a/source/Plugins/Route.Bve5/packages.config
+++ b/source/Plugins/Route.Bve5/packages.config
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/source/Plugins/Route.CsvRw/CsvRwRouteParser.Preprocess.cs b/source/Plugins/Route.CsvRw/CsvRwRouteParser.Preprocess.cs
index 7e867d24a2..44e43e312e 100644
--- a/source/Plugins/Route.CsvRw/CsvRwRouteParser.Preprocess.cs
+++ b/source/Plugins/Route.CsvRw/CsvRwRouteParser.Preprocess.cs
@@ -537,12 +537,6 @@ private void PreprocessChrRndSub(string FileName, System.Text.Encoding Encoding,
}
} else {
continueWithNextExpression = true;
- if (NumberFormats.TryParseIntVb6(s, out int r))
- {
- // only one number- return this as the result
- Expressions[i].Text = Expressions[i].Text.Substring(0, j) + r.ToString(Culture) + Expressions[i].Text.Substring(h + 1);
- continueWithNextExpression = false;
- }
Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Two arguments are expected in " + t + Epilog);
}
} break;
diff --git a/source/Plugins/Route.CsvRw/Namespaces/NonTrack/Structure.cs b/source/Plugins/Route.CsvRw/Namespaces/NonTrack/Structure.cs
index bb70348352..8079d0e718 100644
--- a/source/Plugins/Route.CsvRw/Namespaces/NonTrack/Structure.cs
+++ b/source/Plugins/Route.CsvRw/Namespaces/NonTrack/Structure.cs
@@ -84,7 +84,7 @@ private void ParseStructureCommand(StructureCommand Command, string[] Arguments,
string f = Path.CombineFile(ObjectPath, Arguments[0]);
if (!File.Exists(f))
{
- Plugin.CurrentHost.AddMessage(MessageType.Error, true, "FileName " + Arguments[0] + " not found in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
+ Plugin.CurrentHost.AddMessage(MessageType.Error, true, "FileName " + f + " not found in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
}
else
{
diff --git a/source/Plugins/Route.CsvRw/Namespaces/Track/Track.cs b/source/Plugins/Route.CsvRw/Namespaces/Track/Track.cs
index bab5cc0bdc..cc53832f37 100644
--- a/source/Plugins/Route.CsvRw/Namespaces/Track/Track.cs
+++ b/source/Plugins/Route.CsvRw/Namespaces/Track/Track.cs
@@ -628,14 +628,10 @@ private void ParseTrackCommand(TrackCommand Command, string[] Arguments, string
num = -2;
}
- if (num == 0)
+ if (num == 0 && IsRW)
{
- //Aspects value of zero produces a 2-aspect R/G signal in BVE2
- if (IsRw || Plugin.CurrentOptions.EnableBveTsHacks)
- {
- num = -2;
- }
-
+ //Aspects value of zero in RW routes produces a 2-aspect R/G signal
+ num = -2;
}
if (num != 1 & num != -2 & num != 2 & num != -3 & num != 3 & num != -4 & num != 4 & num != -5 & num != 5 & num != 6)
@@ -2589,19 +2585,13 @@ private void ParseTrackCommand(TrackCommand Command, string[] Arguments, string
if (Arguments.Length >= 6 && Arguments[5].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[5], out pitch))
{
- if (!Data.IgnorePitchRoll)
- {
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Pitch is invalid in Track.FreeObj at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
- }
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Pitch is invalid in Track.FreeObj at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
pitch = 0.0;
}
if (Arguments.Length >= 7 && Arguments[6].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[6], out roll))
{
- if (!Data.IgnorePitchRoll)
- {
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Roll is invalid in Track.FreeObj at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
- }
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Roll is invalid in Track.FreeObj at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
roll = 0.0;
}
diff --git a/source/Plugins/Route.CsvRw/Plugin.cs b/source/Plugins/Route.CsvRw/Plugin.cs
index fa91a80005..9598ad6ab8 100644
--- a/source/Plugins/Route.CsvRw/Plugin.cs
+++ b/source/Plugins/Route.CsvRw/Plugin.cs
@@ -3,7 +3,6 @@
using System.Text;
using System.Threading;
using OpenBveApi;
-using OpenBveApi.Colors;
using OpenBveApi.FileSystem;
using OpenBveApi.Hosts;
using OpenBveApi.Interface;
@@ -128,7 +127,6 @@ public override bool LoadRoute(string path, Encoding textEncoding, string trainP
Parser parser = new Parser(this, isRw);
parser.ParseRoute(path, textEncoding, trainPath, objectPath, soundPath, PreviewOnly);
IsLoading = false;
- CurrentOptions.ClearColor = new Color24(170, 170, 170);
return true;
}
catch(Exception ex)
diff --git a/source/Plugins/Route.CsvRw/Structures/Expression.cs b/source/Plugins/Route.CsvRw/Structures/Expression.cs
index 87719ffc1d..f65f6df419 100644
--- a/source/Plugins/Route.CsvRw/Structures/Expression.cs
+++ b/source/Plugins/Route.CsvRw/Structures/Expression.cs
@@ -92,11 +92,6 @@ internal void SeparateCommandsAndArguments(out string Command, out string Argume
// 普通播州赤穂行 - brackets in station name
Text = ".Sta [貨]"+ Text.Substring(8);
}
- else if (Text.StartsWith(".freeobj (9"))
- {
- // East Linconshire Railway bridges
- Text = ".freeobj(9" + Text.Substring(11);
- }
if (IsRw && CurrentSection.ToLowerInvariant() == "track")
{
diff --git a/source/Plugins/Route.CsvRw/Structures/Signals/SignalData.BVE4.cs b/source/Plugins/Route.CsvRw/Structures/Signals/SignalData.BVE4.cs
index b369f01ca8..0f71741e6e 100644
--- a/source/Plugins/Route.CsvRw/Structures/Signals/SignalData.BVE4.cs
+++ b/source/Plugins/Route.CsvRw/Structures/Signals/SignalData.BVE4.cs
@@ -22,96 +22,98 @@ internal class Bve4SignalData : SignalObject
public override void Create(Vector3 wpos, Transformation RailTransformation, Transformation LocalTransformation, int SectionIndex, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness)
{
- if (SignalTextures.Length == 0) return;
- int m = Math.Max(SignalTextures.Length, GlowTextures.Length);
- int zn = 0;
- for (int l = 0; l < m; l++)
+ if (SignalTextures.Length != 0)
{
- if (l < SignalTextures.Length && SignalTextures[l] != null || l < GlowTextures.Length && GlowTextures[l] != null)
+ int m = Math.Max(SignalTextures.Length, GlowTextures.Length);
+ int zn = 0;
+ for (int l = 0; l < m; l++)
{
- zn++;
- }
- }
-
- AnimatedObjectCollection aoc = new AnimatedObjectCollection(Plugin.CurrentHost)
- {
- Objects = new[]
- {
- new AnimatedObject(Plugin.CurrentHost)
+ if (l < SignalTextures.Length && SignalTextures[l] != null || l < GlowTextures.Length && GlowTextures[l] != null)
{
- States = new ObjectState[zn]
+ zn++;
}
}
- };
- int zi = 0;
- string expr = string.Empty;
- for (int l = 0; l < m; l++)
- {
- bool qs = l < SignalTextures.Length && SignalTextures[l] != null;
- bool qg = l < GlowTextures.Length && GlowTextures[l] != null;
- StaticObject so = new StaticObject(Plugin.CurrentHost);
- StaticObject go = null;
- if (qs & qg)
+ AnimatedObjectCollection aoc = new AnimatedObjectCollection(Plugin.CurrentHost)
{
-
- if (BaseObject != null)
+ Objects = new[]
{
- so = BaseObject.Clone(SignalTextures[l], null);
+ new AnimatedObject(Plugin.CurrentHost)
+ {
+ States = new ObjectState[zn]
+ }
}
+ };
- if (GlowObject != null)
+ int zi = 0;
+ string expr = string.Empty;
+ for (int l = 0; l < m; l++)
+ {
+ bool qs = l < SignalTextures.Length && SignalTextures[l] != null;
+ bool qg = l < GlowTextures.Length && GlowTextures[l] != null;
+ StaticObject so = new StaticObject(Plugin.CurrentHost);
+ StaticObject go = null;
+ if (qs & qg)
{
- go = GlowObject.Clone(GlowTextures[l], null);
+
+ if (BaseObject != null)
+ {
+ so = BaseObject.Clone(SignalTextures[l], null);
+ }
+
+ if (GlowObject != null)
+ {
+ go = GlowObject.Clone(GlowTextures[l], null);
+ }
+
+ so.JoinObjects(go);
+ aoc.Objects[0].States[zi] = new ObjectState(so);
}
+ else if (qs)
+ {
+ if (BaseObject != null)
+ {
+ so = BaseObject.Clone(SignalTextures[l], null);
+ }
- so.JoinObjects(go);
- aoc.Objects[0].States[zi] = new ObjectState(so);
- }
- else if (qs)
- {
- if (BaseObject != null)
+ aoc.Objects[0].States[zi] = new ObjectState(so);
+ }
+ else if (qg)
{
- so = BaseObject.Clone(SignalTextures[l], null);
+ if (GlowObject != null)
+ {
+ go = GlowObject.Clone(GlowTextures[l], null);
+ }
+
+ //BUG: Should we join the glow object here? Test what BVE4 does with missing state, but provided glow
+ aoc.Objects[0].States[zi] = new ObjectState(so);
}
- aoc.Objects[0].States[zi] = new ObjectState(so);
- }
- else if (qg)
- {
- if (GlowObject != null)
+ if (qs | qg)
{
- go = GlowObject.Clone(GlowTextures[l], null);
- }
+ CultureInfo Culture = CultureInfo.InvariantCulture;
+ if (zi < zn - 1)
+ {
+ expr += "section " + l.ToString(Culture) + " <= " + zi.ToString(Culture) + " ";
+ }
+ else
+ {
+ expr += zi.ToString(Culture);
+ }
- //BUG: Should we join the glow object here? Test what BVE4 does with missing state, but provided glow
- aoc.Objects[0].States[zi] = new ObjectState(so);
+ zi++;
+ }
}
- if (qs | qg)
+ for (int l = 0; l < zn - 1; l++)
{
- CultureInfo Culture = CultureInfo.InvariantCulture;
- if (zi < zn - 1)
- {
- expr += "section " + l.ToString(Culture) + " <= " + zi.ToString(Culture) + " ";
- }
- else
- {
- expr += zi.ToString(Culture);
- }
-
- zi++;
+ expr += " ?";
}
- }
- for (int l = 0; l < zn - 1; l++)
- {
- expr += " ?";
+ aoc.Objects[0].StateFunction = new FunctionScript(Plugin.CurrentHost, expr, false);
+ aoc.Objects[0].RefreshRate = 1.0 + 0.01 * Plugin.RandomNumberGenerator.NextDouble();
+ aoc.CreateObject(wpos, RailTransformation, LocalTransformation, new ObjectCreationParameters(TrackPosition, StartingDistance, EndingDistance, SectionIndex));
}
-
- aoc.Objects[0].StateFunction = new FunctionScript(Plugin.CurrentHost, expr, false);
- aoc.Objects[0].RefreshRate = 1.0 + 0.01 * Plugin.RandomNumberGenerator.NextDouble();
- aoc.CreateObject(wpos, RailTransformation, LocalTransformation, new ObjectCreationParameters(TrackPosition, StartingDistance, EndingDistance, 1.0, SectionIndex));
}
}
}
diff --git a/source/Plugins/Route.CsvRw/XML/DynamicLight.cs b/source/Plugins/Route.CsvRw/XML/DynamicLight.cs
index 0ebe6ebeb7..1569067559 100644
--- a/source/Plugins/Route.CsvRw/XML/DynamicLight.cs
+++ b/source/Plugins/Route.CsvRw/XML/DynamicLight.cs
@@ -1,4 +1,4 @@
-using Formats.OpenBve;
+using Formats.OpenBve;
using Formats.OpenBve.XML;
using OpenBveApi.Interface;
using OpenBveApi.Math;
@@ -48,8 +48,7 @@ public static bool ReadLightingXML(string fileName, out LightDefinition[] LightD
ld = lightBlock.TryGetVector3(DynamicLightKey.LightDirection, ',', ref currentLight.LightPosition);
if (!ld && lightBlock.GetVector2(DynamicLightKey.SphericalLightDirection, ',', out Vector2 temp))
{
- double theta = temp.X.ToRadians(), phi = temp.Y.ToRadians();
- currentLight.LightPosition = new Vector3(-Math.Cos(theta) * Math.Sin(phi), Math.Sin(theta), -Math.Cos(theta) * Math.Cos(phi));
+ currentLight.LightPosition = new Vector3(Math.Cos(temp.X) * Math.Sin(temp.Y), -Math.Sin(temp.X), Math.Cos(temp.X) * Math.Cos(temp.Y));
ld = true;
}
//We want to be able to add a completely default light element, but not one that's not been defined in the XML properly
diff --git a/source/Plugins/Route.CsvRw/app.config b/source/Plugins/Route.CsvRw/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Route.CsvRw/app.config
+++ b/source/Plugins/Route.CsvRw/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Route.Mechanik/Plugin.cs b/source/Plugins/Route.Mechanik/Plugin.cs
index a23aab479b..4eaaf97c0f 100644
--- a/source/Plugins/Route.Mechanik/Plugin.cs
+++ b/source/Plugins/Route.Mechanik/Plugin.cs
@@ -22,19 +22,18 @@
//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
using OpenBveApi;
-using OpenBveApi.Colors;
using OpenBveApi.FileSystem;
using OpenBveApi.Hosts;
using OpenBveApi.Interface;
using OpenBveApi.Routes;
using RouteManager2;
using RouteManager2.Stations;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
using Path = OpenBveApi.Path;
namespace MechanikRouteParser
@@ -143,8 +142,7 @@ public override bool LoadRoute(string path, System.Text.Encoding textEncoding, s
return false;
}
IsLoading = false;
- CurrentOptions.ClearColor = new Color24(170, 170, 170);
- return true;
+ return true;
}
catch(Exception ex)
{
diff --git a/source/Plugins/Route.Mechanik/app.config b/source/Plugins/Route.Mechanik/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Route.Mechanik/app.config
+++ b/source/Plugins/Route.Mechanik/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Sound.Flac/Decoder.cs b/source/Plugins/Sound.Flac/Decoder.cs
index 1ec15e1f8a..fbfecfdbef 100644
--- a/source/Plugins/Sound.Flac/Decoder.cs
+++ b/source/Plugins/Sound.Flac/Decoder.cs
@@ -320,7 +320,7 @@ internal static int[][] Decode(string file, out int sampleRate, out int bitsPerS
predictor += coefficients[k] * blockSamples[j - k - 1];
}
predictor >>= predictorShift;
- blockSamples[j] = (sbyte)(predictor + residuals[j]);
+ blockSamples[j] = (int)(sbyte)(predictor + residuals[j]);
}
} else {
for (int j = predictorOrder; j < blockNumberOfSamples; j++) {
@@ -329,7 +329,7 @@ internal static int[][] Decode(string file, out int sampleRate, out int bitsPerS
predictor += (long)coefficients[k] * (long)blockSamples[j - k - 1];
}
predictor >>= predictorShift;
- blockSamples[j] = (sbyte)(predictor + residuals[j]);
+ blockSamples[j] = (int)(sbyte)(predictor + residuals[j]);
}
}
} else if (subframeBitsPerSample == 16) {
@@ -340,7 +340,7 @@ internal static int[][] Decode(string file, out int sampleRate, out int bitsPerS
predictor += coefficients[k] * blockSamples[j - k - 1];
}
predictor >>= predictorShift;
- blockSamples[j] = (short)(predictor + residuals[j]);
+ blockSamples[j] = (int)(short)(predictor + residuals[j]);
}
} else {
for (int j = predictorOrder; j < blockNumberOfSamples; j++) {
@@ -349,7 +349,7 @@ internal static int[][] Decode(string file, out int sampleRate, out int bitsPerS
predictor += (long)coefficients[k] * (long)blockSamples[j - k - 1];
}
predictor >>= predictorShift;
- blockSamples[j] = (short)(predictor + residuals[j]);
+ blockSamples[j] = (int)(short)(predictor + residuals[j]);
}
}
} else {
@@ -420,92 +420,74 @@ internal static int[][] Decode(string file, out int sampleRate, out int bitsPerS
break;
}
}
- if (md5Set)
- {
- int pos = 0;
- MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
- byte[] check;
- switch (bitsPerSample)
- {
- case 8:
- /* For 8 bits per sample */
- bytes = new byte[numberOfChannels * samplesUsed];
- for (int i = 0; i < samplesUsed; i++)
- {
- for (int j = 0; j < numberOfChannels; j++)
- {
- bytes[pos] = (byte)(samples[j][i] >> 24);
- pos++;
- }
- }
-
- check = provider.ComputeHash(bytes);
- if (check.Length != md5.Length)
- {
- throw new InvalidOperationException();
- }
- for (int i = 0; i < check.Length; i++)
- {
- if (check[i] != md5[i])
- {
- throw new InvalidDataException("MD5 failed.");
- }
+ if (md5Set) {
+ if (bitsPerSample == 8) {
+ /* For 8 bits per sample */
+ bytes = new byte[numberOfChannels * samplesUsed];
+ int pos = 0;
+ for (int i = 0; i < samplesUsed; i++) {
+ for (int j = 0; j < numberOfChannels; j++) {
+ bytes[pos] = (byte)(samples[j][i] >> 24);
+ pos++;
}
- break;
- case 16:
- /* For 16 bits per sample */
- bytes = new byte[2 * numberOfChannels * samplesUsed];
- for (int i = 0; i < samplesUsed; i++)
- {
- for (int j = 0; j < numberOfChannels; j++)
- {
- bytes[pos + 0] = (byte)(samples[j][i] >> 16);
- bytes[pos + 1] = (byte)(samples[j][i] >> 24);
- pos += 2;
- }
- }
- check = provider.ComputeHash(bytes);
- if (check.Length != md5.Length)
- {
- throw new InvalidOperationException();
+ }
+ MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
+ byte[] check = provider.ComputeHash(bytes);
+ if (check.Length != md5.Length) {
+ throw new InvalidOperationException();
+ }
+ for (int i = 0; i < check.Length; i++) {
+ if (check[i] != md5[i]) {
+ throw new InvalidDataException("MD5 failed.");
}
- for (int i = 0; i < check.Length; i++)
- {
- if (check[i] != md5[i])
- {
- throw new InvalidDataException("MD5 failed.");
- }
+ }
+ } else if (bitsPerSample == 16) {
+ /* For 16 bits per sample */
+ bytes = new byte[2 * numberOfChannels * samplesUsed];
+ int pos = 0;
+ for (int i = 0; i < samplesUsed; i++) {
+ for (int j = 0; j < numberOfChannels; j++) {
+ bytes[pos + 0] = (byte)(samples[j][i] >> 16);
+ bytes[pos + 1] = (byte)(samples[j][i] >> 24);
+ pos += 2;
}
- break;
- case 24:
- /* For 24 bits per sample */
- bytes = new byte[3 * numberOfChannels * samplesUsed];
- for (int i = 0; i < samplesUsed; i++)
- {
- for (int j = 0; j < numberOfChannels; j++)
- {
- bytes[pos + 0] = (byte)(samples[j][i] >> 8);
- bytes[pos + 1] = (byte)(samples[j][i] >> 16);
- bytes[pos + 2] = (byte)(samples[j][i] >> 24);
- pos += 3;
- }
+ }
+ MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
+ byte[] check = provider.ComputeHash(bytes);
+ if (check.Length != md5.Length) {
+ throw new InvalidOperationException();
+ }
+ for (int i = 0; i < check.Length; i++) {
+ if (check[i] != md5[i]) {
+ throw new InvalidDataException("MD5 failed.");
}
- check = provider.ComputeHash(bytes);
- if (check.Length != md5.Length)
- {
- throw new InvalidOperationException();
+ }
+ } else if (bitsPerSample == 24) {
+ /* For 24 bits per sample */
+ bytes = new byte[3 * numberOfChannels * samplesUsed];
+ int pos = 0;
+ for (int i = 0; i < samplesUsed; i++) {
+ for (int j = 0; j < numberOfChannels; j++) {
+ bytes[pos + 0] = (byte)(samples[j][i] >> 8);
+ bytes[pos + 1] = (byte)(samples[j][i] >> 16);
+ bytes[pos + 2] = (byte)(samples[j][i] >> 24);
+ pos += 3;
}
- for (int i = 0; i < check.Length; i++)
- {
- if (check[i] != md5[i])
- {
- throw new InvalidDataException("MD5 failed.");
- }
+ }
+ MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
+ byte[] check = provider.ComputeHash(bytes);
+ if (check.Length != md5.Length) {
+ throw new InvalidOperationException();
+ }
+ for (int i = 0; i < check.Length; i++) {
+ if (check[i] != md5[i]) {
+ throw new InvalidDataException("MD5 failed.");
}
- break;
+ }
+ } else {
+ /* Let's just skip the MD5 check in other cases
+ * or feel free to implement the check here. */
}
- /* Let's just skip the MD5 check in other cases
- * or feel free to implement the check here. */
}
#endif
// --- end of file ---
@@ -559,22 +541,22 @@ private static int[] ReadResiduals(BitReader reader, int predictorOrder, int blo
}
}
return residuals;
+ } else {
+ // --- not supported ---
+ throw new InvalidDataException();
}
- // --- not supported --- (methods 3+ are stated as reserved in FLAC specification)
- throw new InvalidDataException();
}
/// Gets a signed integer from an unsigned integer assuming the unsigned integer is stored in two's complement notation.
/// The unsigned integer.
/// The value range, e.g. 16 for 4 bits, 256 for 8 bits, 65536 for 16 bits, etc.
/// The signed integer.
- private static int FromTwosComplement(uint value, uint range)
- {
+ private static int FromTwosComplement(uint value, uint range) {
if (value < (range >> 1)) {
return (int)value;
+ } else {
+ return (int)value - (int)range;
}
-
- return (int)value - (int)range;
}
}
diff --git a/source/Plugins/Sound.Flac/Plugin.cs b/source/Plugins/Sound.Flac/Plugin.cs
index c81ba5a1f4..851d6ed633 100644
--- a/source/Plugins/Sound.Flac/Plugin.cs
+++ b/source/Plugins/Sound.Flac/Plugin.cs
@@ -22,10 +22,6 @@ public override bool CanLoadSound(string path) {
}
using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
- if (stream.Length == 0)
- {
- return false;
- }
using (BinaryReader reader = new BinaryReader(stream))
{
if (reader.ReadUInt32() != 0x43614C66)
diff --git a/source/Plugins/Sound.Flac/app.config b/source/Plugins/Sound.Flac/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Sound.Flac/app.config
+++ b/source/Plugins/Sound.Flac/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Sound.MP3/Plugin.cs b/source/Plugins/Sound.MP3/Plugin.cs
index 45427cdb80..c7867c2e47 100644
--- a/source/Plugins/Sound.MP3/Plugin.cs
+++ b/source/Plugins/Sound.MP3/Plugin.cs
@@ -50,10 +50,6 @@ public override bool CanLoadSound(string path)
using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
- if (stream.Length == 0)
- {
- return false;
- }
using (BinaryReader reader = new BinaryReader(stream))
{
byte[] magicNumber = reader.ReadBytes(3);
diff --git a/source/Plugins/Sound.MP3/app.config b/source/Plugins/Sound.MP3/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Sound.MP3/app.config
+++ b/source/Plugins/Sound.MP3/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Sound.RiffWave/Chunks/DataChunk.cs b/source/Plugins/Sound.RiffWave/Chunks/DataChunk.cs
index 465c9f3495..ef793e9724 100644
--- a/source/Plugins/Sound.RiffWave/Chunks/DataChunk.cs
+++ b/source/Plugins/Sound.RiffWave/Chunks/DataChunk.cs
@@ -7,15 +7,14 @@ internal class DataChunk : Chunk
{
public DataChunk(byte[] dataBytes, WaveFormatEx format) : base(format.Channels)
{
- if (format is WaveFormatAdPcm)
+ if (!(format is WaveFormatAdPcm))
{
- BytesPerSample = 2;
+ BytesPerSample = format.BitsPerSample / 8;
}
else
{
- BytesPerSample = format.BitsPerSample / 8;
- }
-
+ BytesPerSample = 2;
+ }
// The size of the data chunk may not be correct, so we use sampleCount as the standard thereafter.
int sampleCount = dataBytes.Length / (format.Channels * BytesPerSample);
diff --git a/source/Plugins/Sound.RiffWave/Plugin.Parser.cs b/source/Plugins/Sound.RiffWave/Plugin.Parser.cs
index 6e26a76ffe..10f1f56714 100644
--- a/source/Plugins/Sound.RiffWave/Plugin.Parser.cs
+++ b/source/Plugins/Sound.RiffWave/Plugin.Parser.cs
@@ -1,15 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
using NAudio.Wave;
+using NLayer.NAudioSupport;
using OpenBveApi;
using OpenBveApi.Math;
+using OpenBveApi.Objects;
using OpenBveApi.Sounds;
-using System;
-using System.Collections.Generic;
-using System.IO;
namespace Plugin
{
public partial class Plugin
{
+
+
+
+ // --- functions ---
+
/// Reads wave data from a WAVE file.
/// The file name of the WAVE file.
/// The wave data.
@@ -17,54 +24,49 @@ private static Sound LoadFromFile(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
- return LoadFromStream(stream);
- }
- }
+ using (BinaryReader reader = new BinaryReader(stream))
+ {
+ Endianness endianness;
+ uint headerCkID = reader.ReadUInt32();
- private static Sound LoadFromStream(Stream stream)
- {
- using (BinaryReader reader = new BinaryReader(stream))
- {
- Endianness endianness;
- uint headerCkID = reader.ReadUInt32();
+ // "RIFF"
+ if (headerCkID == 0x46464952)
+ {
+ endianness = Endianness.Little;
+ }
+ // "RIFX"
+ else if (headerCkID == 0x58464952)
+ {
+ endianness = Endianness.Big;
+ }
+ else
+ {
+ // unsupported format
+ throw new InvalidDataException("Invalid header chunk ID");
+ }
- // "RIFF"
- if (headerCkID == 0x46464952)
- {
- endianness = Endianness.Little;
- }
- // "RIFX"
- else if (headerCkID == 0x58464952)
- {
- endianness = Endianness.Big;
- }
- else
- {
- // unsupported format
- throw new InvalidDataException("Invalid header chunk ID");
- }
+ uint headerCkSize = reader.ReadUInt32(endianness);
- uint headerCkSize = reader.ReadUInt32(endianness);
+ uint formType = reader.ReadUInt32(endianness);
- uint formType = reader.ReadUInt32(endianness);
+ // "WAVE"
+ if (formType == 0x45564157)
+ {
+ return WaveLoadFromStream(reader, endianness, headerCkSize + 8);
+ }
- // "WAVE"
- if (formType == 0x45564157)
- {
- return WaveLoadFromStream(reader, endianness, headerCkSize + 8);
+ // unsupported format
+ throw new InvalidDataException("Unsupported format");
}
-
- // unsupported format
- throw new InvalidDataException("Unsupported format");
}
}
- /// Reads sound data from a MP3 stream, using NAudio
- /// The stream of the MP3
- /// The raw sound data
+ /// Reads sound data from a MP3 stream.
+ /// The stream of the MP3.
+ /// The raw sound data.
private static Sound Mp3LoadFromStream(Stream stream)
{
- using (Mp3FileReader reader = new Mp3FileReader(stream))
+ using (Mp3FileReader reader = new Mp3FileReader(stream, wf => new Mp3FrameDecompressor(wf)))
{
byte[] dataBytes = new byte[reader.Length];
@@ -98,11 +100,6 @@ private static Sound Mp3LoadFromStream(Stream stream)
sample = 1.0f;
}
- if (float.IsNaN(sample))
- {
- sample = 0;
- }
-
writer.Write((short)(sample * short.MaxValue));
}
}
@@ -123,25 +120,6 @@ private static Sound Mp3LoadFromStream(Stream stream)
}
}
- /// Loads sound data from a stream using NAudio to resample it to something we can read
- /// The stream
- /// The sound
- private static Sound NAudioLoadFromStream(Stream stream)
- {
- using (WaveStream wf = new WaveFileReader(stream))
- {
- using (WaveFormatConversionStream cf = (WaveFormatConversionStream)WaveFormatConversionStream.CreatePcmStream(wf))
- {
- using (MemoryStream ms = new MemoryStream())
- {
- WaveFileWriter.WriteWavFileToStream(ms, cf);
- ms.Seek(0, SeekOrigin.Begin);
- return LoadFromStream(ms);
- }
- }
- }
- }
-
private static Sound WaveLoadFromStream(BinaryReader reader, Endianness endianness, uint fileSize)
{
long stopPosition = Math.Min(fileSize, reader.BaseStream.Length);
@@ -154,7 +132,6 @@ private static Sound WaveLoadFromStream(BinaryReader reader, Endianness endianne
{
ChunkID ckID = (ChunkID)reader.ReadUInt32(endianness);
uint ckSize = reader.ReadUInt32(endianness);
- long ckStart = reader.BaseStream.Position;
// "fmt "
switch (ckID)
@@ -176,12 +153,6 @@ private static Sound WaveLoadFromStream(BinaryReader reader, Endianness endianne
case 0x0002:
format = new WaveFormatAdPcm(wFormatTag);
break;
- case 0x0011:
- case 0x0031:
- // 0x0011 - Intel DVI ADPCM
- // 0x0031 - GSM610
- reader.BaseStream.Seek(0, 0);
- return NAudioLoadFromStream(reader.BaseStream);
case 0x0050:
case 0x0055:
format = new WaveFormatMp3(wFormatTag);
@@ -394,15 +365,6 @@ private static Sound WaveLoadFromStream(BinaryReader reader, Endianness endianne
}
}
}
-
- if (format is WaveFormatMp3)
- {
- using (MemoryStream dataStream = new MemoryStream(dataBytes))
- {
- return Mp3LoadFromStream(dataStream);
- }
- }
-
chunks.Add(new DataChunk(dataBytes, format));
break;
case ChunkID.CUE:
@@ -427,9 +389,6 @@ private static Sound WaveLoadFromStream(BinaryReader reader, Endianness endianne
break;
}
- // ensure we're actually at the end of the chunk
- reader.BaseStream.Seek(ckStart + ckSize, SeekOrigin.Begin);
-
// pad byte
if ((ckSize & 1) == 1)
{
@@ -443,6 +402,14 @@ private static Sound WaveLoadFromStream(BinaryReader reader, Endianness endianne
throw new InvalidDataException("File contains no DATA or SLNT chunks.");
}
+ if (format is WaveFormatMp3)
+ {
+ using (MemoryStream dataStream = new MemoryStream(dataBytes))
+ {
+ return Mp3LoadFromStream(dataStream);
+ }
+ }
+
byte[][] buffers = new byte[format.Channels][];
int startPosition = 0;
diff --git a/source/Plugins/Sound.RiffWave/Plugin.cs b/source/Plugins/Sound.RiffWave/Plugin.cs
index 97f7439eed..c9d650d0a6 100644
--- a/source/Plugins/Sound.RiffWave/Plugin.cs
+++ b/source/Plugins/Sound.RiffWave/Plugin.cs
@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
using OpenBveApi;
using OpenBveApi.Hosts;
using OpenBveApi.Math;
@@ -29,10 +29,6 @@ public override bool CanLoadSound(string path)
using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
- if (stream.Length == 0)
- {
- return false;
- }
using (BinaryReader reader = new BinaryReader(stream))
{
Endianness endianness;
diff --git a/source/Plugins/Sound.RiffWave/app.config b/source/Plugins/Sound.RiffWave/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Sound.RiffWave/app.config
+++ b/source/Plugins/Sound.RiffWave/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Sound.Vorbis/Plugin.cs b/source/Plugins/Sound.Vorbis/Plugin.cs
index d24c2abb1b..1e6f727212 100644
--- a/source/Plugins/Sound.Vorbis/Plugin.cs
+++ b/source/Plugins/Sound.Vorbis/Plugin.cs
@@ -27,10 +27,6 @@ public override bool CanLoadSound(string path)
using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
- if (stream.Length == 0)
- {
- return false;
- }
using (BinaryReader reader = new BinaryReader(stream))
{
uint headerCkID = reader.ReadUInt32();
diff --git a/source/Plugins/Sound.Vorbis/app.config b/source/Plugins/Sound.Vorbis/app.config
index 10fc19e69c..7a7be13580 100644
--- a/source/Plugins/Sound.Vorbis/app.config
+++ b/source/Plugins/Sound.Vorbis/app.config
@@ -8,7 +8,7 @@
-
+
diff --git a/source/Plugins/Texture.Ace/Plugin.Parser.cs b/source/Plugins/Texture.Ace/Plugin.Parser.cs
index 71f309684f..bf88d74d23 100644
--- a/source/Plugins/Texture.Ace/Plugin.Parser.cs
+++ b/source/Plugins/Texture.Ace/Plugin.Parser.cs
@@ -118,7 +118,12 @@ private static bool CanLoadUncompressedData(byte[] data)
}
identifier = LittleEndianBinaryExtensions.ToUInt64(data, 8);
- return identifier == DataStart;
+ if (identifier != DataStart)
+ {
+ return false;
+ }
+
+ return true;
}
/// Queries the texture dimensions of the specified file.
@@ -345,7 +350,7 @@ private static OpenBveApi.Textures.Texture LoadFromUncompressedData(byte[] data)
int counter = 0;
for (int x = 0; x < width; x++)
{
- byte mask = (byte)(0x80 >> (x & 0x7));
+ var mask = (byte)(0x80 >> (x & 0x7));
if (counter == 0)
{
value = reader.ReadByte();
@@ -521,6 +526,7 @@ private static byte[] DecompressAce(byte[] data)
}
byte flg = reader.ReadByte();
+ // int fcheck = flg & 31;
if ((256 * cmf + flg) % 31 != 0)
{
throw new InvalidDataException();
diff --git a/source/Plugins/Texture.Ace/Plugin.cs b/source/Plugins/Texture.Ace/Plugin.cs
index 59a154750a..46fed5aa0c 100644
--- a/source/Plugins/Texture.Ace/Plugin.cs
+++ b/source/Plugins/Texture.Ace/Plugin.cs
@@ -28,7 +28,10 @@ public override bool QueryTextureDimensions(string path, out int width, out int
/// Whether the plugin can load the specified texture.
public override bool CanLoadTexture(string path)
{
- return File.Exists(path) && CanLoadFile(path);
+ if (File.Exists(path)) {
+ return CanLoadFile(path);
+ }
+ return false;
}
/// Loads the specified texture.
diff --git a/source/Plugins/Texture.Ace/app.config b/source/Plugins/Texture.Ace/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Texture.Ace/app.config
+++ b/source/Plugins/Texture.Ace/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Texture.BmpGifJpegPngTiff/BMP/BmpDecoder.cs b/source/Plugins/Texture.BmpGifJpegPngTiff/BMP/BmpDecoder.cs
index 441c7f08d7..c837eab55d 100644
--- a/source/Plugins/Texture.BmpGifJpegPngTiff/BMP/BmpDecoder.cs
+++ b/source/Plugins/Texture.BmpGifJpegPngTiff/BMP/BmpDecoder.cs
@@ -72,7 +72,7 @@ internal class BmpDecoder : IDisposable
internal BitsPerPixel BitsPerPixel;
/// The image data
internal byte[] ImageData;
- /// Stores the color table when using a restricted palette
+ /// Stores the color table when using a restricted pallette
internal Color24[] ColorTable;
/// The bitmap format
internal BmpFormat Format;
diff --git a/source/Plugins/Texture.BmpGifJpegPngTiff/GIF/GifDecoder.cs b/source/Plugins/Texture.BmpGifJpegPngTiff/GIF/GifDecoder.cs
index d5ff87a16e..9ad0006c55 100644
--- a/source/Plugins/Texture.BmpGifJpegPngTiff/GIF/GifDecoder.cs
+++ b/source/Plugins/Texture.BmpGifJpegPngTiff/GIF/GifDecoder.cs
@@ -545,7 +545,7 @@ protected void ReadContents()
app += (char) block[i];
}
- if (app.Equals(@"NETSCAPE2.0") || app.Equals(@"ANIMEXTS1.0"))
+ if (app.Equals("NETSCAPE2.0") || app.Equals("ANIMEXTS1.0"))
{
ReadNetscapeExt();
}
@@ -731,7 +731,7 @@ protected void ResetFrame()
dispose = DisposeMode.NoAction;
}
- /// Skips variable length blocks up-to and including the next zero length block
+ /// Skips variable length blocks upto and including the next zero length block
protected void Skip()
{
do
diff --git a/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/ColorType.cs b/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/ColorType.cs
index 44000e3d7b..fc26fbeae5 100644
--- a/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/ColorType.cs
+++ b/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/ColorType.cs
@@ -9,7 +9,7 @@ internal enum ColorType : byte
Rgb = 2,
/// Each pixel is a palette index
///A PLTE chunk must be present
- Paletted = 3,
+ Palleted = 3,
/// Each pixel is a grayscale sample, followed by an alpha sample
GrayscaleAlpha = 4,
/// Each pixel is a R,G,B triple, followed by an alpha sample
diff --git a/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/PngDecoder.cs b/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/PngDecoder.cs
index 263028c18b..f5208b60f0 100644
--- a/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/PngDecoder.cs
+++ b/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/PngDecoder.cs
@@ -148,7 +148,7 @@ internal bool Read(string fileName)
switch (ColorType)
{
- case ColorType.Paletted: // each filtered byte becomes a palette index
+ case ColorType.Palleted: // each filtered byte becomes a pallete index
case ColorType.Grayscale:
BytesPerPixel = 1;
break;
@@ -166,9 +166,9 @@ internal bool Read(string fileName)
return false;
}
- ScanlineLength = Math.Max(1, (int)Math.Ceiling((Width * BytesPerPixel) / (double)ScanlineLength)); // scanline must be a minimum of 1 byte in length. Always round up
+ ScanlineLength = Math.Max(1, (int)Math.Ceiling((Width * BytesPerPixel) / (double)ScanlineLength)); // scanline must be a minumum of 1 byte in length. Always round up
- pixelBuffer = ColorType != ColorType.Paletted && ColorType != ColorType.GrayscaleAlpha && BytesPerPixel != 8 ? new byte[Width * Height * BytesPerPixel] : new byte[Width * Height * 4];
+ pixelBuffer = ColorType != ColorType.Palleted && ColorType != ColorType.GrayscaleAlpha && BytesPerPixel != 8 ? new byte[Width * Height * BytesPerPixel] : new byte[Width * Height * 4];
break;
case ChunkType.PLTE:
colorPalette = new Palette(chunkBuffer);
@@ -276,7 +276,7 @@ internal bool Read(string fileName)
switch (ColorType)
{
- case ColorType.Paletted:
+ case ColorType.Palleted:
{
int pixelIndex = 0;
switch (BitDepth)
@@ -505,7 +505,7 @@ internal bool Read(string fileName)
Adam7.GetPixelIndexForScanlineInPass(currentPass, currentScanline, j, out pixelX, out pixelY);
switch (ColorType)
{
- case ColorType.Paletted:
+ case ColorType.Palleted:
{
// we're always converting to 4bpp in the output, but need the native bpp to find our position in the array, so don't actually set it
int start = Width * 4 * pixelY + pixelX * 4;
@@ -590,7 +590,7 @@ internal bool Read(string fileName)
}
}
- if (ColorType == ColorType.Paletted || ColorType == ColorType.GrayscaleAlpha || BytesPerPixel == 8)
+ if (ColorType == ColorType.Palleted || ColorType == ColorType.GrayscaleAlpha || BytesPerPixel == 8)
{
// need the final bpp to reflect what we've converted the image to, not the bpp in the file used whilst loading
BytesPerPixel = 4;
diff --git a/source/Plugins/Texture.BmpGifJpegPngTiff/app.config b/source/Plugins/Texture.BmpGifJpegPngTiff/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Texture.BmpGifJpegPngTiff/app.config
+++ b/source/Plugins/Texture.BmpGifJpegPngTiff/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Texture.Dds/Dds.FourCc.cs b/source/Plugins/Texture.Dds/Dds.FourCc.cs
index 55f323c128..0c5650252a 100644
--- a/source/Plugins/Texture.Dds/Dds.FourCc.cs
+++ b/source/Plugins/Texture.Dds/Dds.FourCc.cs
@@ -13,7 +13,7 @@
namespace Texture.Dds
{
/// The known DDS FourCC values
- internal enum FourCC : uint
+ enum FourCC : uint
{
DXT1 = 0x31545844,
DXT2 = 0x32545844,
diff --git a/source/Plugins/Texture.Dds/Plugin.Parser.cs b/source/Plugins/Texture.Dds/Plugin.Parser.cs
index b0be386a19..4e7e5a866b 100644
--- a/source/Plugins/Texture.Dds/Plugin.Parser.cs
+++ b/source/Plugins/Texture.Dds/Plugin.Parser.cs
@@ -402,7 +402,7 @@ private static uint HalfToFloat(ushort y)
//
// Normalized number
//
- e += 127 - 15;
+ e += (127 - 15);
m <<= 13;
//
@@ -454,38 +454,38 @@ private byte[] DecompressData(DdsHeader header, byte[] data, PixelFormat pixelFo
switch (pixelFormat)
{
case PixelFormat.RGBA:
- rawData = DecompressRGBA(header, data, pixelFormat);
+ rawData = this.DecompressRGBA(header, data, pixelFormat);
break;
case PixelFormat.RGB:
- rawData = DecompressRGB(header, data, pixelFormat);
+ rawData = this.DecompressRGB(header, data, pixelFormat);
break;
case PixelFormat.LUMINANCE:
case PixelFormat.LUMINANCE_ALPHA:
- rawData = DecompressLum(header, data, pixelFormat);
+ rawData = this.DecompressLum(header, data, pixelFormat);
break;
case PixelFormat.DXT1:
- rawData = DecompressDXT1(header, data, pixelFormat);
+ rawData = this.DecompressDXT1(header, data, pixelFormat);
break;
case PixelFormat.DXT2:
- rawData = DecompressDXT2(header, data, pixelFormat);
+ rawData = this.DecompressDXT2(header, data, pixelFormat);
break;
case PixelFormat.DXT3:
- rawData = DecompressDXT3(header, data, pixelFormat);
+ rawData = this.DecompressDXT3(header, data, pixelFormat);
break;
case PixelFormat.DXT4:
- rawData = DecompressDXT4(header, data, pixelFormat);
+ rawData = this.DecompressDXT4(header, data, pixelFormat);
break;
case PixelFormat.DXT5:
- rawData = DecompressDXT5(header, data, pixelFormat);
+ rawData = this.DecompressDXT5(header, data, pixelFormat);
break;
case PixelFormat.THREEDC:
- rawData = Decompress3Dc(header, data, pixelFormat);
+ rawData = this.Decompress3Dc(header, data, pixelFormat);
break;
case PixelFormat.ATI1N:
- rawData = DecompressAti1n(header, data, pixelFormat);
+ rawData = this.DecompressAti1n(header, data, pixelFormat);
break;
case PixelFormat.RXGB:
- rawData = DecompressRXGB(header, data, pixelFormat);
+ rawData = this.DecompressRXGB(header, data, pixelFormat);
break;
case PixelFormat.R16F:
case PixelFormat.G16R16F:
@@ -493,7 +493,7 @@ private byte[] DecompressData(DdsHeader header, byte[] data, PixelFormat pixelFo
case PixelFormat.R32F:
case PixelFormat.G32R32F:
case PixelFormat.A32B32G32R32F:
- rawData = DecompressFloat(header, data, pixelFormat);
+ rawData = this.DecompressFloat(header, data, pixelFormat);
break;
default:
throw new InvalidDataException("Unsupported DDS PixelFormat value");
@@ -506,8 +506,8 @@ private unsafe byte[] DecompressDXT1(DdsHeader header, byte[] data, PixelFormat
{
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ int sizeofplane = bps * header.height;
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
Color32[] colours = new Color32[4];
colours[0].A = 0xFF;
@@ -562,7 +562,7 @@ private unsafe byte[] DecompressDXT1(DdsHeader header, byte[] data, PixelFormat
Color32 col = colours[select];
if (((x + i) < header.width) && ((y + j) < header.height))
{
- uint offset = (uint)(z * sizeOfPlane + (y + j) * bps + (x + i) * bpp);
+ uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp);
rawData[offset + 0] = col.R;
rawData[offset + 1] = col.G;
rawData[offset + 2] = col.B;
@@ -589,8 +589,8 @@ private unsafe byte[] DecompressDXT3(DdsHeader header, byte[] data, PixelFormat
{
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ int sizeofplane = bps * header.height;
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
Color32[] colours = new Color32[4];
fixed (byte* bytePtr = data)
{
@@ -625,7 +625,7 @@ private unsafe byte[] DecompressDXT3(DdsHeader header, byte[] data, PixelFormat
if (((x + i) < header.width) && ((y + j) < header.height))
{
- uint offset = (uint)(z * sizeOfPlane + (y + j) * bps + (x + i) * bpp);
+ uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp);
rawData[offset + 0] = colours[select].R;
rawData[offset + 1] = colours[select].G;
rawData[offset + 2] = colours[select].B;
@@ -640,7 +640,7 @@ private unsafe byte[] DecompressDXT3(DdsHeader header, byte[] data, PixelFormat
{
if (((x + i) < header.width) && ((y + j) < header.height))
{
- uint offset = (uint)(z * sizeOfPlane + (y + j) * bps + (x + i) * bpp + 3);
+ uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp + 3);
rawData[offset] = (byte)(word & 0x0F);
rawData[offset] = (byte)(rawData[offset] | (rawData[offset] << 4));
}
@@ -667,9 +667,9 @@ private unsafe byte[] DecompressDXT5(DdsHeader header, byte[] data, PixelFormat
// allocate bitmap
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
+ int sizeofplane = bps * header.height;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
Color32[] colours = new Color32[4];
ushort[] alphas = new ushort[8];
@@ -687,7 +687,7 @@ private unsafe byte[] DecompressDXT5(DdsHeader header, byte[] data, PixelFormat
alphas[0] = temp[0];
alphas[1] = temp[1];
- byte* alphaMask = (temp + 2);
+ byte* alphamask = (temp + 2);
temp += 8;
DxtcReadColors(temp, ref colours);
@@ -709,7 +709,7 @@ private unsafe byte[] DecompressDXT5(DdsHeader header, byte[] data, PixelFormat
// only put pixels out < width or height
if (((x + i) < header.width) && ((y + j) < header.height))
{
- uint offset = (uint)(z * sizeOfPlane + (y + j) * bps + (x + i) * bpp);
+ uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp);
rawData[offset] = col.R;
rawData[offset + 1] = col.G;
rawData[offset + 2] = col.B;
@@ -745,7 +745,8 @@ private unsafe byte[] DecompressDXT5(DdsHeader header, byte[] data, PixelFormat
// it operates on a 6-byte system.
// First three bytes
- uint bits = (uint)((alphaMask[0]) | (alphaMask[1] << 8) | (alphaMask[2] << 16));
+ //uint bits = (uint)(alphamask[0]);
+ uint bits = (uint)((alphamask[0]) | (alphamask[1] << 8) | (alphamask[2] << 16));
for (int j = 0; j < 2; j++)
{
for (int i = 0; i < 4; i++)
@@ -753,7 +754,7 @@ private unsafe byte[] DecompressDXT5(DdsHeader header, byte[] data, PixelFormat
// only put pixels out < width or height
if (((x + i) < header.width) && ((y + j) < header.height))
{
- uint offset = (uint)(z * sizeOfPlane + (y + j) * bps + (x + i) * bpp + 3);
+ uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp + 3);
rawData[offset] = (byte)alphas[bits & 0x07];
}
bits >>= 3;
@@ -761,7 +762,8 @@ private unsafe byte[] DecompressDXT5(DdsHeader header, byte[] data, PixelFormat
}
// Last three bytes
- bits = (uint)((alphaMask[3]) | (alphaMask[4] << 8) | (alphaMask[5] << 16));
+ //bits = (uint)(alphamask[3]);
+ bits = (uint)((alphamask[3]) | (alphamask[4] << 8) | (alphamask[5] << 16));
for (int j = 2; j < 4; j++)
{
for (int i = 0; i < 4; i++)
@@ -769,7 +771,7 @@ private unsafe byte[] DecompressDXT5(DdsHeader header, byte[] data, PixelFormat
// only put pixels out < width or height
if (((x + i) < header.width) && ((y + j) < header.height))
{
- uint offset = (uint)(z * sizeOfPlane + (y + j) * bps + (x + i) * bpp + 3);
+ uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp + 3);
rawData[offset] = (byte)alphas[bits & 0x07];
}
bits >>= 3;
@@ -788,9 +790,9 @@ private unsafe byte[] DecompressRGB(DdsHeader header, byte[] data, PixelFormat p
// allocate bitmap
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
+ int sizeofplane = bps * header.height;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
uint valMask;
unchecked
{
@@ -831,9 +833,9 @@ private unsafe byte[] DecompressRGBA(DdsHeader header, byte[] data, PixelFormat
// allocate bitmap
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
+ int sizeofplane = bps * header.height;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
uint valMask;
unchecked
{
@@ -878,9 +880,9 @@ private unsafe byte[] Decompress3Dc(DdsHeader header, byte[] data, PixelFormat p
// allocate bitmap
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
+ int sizeofplane = bps * header.height;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
byte[] yColours = new byte[8];
byte[] xColours = new byte[8];
@@ -982,9 +984,9 @@ private unsafe byte[] DecompressAti1n(DdsHeader header, byte[] data, PixelFormat
// allocate bitmap
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
+ int sizeofplane = bps * header.height;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
byte[] colours = new byte[8];
uint offset = 0;
@@ -1051,9 +1053,9 @@ private unsafe byte[] DecompressLum(DdsHeader header, byte[] data, PixelFormat p
// allocate bitmap
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
+ int sizeofplane = bps * header.height;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
int lShift1; int lMul; int lShift2;
ComputeMaskParams(header.pixelFormat.rbitmask, out lShift1, out lMul, out lShift2);
@@ -1081,9 +1083,9 @@ private unsafe byte[] DecompressRXGB(DdsHeader header, byte[] data, PixelFormat
// allocate bitmap
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
+ int sizeofplane = bps * header.height;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
Color32 color_0 = new Color32();
Color32 color_1 = new Color32();
@@ -1103,7 +1105,7 @@ private unsafe byte[] DecompressRXGB(DdsHeader header, byte[] data, PixelFormat
break;
alphas[0] = temp[0];
alphas[1] = temp[1];
- byte* alphaMask = temp + 2;
+ byte* alphamask = temp + 2;
temp += 8;
DxtcReadColors(temp, ref color_0, ref color_1);
@@ -1147,7 +1149,7 @@ private unsafe byte[] DecompressRXGB(DdsHeader header, byte[] data, PixelFormat
// only put pixels out < width or height
if (((x + i) < header.width) && ((y + j) < header.height))
{
- uint offset = (uint)(z * sizeOfPlane + (y + j) * bps + (x + i) * bpp);
+ uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp);
rawData[offset + 0] = col.R;
rawData[offset + 1] = col.G;
rawData[offset + 2] = col.B;
@@ -1182,7 +1184,7 @@ private unsafe byte[] DecompressRXGB(DdsHeader header, byte[] data, PixelFormat
// Note: Have to separate the next two loops,
// it operates on a 6-byte system.
// First three bytes
- uint bits = *((uint*)alphaMask);
+ uint bits = *((uint*)alphamask);
for (int j = 0; j < 2; j++)
{
for (int i = 0; i < 4; i++)
@@ -1190,7 +1192,7 @@ private unsafe byte[] DecompressRXGB(DdsHeader header, byte[] data, PixelFormat
// only put pixels out < width or height
if (((x + i) < header.width) && ((y + j) < header.height))
{
- uint offset = (uint)(z * sizeOfPlane + (y + j) * bps + (x + i) * bpp + 3);
+ uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp + 3);
rawData[offset] = alphas[bits & 0x07];
}
bits >>= 3;
@@ -1198,7 +1200,7 @@ private unsafe byte[] DecompressRXGB(DdsHeader header, byte[] data, PixelFormat
}
// Last three bytes
- bits = *((uint*)&alphaMask[3]);
+ bits = *((uint*)&alphamask[3]);
for (int j = 2; j < 4; j++)
{
for (int i = 0; i < 4; i++)
@@ -1206,7 +1208,7 @@ private unsafe byte[] DecompressRXGB(DdsHeader header, byte[] data, PixelFormat
// only put pixels out < width or height
if (((x + i) < header.width) && ((y + j) < header.height))
{
- uint offset = (uint)(z * sizeOfPlane + (y + j) * bps + (x + i) * bpp + 3);
+ uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp + 3);
rawData[offset] = alphas[bits & 0x07];
}
bits >>= 3;
@@ -1224,24 +1226,26 @@ private unsafe byte[] DecompressFloat(DdsHeader header, byte[] data, PixelFormat
// allocate bitmap
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
+ int sizeofplane = bps * header.height;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
fixed (byte* bytePtr = data)
{
- fixed (byte* destPtr = rawData)
+ byte* temp = bytePtr;
+ fixed (byte* destPtr = rawData)
{
- int size;
+ byte* destData = destPtr;
+ int size;
switch (pixelFormat)
{
case PixelFormat.R32F: // Red float, green = blue = max
size = header.width * header.height * header.depth * 3;
for (int i = 0, j = 0; i < size; i += 3, j++)
{
- ((float*)destPtr)[i] = ((float*)bytePtr)[j];
- ((float*)destPtr)[i + 1] = 1.0f;
- ((float*)destPtr)[i + 2] = 1.0f;
+ ((float*)destData)[i] = ((float*)temp)[j];
+ ((float*)destData)[i + 1] = 1.0f;
+ ((float*)destData)[i + 2] = 1.0f;
}
break;
@@ -1253,25 +1257,25 @@ private unsafe byte[] DecompressFloat(DdsHeader header, byte[] data, PixelFormat
size = header.width * header.height * header.depth * 3;
for (int i = 0, j = 0; i < size; i += 3, j += 2)
{
- ((float*)destPtr)[i] = ((float*)bytePtr)[j];
- ((float*)destPtr)[i + 1] = ((float*)bytePtr)[j + 1];
- ((float*)destPtr)[i + 2] = 1.0f;
+ ((float*)destData)[i] = ((float*)temp)[j];
+ ((float*)destData)[i + 1] = ((float*)temp)[j + 1];
+ ((float*)destData)[i + 2] = 1.0f;
}
break;
case PixelFormat.R16F: // Red float, green = blue = max
size = header.width * header.height * header.depth * bpp;
- ConvR16ToFloat32((uint*)destPtr, (ushort*)bytePtr, (uint)size);
+ ConvR16ToFloat32((uint*)destData, (ushort*)temp, (uint)size);
break;
case PixelFormat.A16B16G16R16F: // Just convert from half to float.
size = header.width * header.height * header.depth * bpp;
- ConvFloat16ToFloat32((uint*)destPtr, (ushort*)bytePtr, (uint)size);
+ ConvFloat16ToFloat32((uint*)destData, (ushort*)temp, (uint)size);
break;
case PixelFormat.G16R16F: // Convert from half to float, set blue = max.
size = header.width * header.height * header.depth * bpp;
- ConvG16R16ToFloat32((uint*)destPtr, (ushort*)bytePtr, (uint)size);
+ ConvG16R16ToFloat32((uint*)destData, (ushort*)temp, (uint)size);
break;
default:
throw new NotImplementedException("Decompression of PixelFormat " + pixelFormat + " has not been implemented in this plugin.");
@@ -1287,13 +1291,13 @@ private unsafe byte[] DecompressARGB(DdsHeader header, byte[] data, PixelFormat
// allocate bitmap
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
+ int sizeofplane = bps * header.height;
if (header.Check16BitComponents())
return DecompressARGB16(header, data, pixelFormat);
int sizeOfData = (header.width * header.pixelFormat.rgbbitcount / 8) * header.height * header.depth;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
if ((pixelFormat == PixelFormat.LUMINANCE) && (header.pixelFormat.rgbbitcount == 16) && (header.pixelFormat.rbitmask == 0xFFFF))
{
@@ -1381,10 +1385,10 @@ private unsafe byte[] DecompressARGB16(DdsHeader header, byte[] data, PixelForma
// allocate bitmap
int bpp = PixelFormatToBpp(pixelFormat, header.pixelFormat.rgbbitcount);
int bps = header.width * bpp * PixelFormatToBpc(pixelFormat);
- int sizeOfPlane = bps * header.height;
+ int sizeofplane = bps * header.height;
int sizeOfData = (header.width * header.pixelFormat.rgbbitcount / 8) * header.height * header.depth;
- byte[] rawData = new byte[header.depth * sizeOfPlane + header.height * bps + header.width * bpp];
+ byte[] rawData = new byte[header.depth * sizeofplane + header.height * bps + header.width * bpp];
uint readI = 0;
uint redL, redR;
diff --git a/source/Plugins/Texture.Dds/app.config b/source/Plugins/Texture.Dds/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Texture.Dds/app.config
+++ b/source/Plugins/Texture.Dds/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Texture.Tga/app.config b/source/Plugins/Texture.Tga/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Texture.Tga/app.config
+++ b/source/Plugins/Texture.Tga/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Train.MsTs/Train.MsTs.csproj b/source/Plugins/Train.MsTs/Train.MsTs.csproj
index 297deff4c3..bed86088c2 100644
--- a/source/Plugins/Train.MsTs/Train.MsTs.csproj
+++ b/source/Plugins/Train.MsTs/Train.MsTs.csproj
@@ -31,12 +31,9 @@
4
-
- ..\..\..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\netstandard2.0\Microsoft.Bcl.AsyncInterfaces.dll
-
-
- ..\..\..\packages\SharpCompress.0.48.0\lib\netstandard2.0\SharpCompress.dll
+
+ ..\..\..\packages\SharpCompress.0.32.2\lib\net461\SharpCompress.dll
@@ -54,11 +51,8 @@
..\..\..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
-
- ..\..\..\packages\System.Text.Encoding.CodePages.8.0.0\lib\netstandard2.0\System.Text.Encoding.CodePages.dll
-
-
- ..\..\..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
+
+ ..\..\..\packages\System.Text.Encoding.CodePages.6.0.0\lib\net461\System.Text.Encoding.CodePages.dll
..\..\..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll
diff --git a/source/Plugins/Train.MsTs/app.config b/source/Plugins/Train.MsTs/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Train.MsTs/app.config
+++ b/source/Plugins/Train.MsTs/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Train.MsTs/packages.config b/source/Plugins/Train.MsTs/packages.config
index 320403e49f..095a12e071 100644
--- a/source/Plugins/Train.MsTs/packages.config
+++ b/source/Plugins/Train.MsTs/packages.config
@@ -1,12 +1,10 @@
-
-
+
-
-
+
\ No newline at end of file
diff --git a/source/Plugins/Train.OpenBve/Panel/PanelAnimatedXmlParser.cs b/source/Plugins/Train.OpenBve/Panel/PanelAnimatedXmlParser.cs
index a2391d615c..d58e05270d 100644
--- a/source/Plugins/Train.OpenBve/Panel/PanelAnimatedXmlParser.cs
+++ b/source/Plugins/Train.OpenBve/Panel/PanelAnimatedXmlParser.cs
@@ -222,7 +222,7 @@ private void CreateTouchElement(ElementsGroup Group, Vector3 Position, Vector3 S
Vertex t7 = new Vertex(-Size.X, Size.Y, Size.Z);
StaticObject Object = new StaticObject(Plugin.CurrentHost);
Object.Mesh.Vertices = new VertexTemplate[] { t0, t1, t2, t3, t4, t5, t6, t7 };
- Object.Mesh.Faces = new[] { new MeshFace(new[] { 0, 1, 2, 0, 2 ,3 }), new MeshFace(new[] { 0, 4, 5, 0, 5, 1 }), new MeshFace(new[] { 0, 3, 7, 0, 7, 4 }), new MeshFace(new[] { 6, 5, 4, 6, 4, 7 }), new MeshFace(new[] { 6, 7, 3, 6, 3, 2 }), new MeshFace(new[] { 6, 2, 1, 6, 1, 5 }) };
+ Object.Mesh.Faces = new[] { new MeshFace(new[] { 0, 1, 2, 3 }), new MeshFace(new[] { 0, 4, 5, 1 }), new MeshFace(new[] { 0, 3, 7, 4 }), new MeshFace(new[] { 6, 5, 4, 7 }), new MeshFace(new[] { 6, 7, 3, 2 }), new MeshFace(new[] { 6, 2, 1, 5 }) };
Object.Mesh.Faces[0].Flags |= FaceFlags.Triangles;
Object.Mesh.Faces[1].Flags |= FaceFlags.Triangles;
Object.Mesh.Faces[2].Flags |= FaceFlags.Triangles;
diff --git a/source/Plugins/Train.OpenBve/Panel/PanelCfgParser.cs b/source/Plugins/Train.OpenBve/Panel/PanelCfgParser.cs
index ec23e51971..7f81362970 100644
--- a/source/Plugins/Train.OpenBve/Panel/PanelCfgParser.cs
+++ b/source/Plugins/Train.OpenBve/Panel/PanelCfgParser.cs
@@ -40,9 +40,6 @@ internal PanelCfgParser(Plugin plugin)
private double WorldLeft, WorldTop;
private double SemiHeight = 240;
- private Texture panelTexture;
- private bool isBackground = true;
-
/// Parses a BVE1 panel.cfg file
/// The on-disk path to the train
/// The train's text encoding
@@ -84,13 +81,11 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
if (File.Exists(PanelBackground))
{
- Plugin.CurrentHost.RegisterTexture(PanelBackground, new TextureParameters(null, Color24.Blue), out panelTexture, true);
+ Plugin.CurrentHost.RegisterTexture(PanelBackground, new TextureParameters(null, Color24.Blue), out var panelTexture, true);
SemiHeight = PanelSize.Y - panelTexture.Height;
- CreateElement(Car, 0, SemiHeight, panelTexture.Width, panelTexture.Height, WorldZ + EyeDistance, false, panelTexture, Color32.White);
+ CreateElement(Car, 0, SemiHeight, panelTexture.Width, panelTexture.Height, WorldZ + EyeDistance, panelTexture, Color32.White);
}
- isBackground = false;
-
string compatibilityFolder = Plugin.FileSystem.GetDataFolder("Compatibility");
while (cfg.RemainingSubBlocks > 0)
{
@@ -116,7 +111,7 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
case PanelSections.PressureGauge:
Angle = 45;
Block.GetValue(PanelKey.Type, out Type);
- PanelSubject[] NeedleType = { PanelSubject.Unknown, PanelSubject.Unknown };
+ int[] NeedleType = { 0, 0 };
Color32[] NeedleColor = { Color32.Black, Color32.Black };
double UnitFactor = 1000;
@@ -129,13 +124,13 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
if (Block.GetEnumValue(PanelKey.LowerHand, out PanelSubject lowerSubject, out Color32 lowerColor))
{
- NeedleType[0] = lowerSubject;
+ NeedleType[0] = (int)lowerSubject;
NeedleColor[0] = lowerColor;
}
if (Block.GetEnumValue(PanelKey.UpperHand, out PanelSubject upperSubject, out Color32 upperColor))
{
- NeedleType[1] = upperSubject;
+ NeedleType[1] = (int)upperSubject;
NeedleColor[1] = upperColor;
}
@@ -176,14 +171,14 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
if (!string.IsNullOrEmpty(Background) && File.Exists(Background))
{
Plugin.CurrentHost.RegisterTexture(Background, new TextureParameters(null, Color24.Blue), out var pressureBackgroundTexture, true);
- CreateElement(Car, Center.X - 0.5 * pressureBackgroundTexture.Width, Center.Y + SemiHeight - 0.5 * pressureBackgroundTexture.Height, WorldZ + EyeDistance - 3.0 * StackDistance, false, pressureBackgroundTexture);
+ CreateElement(Car, Center.X - 0.5 * pressureBackgroundTexture.Width, Center.Y + SemiHeight - 0.5 * pressureBackgroundTexture.Height, WorldZ + EyeDistance - 3.0 * StackDistance, pressureBackgroundTexture);
}
// cover
if (!string.IsNullOrEmpty(Cover) && File.Exists(Cover))
{
Plugin.CurrentHost.RegisterTexture(Cover, new TextureParameters(null, Color24.Blue), out var pressureCoverTexture, true);
- CreateElement(Car, Center.X - 0.5 * pressureCoverTexture.Width, Center.Y + SemiHeight - 0.5 * pressureCoverTexture.Height, WorldZ + EyeDistance - 6.0 * StackDistance, false, pressureCoverTexture);
+ CreateElement(Car, Center.X - 0.5 * pressureCoverTexture.Width, Center.Y + SemiHeight - 0.5 * pressureCoverTexture.Height, WorldZ + EyeDistance - 6.0 * StackDistance, pressureCoverTexture);
}
if (Type == 0)
@@ -195,7 +190,7 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
{
TextureFile = Path.CombineFile(compatibilityFolder, k == 0 ? "needle_pressuregauge_lower.png" : "needle_pressuregauge_upper.png");
Plugin.CurrentHost.RegisterTexture(TextureFile, TextureParameters.NoChange, out var pressureNeedleTexture, true);
- int j = CreateElement(Car, Center.X - Radius * pressureNeedleTexture.AspectRatio, Center.Y + SemiHeight - Radius, 2.0 * Radius * pressureNeedleTexture.AspectRatio, 2.0 * Radius, WorldZ + EyeDistance - (4 + k) * StackDistance, true, pressureNeedleTexture, NeedleColor[k]);
+ int j = CreateElement(Car, Center.X - Radius * pressureNeedleTexture.AspectRatio, Center.Y + SemiHeight - Radius, 2.0 * Radius * pressureNeedleTexture.AspectRatio, 2.0 * Radius, WorldZ + EyeDistance - (4 + k) * StackDistance, pressureNeedleTexture, NeedleColor[k]);
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateZDirection = Vector3.Backward;
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateXDirection = Vector3.Right;
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateYDirection = Vector3.Cross(Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateZDirection, Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateXDirection);
@@ -204,19 +199,19 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
string Variable = "0";
switch (NeedleType[k])
{
- case PanelSubject.BC:
+ case 1:
Variable = "brakecylinder";
break;
- case PanelSubject.SAP:
+ case 2:
Variable = "straightairpipe";
break;
- case PanelSubject.BP:
+ case 3:
Variable = "brakepipe";
break;
- case PanelSubject.ER:
+ case 4:
Variable = "equalizingreservoir";
break;
- case PanelSubject.MR:
+ case 5:
Variable = "mainreservoir";
break;
}
@@ -230,7 +225,7 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
// leds
if (NeedleType[1] != 0)
{
- int j = CreateElement(Car, Center.X - Radius, Center.Y + SemiHeight - Radius, 2.0 * Radius, 2.0 * Radius, WorldZ + EyeDistance - 5.0 * StackDistance, true, null, NeedleColor[1]);
+ int j = CreateElement(Car, Center.X - Radius, Center.Y + SemiHeight - Radius, 2.0 * Radius, 2.0 * Radius, WorldZ + EyeDistance - 5.0 * StackDistance, null, NeedleColor[1]);
double x0 = Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].States[0].Prototype.Mesh.Vertices[0].Coordinates.X;
double y0 = Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].States[0].Prototype.Mesh.Vertices[0].Coordinates.Y;
double z0 = Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].States[0].Prototype.Mesh.Vertices[0].Coordinates.Z;
@@ -278,19 +273,19 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
string Variable;
switch (NeedleType[1])
{
- case PanelSubject.BC:
+ case 1:
Variable = "brakecylinder";
break;
- case PanelSubject.SAP:
+ case 2:
Variable = "straightairpipe";
break;
- case PanelSubject.BP:
+ case 3:
Variable = "brakepipe";
break;
- case PanelSubject.ER:
+ case 4:
Variable = "equalizingreservoir";
break;
- case PanelSubject.MR:
+ case 5:
Variable = "mainreservoir";
break;
default:
@@ -343,14 +338,14 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
{
// background/led
Plugin.CurrentHost.RegisterTexture(Background, new TextureParameters(null, Color24.Blue), out var speedometerBackgroundTexture, true);
- CreateElement(Car, Center.X - 0.5 * speedometerBackgroundTexture.Width, Center.Y + SemiHeight - 0.5 * speedometerBackgroundTexture.Height, WorldZ + EyeDistance - 3.0 * StackDistance, false, speedometerBackgroundTexture);
+ CreateElement(Car, Center.X - 0.5 * speedometerBackgroundTexture.Width, Center.Y + SemiHeight - 0.5 * speedometerBackgroundTexture.Height, WorldZ + EyeDistance - 3.0 * StackDistance, speedometerBackgroundTexture);
}
if (!string.IsNullOrEmpty(Cover))
{
// cover
Plugin.CurrentHost.RegisterTexture(Cover, new TextureParameters(null, Color24.Blue), out var speedometerCoverTexture, true);
- CreateElement(Car, Center.X - 0.5 * speedometerCoverTexture.Width, Center.Y + SemiHeight - 0.5 * speedometerCoverTexture.Height, WorldZ + EyeDistance - 6.0 * StackDistance, false, speedometerCoverTexture);
+ CreateElement(Car, Center.X - 0.5 * speedometerCoverTexture.Width, Center.Y + SemiHeight - 0.5 * speedometerCoverTexture.Height, WorldZ + EyeDistance - 6.0 * StackDistance, speedometerCoverTexture);
}
if (!string.IsNullOrEmpty(ATCPath))
@@ -420,11 +415,11 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
Plugin.CurrentHost.RegisterTexture(ATCPath, new TextureParameters(new TextureClipRegion(j * atcHeight, 0, atcHeight, atcHeight), Color24.Blue), out var ATCTexture, true);
if (j == 0)
{
- k = CreateElement(Car, x, y, atcHeight, atcHeight, WorldZ + EyeDistance - 4.0 * StackDistance, false, ATCTexture, Color32.White);
+ k = CreateElement(Car, x, y, atcHeight, atcHeight, WorldZ + EyeDistance - 4.0 * StackDistance, ATCTexture, Color32.White);
}
else
{
- CreateElement(Car, x, y, atcHeight, atcHeight, WorldZ + EyeDistance - 4.0 * StackDistance, false, ATCTexture, Color32.White, true);
+ CreateElement(Car, x, y, atcHeight, atcHeight, WorldZ + EyeDistance - 4.0 * StackDistance, ATCTexture, Color32.White, true);
}
}
@@ -437,7 +432,7 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
// needle
TextureFile = Path.CombineFile(compatibilityFolder, "needle_speedometer.png");
Plugin.CurrentHost.RegisterTexture(TextureFile, TextureParameters.NoChange, out var speedometerNeedleTexture, true);
- int j = CreateElement(Car, Center.X - Radius * speedometerNeedleTexture.AspectRatio, Center.Y + SemiHeight - Radius, 2.0 * Radius * speedometerNeedleTexture.AspectRatio, 2.0 * Radius, WorldZ + EyeDistance - 5.0 * StackDistance, true, speedometerNeedleTexture, needleColor);
+ int j = CreateElement(Car, Center.X - Radius * speedometerNeedleTexture.AspectRatio, Center.Y + SemiHeight - Radius, 2.0 * Radius * speedometerNeedleTexture.AspectRatio, 2.0 * Radius, WorldZ + EyeDistance - 5.0 * StackDistance, speedometerNeedleTexture, needleColor);
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateZDirection = Vector3.Backward;
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateXDirection = Vector3.Right;
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateYDirection = Vector3.Cross(Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateZDirection, Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].RotateXDirection);
@@ -449,7 +444,7 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
{
// led
if (!needleColorOverridden) needleColor = Color32.Black;
- int j = CreateElement(Car, Center.X - Radius, Center.Y + SemiHeight - Radius, 2.0 * Radius, 2.0 * Radius, WorldZ + EyeDistance - 5.0 * StackDistance, true, null, needleColor);
+ int j = CreateElement(Car, Center.X - Radius, Center.Y + SemiHeight - Radius, 2.0 * Radius, 2.0 * Radius, WorldZ + EyeDistance - 5.0 * StackDistance, null, needleColor);
double x0 = Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].States[0].Prototype.Mesh.Vertices[0].Coordinates.X;
double y0 = Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].States[0].Prototype.Mesh.Vertices[0].Coordinates.Y;
double z0 = Car.CarSections[CarSectionType.Interior].Groups[0].Elements[j].States[0].Prototype.Mesh.Vertices[0].Coordinates.Z;
@@ -589,11 +584,11 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
{
if (j == 0)
{
- k = CreateElement(Car, Corner.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, false, digitalNumberTextures[j], Color32.White);
+ k = CreateElement(Car, Corner.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, digitalNumberTextures[j], Color32.White);
}
else
{
- CreateElement(Car, Corner.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, false, digitalNumberTextures[j], Color32.White, true);
+ CreateElement(Car, Corner.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, digitalNumberTextures[j], Color32.White, true);
}
}
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[k].StateFunction = new FunctionScript(Plugin.CurrentHost, "speedometer abs " + UnitFactor.ToString(Culture) + " * ~ 100 >= <> 100 quotient 10 mod 10 ?", false);
@@ -604,11 +599,11 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
{
if (j == 0)
{
- k = CreateElement(Car, Corner.X + Size.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, false, digitalNumberTextures[j], Color32.White);
+ k = CreateElement(Car, Corner.X + Size.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, digitalNumberTextures[j], Color32.White);
}
else
{
- CreateElement(Car, Corner.X + Size.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, false, digitalNumberTextures[j], Color32.White, true);
+ CreateElement(Car, Corner.X + Size.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, digitalNumberTextures[j], Color32.White, true);
}
}
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[k].StateFunction = new FunctionScript(Plugin.CurrentHost, "speedometer abs " + UnitFactor.ToString(Culture) + " * ~ 10 >= <> 10 quotient 10 mod 10 ?", false);
@@ -619,11 +614,11 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
{
if (j == 0)
{
- k = CreateElement(Car, Corner.X + 2.0 * Size.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, false, digitalNumberTextures[j], Color32.White);
+ k = CreateElement(Car, Corner.X + 2.0 * Size.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, digitalNumberTextures[j], Color32.White);
}
else
{
- CreateElement(Car, Corner.X + 2.0 * Size.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, false, digitalNumberTextures[j], Color32.White, true);
+ CreateElement(Car, Corner.X + 2.0 * Size.X, Corner.Y + SemiHeight, Size.X, Size.Y, WorldZ + EyeDistance - 7.0 * StackDistance, digitalNumberTextures[j], Color32.White, true);
}
}
@@ -644,8 +639,8 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
Plugin.CurrentHost.RegisterTexture(turnOnPath, new TextureParameters(null, Color24.Blue), out var t0, true);
Plugin.CurrentHost.RegisterTexture(turnOffPath, new TextureParameters(null, Color24.Blue), out var t1, true);
- int elementIndex = CreateElement(Car, Corner.X, Corner.Y + SemiHeight, WorldZ + EyeDistance - 2.0 * StackDistance, false, t0);
- CreateElement(Car, Corner.X, Corner.Y + SemiHeight, WorldZ + EyeDistance - 2.0 * StackDistance, false, t1, true);
+ int elementIndex = CreateElement(Car, Corner.X, Corner.Y + SemiHeight, WorldZ + EyeDistance - 2.0 * StackDistance, t0);
+ CreateElement(Car, Corner.X, Corner.Y + SemiHeight, WorldZ + EyeDistance - 2.0 * StackDistance, t1, true);
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[elementIndex].StateFunction = new FunctionScript(Plugin.CurrentHost, "doors 0 !=", false);
break;
case PanelSections.Watch:
@@ -663,13 +658,13 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
if (!string.IsNullOrEmpty(Background))
{
Plugin.CurrentHost.RegisterTexture(Background, new TextureParameters(null, Color24.Blue), out var watchBackgroundTexture, true);
- CreateElement(Car, Center.X - 0.5 * watchBackgroundTexture.Width, Center.Y + SemiHeight - 0.5 * watchBackgroundTexture.Height, WorldZ + EyeDistance - 3.0 * StackDistance, false, watchBackgroundTexture);
+ CreateElement(Car, Center.X - 0.5 * watchBackgroundTexture.Width, Center.Y + SemiHeight - 0.5 * watchBackgroundTexture.Height, WorldZ + EyeDistance - 3.0 * StackDistance, watchBackgroundTexture);
}
// hour
TextureFile = Path.CombineFile(compatibilityFolder, "needle_hour.png");
Plugin.CurrentHost.RegisterTexture(TextureFile, TextureParameters.NoChange, out var hourTexture, true);
- int handElement = CreateElement(Car, Center.X - handRadius * hourTexture.AspectRatio, Center.Y + SemiHeight - handRadius, 2.0 * handRadius * hourTexture.AspectRatio, 2.0 * handRadius, WorldZ + EyeDistance - 4.0 * StackDistance, true, hourTexture, handColor);
+ int handElement = CreateElement(Car, Center.X - handRadius * hourTexture.AspectRatio, Center.Y + SemiHeight - handRadius, 2.0 * handRadius * hourTexture.AspectRatio, 2.0 * handRadius, WorldZ + EyeDistance - 4.0 * StackDistance, hourTexture, handColor);
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateZDirection = Vector3.Backward;
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateXDirection = Vector3.Right;
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateYDirection = Vector3.Cross(Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateZDirection, Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateXDirection);
@@ -678,7 +673,7 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
// minute
TextureFile = Path.CombineFile(compatibilityFolder, "needle_minute.png");
Plugin.CurrentHost.RegisterTexture(TextureFile, TextureParameters.NoChange, out var minuteTexture, true);
- handElement = CreateElement(Car, Center.X - handRadius * minuteTexture.AspectRatio, Center.Y + SemiHeight - handRadius, 2.0 * handRadius * minuteTexture.AspectRatio, 2.0 * handRadius, WorldZ + EyeDistance - 5.0 * StackDistance, true, minuteTexture, handColor);
+ handElement = CreateElement(Car, Center.X - handRadius * minuteTexture.AspectRatio, Center.Y + SemiHeight - handRadius, 2.0 * handRadius * minuteTexture.AspectRatio, 2.0 * handRadius, WorldZ + EyeDistance - 5.0 * StackDistance, minuteTexture, handColor);
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateZDirection = Vector3.Backward;
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateXDirection = Vector3.Right;
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateYDirection = Vector3.Cross(Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateZDirection, Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateXDirection);
@@ -687,7 +682,7 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
// second
TextureFile = Path.CombineFile(compatibilityFolder, "needle_second.png");
Plugin.CurrentHost.RegisterTexture(TextureFile, TextureParameters.NoChange, out var secondTexture, true);
- handElement = CreateElement(Car, Center.X - handRadius * secondTexture.AspectRatio, Center.Y + SemiHeight - handRadius, 2.0 * handRadius * secondTexture.AspectRatio, 2.0 * handRadius, WorldZ + EyeDistance - 6.0 * StackDistance, true, secondTexture, handColor);
+ handElement = CreateElement(Car, Center.X - handRadius * secondTexture.AspectRatio, Center.Y + SemiHeight - handRadius, 2.0 * handRadius * secondTexture.AspectRatio, 2.0 * handRadius, WorldZ + EyeDistance - 6.0 * StackDistance, secondTexture, handColor);
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateZDirection = Vector3.Backward;
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateXDirection = Vector3.Right;
Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateYDirection = Vector3.Cross(Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateZDirection, Car.CarSections[CarSectionType.Interior].Groups[0].Elements[handElement].RotateXDirection);
@@ -719,11 +714,11 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
Plugin.CurrentHost.RegisterTexture(brakeIndicatorPath, new TextureParameters(clip, Color24.Blue), out var brakeIndicatorTexture);
if (j == 0)
{
- k = CreateElement(Car, Corner.X, Corner.Y + SemiHeight, indicatorWidth, h, WorldZ + EyeDistance - StackDistance, false, brakeIndicatorTexture, Color32.White);
+ k = CreateElement(Car, Corner.X, Corner.Y + SemiHeight, indicatorWidth, h, WorldZ + EyeDistance - StackDistance, brakeIndicatorTexture, Color32.White);
}
else
{
- CreateElement(Car, Corner.X, Corner.Y + SemiHeight, indicatorWidth, h, WorldZ + EyeDistance - StackDistance, false, brakeIndicatorTexture, Color32.White, true);
+ CreateElement(Car, Corner.X, Corner.Y + SemiHeight, indicatorWidth, h, WorldZ + EyeDistance - StackDistance, brakeIndicatorTexture, Color32.White, true);
}
}
@@ -756,63 +751,14 @@ internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding,
}
}
- private int CreateElement(CarBase Car, double Left, double Top, double WorldZ, bool IsNeedle, Texture Texture, bool AddStateToLastElement = false)
+ private int CreateElement(CarBase Car, double Left, double Top, double WorldZ, Texture Texture, bool AddStateToLastElement = false)
{
- return CreateElement(Car, Left, Top, Texture.Width, Texture.Height, WorldZ, IsNeedle, Texture, Color32.White, AddStateToLastElement);
+ return CreateElement(Car, Left, Top, Texture.Width, Texture.Height, WorldZ, Texture, Color32.White, AddStateToLastElement);
}
// create element
- private int CreateElement(CarBase Car, double Left, double Top, double Width, double Height, double WorldZ, bool IsNeedle, Texture Texture, Color32 Color, bool AddStateToLastElement = false)
+ private int CreateElement(CarBase Car, double Left, double Top, double Width, double Height, double WorldZ, Texture Texture, Color32 Color, bool AddStateToLastElement = false)
{
- if (Plugin.CurrentOptions.EnableBveTsHacks && isBackground == false)
- {
- /*
- * In regions where the main panel texture is transparent,
- * BVE2 renders any other overlapping elements as transparent also
- *
- * e.g. Portuguese trains:
- * CP1400
- * CP2100
- * CP3500
- * CP4000
- *
- * All of these have junk extra elements in the main panel view
- * (Appears to have come from copy+pasting between trains)
- *
- * So, what we need to do is to extract the region of the main overlapping texture
- * Now, if this is *not* opaque, apply as a mask to the alpha channel
- *
- */
- double clipWidth = Math.Min(Width, panelTexture.Width - Left);
- double clipHeight = Math.Min(Height, panelTexture.Height + SemiHeight - Top);
- Texture temp = panelTexture.ApplyParameters(new TextureParameters(new TextureClipRegion(Math.Max(0, (int)Left)
- , Math.Max(0, (int)(Top - SemiHeight)), (int)clipWidth, (int)clipHeight), Color24.Blue));
-
- temp.Origin.GetTexture(out Texture t);
- switch (t.GetTransparencyType())
- {
- case TextureTransparencyType.Transparent:
- // totally hidden
- Texture = new Texture(1, 1, PixelFormat.RGBAlpha, new byte[] { 0, 0, 0, 0 }, new Color24[] { });
- break;
- case TextureTransparencyType.Partial:
- if (IsNeedle)
- {
- // as needles rotate, we can't just apply a mask and have to hide the whole thing
- Texture = new Texture(1, 1, PixelFormat.RGBAlpha, new byte[] { 0, 0, 0, 0 }, new Color24[] { });
- }
- else
- {
- Texture.Origin.GetTexture(out Texture tt);
- Texture = tt.ApplyParameters(new TextureParameters(null, null, t));
- }
-
- break;
- }
-
- }
-
-
// create object
StaticObject Object = new StaticObject(Plugin.CurrentHost);
Vector3[] v = new Vector3[4];
diff --git a/source/Plugins/Train.OpenBve/Panel/PanelXmlParser.cs b/source/Plugins/Train.OpenBve/Panel/PanelXmlParser.cs
index 60030cea41..048dfdafbd 100644
--- a/source/Plugins/Train.OpenBve/Panel/PanelXmlParser.cs
+++ b/source/Plugins/Train.OpenBve/Panel/PanelXmlParser.cs
@@ -2114,7 +2114,7 @@ internal void CreateTouchElement(ElementsGroup Group, Vector2 Location, Vector2
Vertex t3 = new Vertex(v[3], new Vector2(1.0f, 1.0f));
StaticObject Object = new StaticObject(Plugin.CurrentHost);
Object.Mesh.Vertices = new VertexTemplate[] { t0, t1, t2, t3 };
- Object.Mesh.Faces = new[] { new MeshFace(new[] { 0, 1, 2, 0, 2, 3 }) };
+ Object.Mesh.Faces = new[] { new MeshFace(new[] { 0, 1, 2, 3 }) };
Object.Mesh.Faces[0].Flags |= FaceFlags.Triangles;
Object.Mesh.Materials = new MeshMaterial[1];
Object.Mesh.Materials[0].Flags = 0;
diff --git a/source/Plugins/Train.OpenBve/Sound/SoundCfg.Xml.cs b/source/Plugins/Train.OpenBve/Sound/SoundCfg.Xml.cs
index 861bf32ac3..67a176026c 100644
--- a/source/Plugins/Train.OpenBve/Sound/SoundCfg.Xml.cs
+++ b/source/Plugins/Train.OpenBve/Sound/SoundCfg.Xml.cs
@@ -181,6 +181,10 @@ internal void Parse(string fileName, ref TrainBase Train, ref CarBase car, bool
}
break;
case SoundXMLSection.Door:
+ if (!isDriverCar)
+ {
+ break;
+ }
while (subBlock.RemainingSubBlocks > 0)
{
Block doorSubBlock = subBlock.ReadNextBlock();
@@ -551,17 +555,15 @@ private void ParseMotorSoundTableBlock(Block block
if (motorSound is BVEMotorSound bveMotorSound)
{
- ParseBlock(subBlock, out SoundBuffer buffer, ref Position, Radius);
for (int i = 0; i < bveMotorSound.Tables.Length; i++)
{
bveMotorSound.Tables[i].Buffer = null;
bveMotorSound.Tables[i].Source = null;
-
for (int j = 0; j < bveMotorSound.Tables[i].Entries.Length; j++)
{
if (idx == bveMotorSound.Tables[i].Entries[j].SoundIndex)
{
- bveMotorSound.Tables[i].Entries[j].Buffer = buffer;
+ ParseBlock(subBlock, out bveMotorSound.Tables[i].Entries[j].Buffer, ref Position, Radius);
}
}
}
diff --git a/source/Plugins/Train.OpenBve/Train/BVE/ExtensionsCfgParser.cs b/source/Plugins/Train.OpenBve/Train/BVE/ExtensionsCfgParser.cs
index 44058dd66f..dca8ca6faf 100644
--- a/source/Plugins/Train.OpenBve/Train/BVE/ExtensionsCfgParser.cs
+++ b/source/Plugins/Train.OpenBve/Train/BVE/ExtensionsCfgParser.cs
@@ -18,286 +18,286 @@ internal ExtensionsCfgParser(Plugin plugin)
Plugin = plugin;
}
- internal static bool UnicodeCheck;
+ internal static bool unicodeCheck;
-
- internal void ParseExtensionsConfig(string trainPath, Encoding trainEncoding, ref UnifiedObject[] CarObjects, ref UnifiedObject[] BogieObjects, ref UnifiedObject[] CouplerObjects, out bool[] VisibleFromInterior, TrainBase Train)
+ // parse extensions config
+ internal void ParseExtensionsConfig(string TrainPath, Encoding Encoding, ref UnifiedObject[] CarObjects, ref UnifiedObject[] BogieObjects, ref UnifiedObject[] CouplerObjects, out bool[] VisibleFromInterior, TrainBase Train)
{
VisibleFromInterior = new bool[Train.Cars.Length];
bool[] CarObjectsReversed = new bool[Train.Cars.Length];
bool[] BogieObjectsReversed = new bool[Train.Cars.Length * 2];
bool[] CarsDefined = new bool[Train.Cars.Length];
bool[] BogiesDefined = new bool[Train.Cars.Length * 2];
- string fileName = Path.CombineFile(trainPath, "extensions.cfg");
- if (!System.IO.File.Exists(fileName))
- {
- return;
- }
+ string FileName = Path.CombineFile(TrainPath, "extensions.cfg");
+ if (System.IO.File.Exists(FileName)) {
+ Encoding = TextEncoding.GetSystemEncodingFromFile(FileName, Encoding);
- trainEncoding = TextEncoding.GetSystemEncodingFromFile(fileName, trainEncoding);
-
- string[] Lines = System.IO.File.ReadAllLines(fileName, trainEncoding);
- if (Lines.Length == 1)
- {
- if (UnicodeCheck)
+ string[] Lines = System.IO.File.ReadAllLines(FileName, Encoding);
+ if (Lines.Length == 1)
{
+ if (unicodeCheck)
+ {
+ return;
+ }
+
+ unicodeCheck = true;
+ /*
+ * If only one line, there's a good possibility that our file is NOT Unicode at all
+ * and that the misdetection has turned it into garbage
+ *
+ * Try again with ASCII instead
+ */
+ ParseExtensionsConfig(TrainPath, Encoding.GetEncoding(1252), ref CarObjects, ref BogieObjects, ref CouplerObjects, out VisibleFromInterior, Train);
return;
}
+ ConfigFile cfg = new ConfigFile(Lines, FileName, Plugin.CurrentHost);
- UnicodeCheck = true;
- /*
- * If only one line, there's a good possibility that our file is NOT Unicode at all
- * and that the misdetection has turned it into garbage
- *
- * Try again with ASCII instead
- */
- ParseExtensionsConfig(trainPath, Encoding.GetEncoding(1252), ref CarObjects, ref BogieObjects, ref CouplerObjects, out VisibleFromInterior, Train);
- return;
- }
- ConfigFile cfg = new ConfigFile(Lines, fileName, Plugin.CurrentHost);
-
- double perBlockProgress = cfg.RemainingSubBlocks == 0 ? 0.25 : 0.25 / cfg.RemainingSubBlocks;
- int readBlocks = 0;
- while (cfg.RemainingSubBlocks > 0)
- {
- Plugin.CurrentProgress = Plugin.LastProgress + perBlockProgress * readBlocks;
- Block block = cfg.ReadNextBlock();
- switch (block.Key)
+ double perBlockProgress = cfg.RemainingSubBlocks == 0 ? 0.25 : 0.25 / cfg.RemainingSubBlocks;
+ int readBlocks = 0;
+ while (cfg.RemainingSubBlocks > 0)
{
- case ExtensionCfgSection.Exterior:
- while (block.RemainingDataValues > 0 && block.GetIndexedPath(trainPath, out var carIndex, out string exteriorObject))
- {
- Plugin.CurrentHost.LoadObject(exteriorObject, trainEncoding, out CarObjects[carIndex]);
- }
- break;
- case ExtensionCfgSection.Car:
- if (block.Index == -1)
- {
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid or missing CarIndex in file " + block.FileName);
+ Plugin.CurrentProgress = Plugin.LastProgress + perBlockProgress * readBlocks;
+ Block block = cfg.ReadNextBlock();
+ switch (block.Key)
+ {
+ case ExtensionCfgSection.Exterior:
+ while (block.RemainingDataValues > 0 && block.GetIndexedPath(TrainPath, out var carIndex, out var fileName))
+ {
+ Plugin.CurrentHost.LoadObject(fileName, Encoding, out CarObjects[carIndex]);
+ }
break;
- }
+ case ExtensionCfgSection.Car:
+ if (block.Index == -1)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid or missing CarIndex in file " + block.FileName);
+ break;
+ }
- if (block.Index >= Train.Cars.Length)
- {
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "CarIndex " + block.Index + " does not reference an existing car in in file " + block.FileName);
- break;
- }
+ if (block.Index >= Train.Cars.Length)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "CarIndex " + block.Index + " does not reference an existing car in in file " + block.FileName);
+ break;
+ }
- if (CarsDefined[block.Index])
- {
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "CarIndex " + block.Index + " has already been declared in in file " + block.FileName);
- }
+ if (CarsDefined[block.Index])
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "CarIndex " + block.Index + " has already been declared in in file " + block.FileName);
+ }
- CarsDefined[block.Index] = true;
- if (block.GetPath(ExtensionCfgKey.Object, trainPath, out string carObject))
- {
- Plugin.CurrentHost.LoadObject(carObject, trainEncoding, out CarObjects[block.Index]);
- }
+ CarsDefined[block.Index] = true;
+ if (block.GetPath(ExtensionCfgKey.Object, TrainPath, out string carObject))
+ {
+ Plugin.CurrentHost.LoadObject(carObject, Encoding, out CarObjects[block.Index]);
+ }
- bool definedLength = false;
- if (block.GetValue(ExtensionCfgKey.Length, out double carLength, NumberRange.Positive))
- {
- Train.Cars[block.Index].Length = carLength;
- Train.Cars[block.Index].BeaconReceiverPosition = 0.5 * carLength;
- definedLength = true;
- }
- block.GetValue(ExtensionCfgKey.Reversed, out CarObjectsReversed[block.Index]);
- block.GetValue(ExtensionCfgKey.VisibleFromInterior, out VisibleFromInterior[block.Index]);
- block.GetValue(ExtensionCfgKey.LoadingSway, out Train.Cars[block.Index].EnableLoadingSway);
- if (block.GetVector2(ExtensionCfgKey.Axles, ',', out Vector2 carAxles))
- {
- if (carAxles.X >= carAxles.Y)
+ bool definedLength = false;
+ if (block.GetValue(ExtensionCfgKey.Length, out double carLength, NumberRange.Positive))
{
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Rear is expected to be less than Front for Car " + block.Index + " in file " + block.FileName);
+ Train.Cars[block.Index].Length = carLength;
+ Train.Cars[block.Index].BeaconReceiverPosition = 0.5 * carLength;
+ definedLength = true;
}
- else
+ block.GetValue(ExtensionCfgKey.Reversed, out CarObjectsReversed[block.Index]);
+ block.GetValue(ExtensionCfgKey.VisibleFromInterior, out VisibleFromInterior[block.Index]);
+ block.GetValue(ExtensionCfgKey.LoadingSway, out Train.Cars[block.Index].EnableLoadingSway);
+ if (block.GetVector2(ExtensionCfgKey.Axles, ',', out Vector2 carAxles))
{
- Train.Cars[block.Index].RearAxle.Position = carAxles.X;
- Train.Cars[block.Index].FrontAxle.Position = carAxles.Y;
+ if (carAxles.X >= carAxles.Y)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Rear is expected to be less than Front for Car " + block.Index + " in file " + block.FileName);
+ }
+ else
+ {
+ Train.Cars[block.Index].RearAxle.Position = carAxles.X;
+ Train.Cars[block.Index].FrontAxle.Position = carAxles.Y;
+ }
}
- }
- else
- {
- if (definedLength == false)
+ else
{
- double axleDistance = 0.4 * Train.Cars[block.Index].Length;
- Train.Cars[block.Index].RearAxle.Position = -axleDistance;
- Train.Cars[block.Index].FrontAxle.Position = axleDistance;
+ if (definedLength == false)
+ {
+ double axleDistance = 0.4 * Train.Cars[block.Index].Length;
+ Train.Cars[block.Index].RearAxle.Position = -axleDistance;
+ Train.Cars[block.Index].FrontAxle.Position = axleDistance;
+ }
}
- }
- break;
- case ExtensionCfgSection.Coupler:
- if (block.Index == -1 || block.Index >= Train.Cars.Length)
- {
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid or missing CouplerIndex in file " + block.FileName);
break;
- }
- if (block.GetVector2(ExtensionCfgKey.Distances, ',', out Vector2 distances))
- {
- if (distances.X > distances.Y)
+ case ExtensionCfgSection.Coupler:
+ if (block.Index == -1 || block.Index >= Train.Cars.Length)
{
- // NOTE: Current error is misleading...
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Minimum is expected to be less than Maximum in for Coupler " + block.Index + " in file " + block.FileName);
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid or missing CouplerIndex in file " + block.FileName);
+ break;
}
- else
+ if (block.GetVector2(ExtensionCfgKey.Distances, ',', out Vector2 distances))
{
- Train.Cars[block.Index].Coupler.MinimumDistanceBetweenCars = distances.X;
- Train.Cars[block.Index].Coupler.MaximumDistanceBetweenCars = distances.Y;
+ if (distances.X > distances.Y)
+ {
+ // NOTE: Current error is misleading...
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Minimum is expected to be less than Maximum in for Coupler " + block.Index + " in file " + block.FileName);
+ }
+ else
+ {
+ Train.Cars[block.Index].Coupler.MinimumDistanceBetweenCars = distances.X;
+ Train.Cars[block.Index].Coupler.MaximumDistanceBetweenCars = distances.Y;
+ }
+ }
+ if (block.GetPath(ExtensionCfgKey.Object, TrainPath, out string couplerObject))
+ {
+ Plugin.CurrentHost.LoadObject(couplerObject, Encoding, out CouplerObjects[block.Index]);
}
- }
- if (block.GetPath(ExtensionCfgKey.Object, trainPath, out string couplerObject))
- {
- Plugin.CurrentHost.LoadObject(couplerObject, trainEncoding, out CouplerObjects[block.Index]);
- }
- break;
- case ExtensionCfgSection.Bogie:
- if (block.Index == -1)
- {
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid or missing BogieIndex in file " + block.FileName);
break;
- }
+ case ExtensionCfgSection.Bogie:
+ if (block.Index == -1)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid or missing BogieIndex in file " + block.FileName);
+ break;
+ }
- if (block.Index > Train.Cars.Length * 2)
- {
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "BogieIndex " + block.Index + " does not reference an existing bogie in in file " + block.FileName);
- break;
- }
+ if (block.Index > Train.Cars.Length * 2)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "BogieIndex " + block.Index + " does not reference an existing bogie in in file " + block.FileName);
+ break;
+ }
- if (BogiesDefined[block.Index])
- {
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "BogieIndex " + block.Index + " has already been declared in in file " + block.FileName);
- }
- BogiesDefined[block.Index] = true;
- //Assuming that there are two bogies per car
- bool IsOdd = (block.Index % 2 != 0);
- int CarIndex = block.Index / 2;
+ if (BogiesDefined[block.Index])
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "BogieIndex " + block.Index + " has already been declared in in file " + block.FileName);
+ }
+ BogiesDefined[block.Index] = true;
+ //Assuming that there are two bogies per car
+ bool IsOdd = (block.Index % 2 != 0);
+ int CarIndex = block.Index / 2;
- if (block.GetPath(ExtensionCfgKey.Object, trainPath, out string bogieObject))
- {
- Plugin.CurrentHost.LoadObject(bogieObject, trainEncoding, out BogieObjects[block.Index]);
- }
- block.GetValue(ExtensionCfgKey.Reversed, out BogieObjectsReversed[block.Index]);
- if (block.GetVector2(ExtensionCfgKey.Axles, ',', out Vector2 bogieAxles))
- {
- if (bogieAxles.X >= bogieAxles.Y)
+ if (block.GetPath(ExtensionCfgKey.Object, TrainPath, out string bogieObject))
{
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Rear is expected to be less than Front for Bogie " + block.Index + " in file " + block.FileName);
+ Plugin.CurrentHost.LoadObject(bogieObject, Encoding, out BogieObjects[block.Index]);
}
- else
+ block.GetValue(ExtensionCfgKey.Reversed, out BogieObjectsReversed[block.Index]);
+ if (block.GetVector2(ExtensionCfgKey.Axles, ',', out Vector2 bogieAxles))
{
- if (IsOdd)
+ if (bogieAxles.X >= bogieAxles.Y)
{
- Train.Cars[CarIndex].FrontBogie.RearAxle.Position = bogieAxles.X;
- Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = bogieAxles.Y;
+ Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Rear is expected to be less than Front for Bogie " + block.Index + " in file " + block.FileName);
}
else
{
- Train.Cars[CarIndex].RearBogie.RearAxle.Position = bogieAxles.X;
- Train.Cars[CarIndex].RearBogie.FrontAxle.Position = bogieAxles.Y;
+ if (IsOdd)
+ {
+ Train.Cars[CarIndex].FrontBogie.RearAxle.Position = bogieAxles.X;
+ Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = bogieAxles.Y;
+ }
+ else
+ {
+ Train.Cars[CarIndex].RearBogie.RearAxle.Position = bogieAxles.X;
+ Train.Cars[CarIndex].RearBogie.FrontAxle.Position = bogieAxles.Y;
+ }
}
}
- }
- else
- {
- if (IsOdd)
- {
- double axleDistance = 0.4 * Train.Cars[CarIndex].FrontBogie.Length;
- Train.Cars[CarIndex].FrontBogie.RearAxle.Position = -axleDistance;
- Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = axleDistance;
- }
else
{
- double axleDistance = 0.4 * Train.Cars[CarIndex].RearBogie.Length;
- Train.Cars[CarIndex].RearBogie.RearAxle.Position = -axleDistance;
- Train.Cars[CarIndex].RearBogie.FrontAxle.Position = axleDistance;
+ if (IsOdd)
+ {
+ double axleDistance = 0.4 * Train.Cars[CarIndex].FrontBogie.Length;
+ Train.Cars[CarIndex].FrontBogie.RearAxle.Position = -axleDistance;
+ Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = axleDistance;
+ }
+ else
+ {
+ double axleDistance = 0.4 * Train.Cars[CarIndex].RearBogie.Length;
+ Train.Cars[CarIndex].RearBogie.RearAxle.Position = -axleDistance;
+ Train.Cars[CarIndex].RearBogie.FrontAxle.Position = axleDistance;
+ }
}
- }
- break;
+ break;
+ }
+ block.ReportErrors();
+ readBlocks++;
}
- block.ReportErrors();
- readBlocks++;
- }
- // check for car objects and reverse if necessary
- int carObjects = 0;
- for (int i = 0; i < Train.Cars.Length; i++) {
- if (CarObjects[i] != null) {
- carObjects++;
- if (CarObjectsReversed[i]) {
- {
- // reverse axle positions
- double temp = Train.Cars[i].FrontAxle.Position;
- Train.Cars[i].FrontAxle.Position = -Train.Cars[i].RearAxle.Position;
- Train.Cars[i].RearAxle.Position = -temp;
- }
- if (CarObjects[i] is StaticObject) {
- StaticObject obj = (StaticObject)CarObjects[i].Clone();
- obj.ApplyScale(-1.0, 1.0, -1.0);
- CarObjects[i] = obj;
- } else if (CarObjects[i] is AnimatedObjectCollection) {
- AnimatedObjectCollection obj = (AnimatedObjectCollection)CarObjects[i].Clone();
- obj.Reverse();
- CarObjects[i] = obj;
- } else if (CarObjects[i] is KeyframeAnimatedObject) {
- KeyframeAnimatedObject obj = (KeyframeAnimatedObject)CarObjects[i].Clone();
- obj.Reverse();
- CarObjects[i] = obj;
- } else {
- throw new NotImplementedException();
+ // check for car objects and reverse if necessary
+ int carObjects = 0;
+ for (int i = 0; i < Train.Cars.Length; i++) {
+ if (CarObjects[i] != null) {
+ carObjects++;
+ if (CarObjectsReversed[i]) {
+ {
+ // reverse axle positions
+ double temp = Train.Cars[i].FrontAxle.Position;
+ Train.Cars[i].FrontAxle.Position = -Train.Cars[i].RearAxle.Position;
+ Train.Cars[i].RearAxle.Position = -temp;
+ }
+ if (CarObjects[i] is StaticObject) {
+ StaticObject obj = (StaticObject)CarObjects[i].Clone();
+ obj.ApplyScale(-1.0, 1.0, -1.0);
+ CarObjects[i] = obj;
+ } else if (CarObjects[i] is AnimatedObjectCollection) {
+ AnimatedObjectCollection obj = (AnimatedObjectCollection)CarObjects[i].Clone();
+ obj.Reverse();
+ CarObjects[i] = obj;
+ } else if (CarObjects[i] is KeyframeAnimatedObject) {
+ KeyframeAnimatedObject obj = (KeyframeAnimatedObject)CarObjects[i].Clone();
+ obj.Reverse();
+ CarObjects[i] = obj;
+ } else {
+ throw new NotImplementedException();
+ }
}
}
}
- }
- //Check for bogie objects and reverse if necessary.....
- int bogieObjects = 0;
- for (int i = 0; i < Train.Cars.Length * 2; i++)
- {
- int CarIndex = i / 2;
- if (BogieObjects[i] != null)
+ //Check for bogie objects and reverse if necessary.....
+ int bogieObjects = 0;
+ for (int i = 0; i < Train.Cars.Length * 2; i++)
{
- bogieObjects++;
- if (BogieObjectsReversed[i])
+ bool IsOdd = (i % 2 != 0);
+ int CarIndex = i/2;
+ if (BogieObjects[i] != null)
{
- // reverse axle positions
- if (i % 2 != 0)
+ bogieObjects++;
+ if (BogieObjectsReversed[i])
{
- double temp = Train.Cars[CarIndex].FrontBogie.FrontAxle.Position;
- Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = -Train.Cars[CarIndex].FrontBogie.RearAxle.Position;
- Train.Cars[CarIndex].FrontBogie.RearAxle.Position = -temp;
- }
- else
- {
- double temp = Train.Cars[CarIndex].RearBogie.FrontAxle.Position;
- Train.Cars[CarIndex].RearBogie.FrontAxle.Position = -Train.Cars[CarIndex].RearBogie.RearAxle.Position;
- Train.Cars[CarIndex].RearBogie.RearAxle.Position = -temp;
- }
- if (BogieObjects[i] is StaticObject) {
- StaticObject obj = (StaticObject)BogieObjects[i].Clone();
- obj.ApplyScale(-1.0, 1.0, -1.0);
- BogieObjects[i] = obj;
- } else if (BogieObjects[i] is AnimatedObjectCollection) {
- AnimatedObjectCollection obj = (AnimatedObjectCollection)BogieObjects[i].Clone();
- obj.Reverse();
- BogieObjects[i] = obj;
- } else if (BogieObjects[i] is KeyframeAnimatedObject) {
- KeyframeAnimatedObject obj = (KeyframeAnimatedObject)BogieObjects[i].Clone();
- obj.Reverse();
- BogieObjects[i] = obj;
- } else {
- throw new NotImplementedException();
+ {
+ // reverse axle positions
+ if (IsOdd)
+ {
+ double temp = Train.Cars[CarIndex].FrontBogie.FrontAxle.Position;
+ Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = -Train.Cars[CarIndex].FrontBogie.RearAxle.Position;
+ Train.Cars[CarIndex].FrontBogie.RearAxle.Position = -temp;
+ }
+ else
+ {
+ double temp = Train.Cars[CarIndex].RearBogie.FrontAxle.Position;
+ Train.Cars[CarIndex].RearBogie.FrontAxle.Position = -Train.Cars[CarIndex].RearBogie.RearAxle.Position;
+ Train.Cars[CarIndex].RearBogie.RearAxle.Position = -temp;
+ }
+ }
+ if (BogieObjects[i] is StaticObject) {
+ StaticObject obj = (StaticObject)BogieObjects[i].Clone();
+ obj.ApplyScale(-1.0, 1.0, -1.0);
+ BogieObjects[i] = obj;
+ } else if (BogieObjects[i] is AnimatedObjectCollection) {
+ AnimatedObjectCollection obj = (AnimatedObjectCollection)BogieObjects[i].Clone();
+ obj.Reverse();
+ BogieObjects[i] = obj;
+ } else if (BogieObjects[i] is KeyframeAnimatedObject) {
+ KeyframeAnimatedObject obj = (KeyframeAnimatedObject)BogieObjects[i].Clone();
+ obj.Reverse();
+ BogieObjects[i] = obj;
+ } else {
+ throw new NotImplementedException();
+ }
}
}
}
- }
- if (carObjects > 0 && carObjects < Train.Cars.Length) {
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "An incomplete set of exterior objects was provided in file " + fileName);
- }
+ if (carObjects > 0 && carObjects < Train.Cars.Length) {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "An incomplete set of exterior objects was provided in file " + FileName);
+ }
- if (bogieObjects > 0 && bogieObjects < Train.Cars.Length * 2)
- {
- Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "An incomplete set of bogie objects was provided in file " + fileName);
+ if (bogieObjects > 0 && bogieObjects < Train.Cars.Length * 2)
+ {
+ Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "An incomplete set of bogie objects was provided in file " + FileName);
+ }
}
}
diff --git a/source/Plugins/Train.OpenBve/Train/BVE/TrainDatParser.cs b/source/Plugins/Train.OpenBve/Train/BVE/TrainDatParser.cs
index d2c13cb541..6701c8629f 100644
--- a/source/Plugins/Train.OpenBve/Train/BVE/TrainDatParser.cs
+++ b/source/Plugins/Train.OpenBve/Train/BVE/TrainDatParser.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -1257,7 +1257,7 @@ internal void Parse(string FileName, Encoding Encoding, TrainBase Train) {
}
Train.Cars[i].CarBrake.MainReservoir = new MainReservoir(MainReservoirMinimumPressure, MainReservoirMaximumPressure, 0.01, (trainBrakeType == BrakeSystemType.AutomaticAirBrake ? 0.25 : 0.075) / Cars);
- Train.Cars[i].CarBrake.MainReservoir.Volume = 0.5; // Organization for Co-Operation between Railways specifies 340L to 680L main reservoir capacity for EMU, so let's pick something in the middle (in m³)
+ Train.Cars[i].CarBrake.MainReservoir.Volume = 0.5; // Organization for Co-Operation between Railways specifies 340L to 680L main reservoir capacity for EMU, so let's pick something in the middle (in m)
Train.Cars[i].CarBrake.EqualizingReservoir = new EqualizingReservoir(50000.0, 250000.0, 200000.0);
Train.Cars[i].CarBrake.EqualizingReservoir.NormalPressure = 1.005 * OperatingPressure;
@@ -1437,57 +1437,9 @@ internal void Parse(string FileName, Encoding Encoding, TrainBase Train) {
{
Train.Cars[DriverCar].HasInteriorView = true;
}
-
- /*
- * Determine the maximum width of the handle strings for drawing purposes
- * (As translators may use much longer strings than we expect)
- */
- if (Plugin.Renderer?.Fonts?.NormalFont != null && Translations.QuickReferences != null)
- {
- Vector2 rs = Plugin.Renderer.Fonts.NormalFont.MeasureString(Translations.QuickReferences.HandleForward);
- if (rs.X > Train.Handles.Reverser.MaxWidth)
- {
- Train.Handles.Reverser.MaxWidth = rs.X;
- }
- rs = Plugin.Renderer.Fonts.NormalFont.MeasureString(Translations.QuickReferences.HandleNeutral);
- if (rs.X > Train.Handles.Reverser.MaxWidth)
- {
- Train.Handles.Reverser.MaxWidth = rs.X;
- }
- rs = Plugin.Renderer.Fonts.NormalFont.MeasureString(Translations.QuickReferences.HandleBackward);
- if (rs.X > Train.Handles.Reverser.MaxWidth)
- {
- Train.Handles.Reverser.MaxWidth = rs.X;
- }
-
- rs = Plugin.Renderer.Fonts.NormalFont.MeasureString(Translations.QuickReferences.HandlePower);
- if (rs.X > Train.Handles.Power.MaxWidth)
- {
- Train.Handles.Power.MaxWidth = rs.X;
- }
- rs = Plugin.Renderer.Fonts.NormalFont.MeasureString(Translations.QuickReferences.HandlePowerNull);
- if (rs.X > Train.Handles.Power.MaxWidth)
- {
- Train.Handles.Power.MaxWidth = rs.X;
- }
-
- rs = Plugin.Renderer.Fonts.NormalFont.MeasureString(Translations.QuickReferences.HandleBrake);
- if (rs.X > Train.Handles.Brake.MaxWidth)
- {
- Train.Handles.Brake.MaxWidth = rs.X;
- }
- rs = Plugin.Renderer.Fonts.NormalFont.MeasureString(Translations.QuickReferences.HandleBrakeNull);
- if (rs.X > Train.Handles.Brake.MaxWidth)
- {
- Train.Handles.Brake.MaxWidth = rs.X;
- }
- rs = Plugin.Renderer.Fonts.NormalFont.MeasureString(Translations.QuickReferences.HandleEmergency);
- if (rs.X > Train.Handles.Brake.MaxWidth)
- {
- Train.Handles.Brake.MaxWidth = rs.X;
- }
- }
+ // finish
+
}
}
diff --git a/source/Plugins/Train.OpenBve/Train/XML/TrainXmlParser.CarNode.cs b/source/Plugins/Train.OpenBve/Train/XML/TrainXmlParser.CarNode.cs
index 85c24e56f9..0d664d29b9 100644
--- a/source/Plugins/Train.OpenBve/Train/XML/TrainXmlParser.CarNode.cs
+++ b/source/Plugins/Train.OpenBve/Train/XML/TrainXmlParser.CarNode.cs
@@ -26,7 +26,6 @@
using LibRender2.Smoke;
using LibRender2.Trains;
using OpenBveApi;
-using OpenBveApi.FunctionScripting;
using OpenBveApi.Graphics;
using OpenBveApi.Interface;
using OpenBveApi.Math;
@@ -456,16 +455,6 @@ private void ParseCarBlock(Block block, int Car, r
Plugin.CurrentHost.RegisterTexture(texturePath, TextureParameters.NoChange, out particleTexture);
}
ParticleSource particleSource = new ParticleSource(Plugin.Renderer, Train.Cars[Car], emitterLocation, maximumSize, maximumGrownSize, initialMotion, maximumLifeSpan);
-
- if(particleSourceBlock.GetFunctionScript(new [] {TrainXMLKey.Function }, currentXMLPath, out AnimationScript function))
- {
- particleSource.Controller = function as FunctionScript;
- }
- else
- {
- particleSource.Controller = new FunctionScript(Plugin.CurrentHost, Car + " enginepowerindex", false);
- }
-
particleSourceBlock.TryGetValue(TrainXMLKey.EmitsAtIdle, ref particleSource.EmitsAtIdle);
particleSource.ParticleTexture = particleTexture;
Train.Cars[Car].ParticleSources.Add(particleSource);
diff --git a/source/Plugins/Train.OpenBve/Train/XML/TrainXmlParser.cs b/source/Plugins/Train.OpenBve/Train/XML/TrainXmlParser.cs
index bc9fef87b6..9f679b8e51 100644
--- a/source/Plugins/Train.OpenBve/Train/XML/TrainXmlParser.cs
+++ b/source/Plugins/Train.OpenBve/Train/XML/TrainXmlParser.cs
@@ -83,12 +83,7 @@ internal void Parse(string fileName, TrainBase Train, ref UnifiedObject[] carObj
}
carBlocks[i].GetValue(TrainXMLKey.Minimum, out Train.Cars[carIndex - 1].Coupler.MinimumDistanceBetweenCars);
- carBlocks[i].GetValue(TrainXMLKey.Maximum, out Train.Cars[carIndex - 1].Coupler.MaximumDistanceBetweenCars);
- if (Train.Cars[carIndex - 1].Coupler.MaximumDistanceBetweenCars < Train.Cars[carIndex - 1].Coupler.MinimumDistanceBetweenCars)
- {
- Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Maximum should be greater than or equal to Minimum for Coupler " + (carIndex -1) + " in XML file " + xmlFile.FileName);
- Train.Cars[carIndex - 1].Coupler.MaximumDistanceBetweenCars = Train.Cars[carIndex - 1].Coupler.MinimumDistanceBetweenCars;
- }
+ carBlocks[i].GetValue(TrainXMLKey.Maximum, out Train.Cars[carIndex - 1].Coupler.MinimumDistanceBetweenCars);
if (carBlocks[i].GetPath(TrainXMLKey.Object, currentPath, out string objectPath))
{
Plugin.CurrentHost.LoadObject(objectPath, Encoding.Default, out couplerObjects[carIndex - 1]);
@@ -136,7 +131,7 @@ internal void Parse(string fileName, TrainBase Train, ref UnifiedObject[] carObj
}
}
}
- if (subBlock.TryGetStringArray(TrainXMLKey.LocoBrake, separatorChars, ref Train.Handles.LocoBrake.NotchDescriptions))
+ if (subBlock.TryGetStringArray(TrainXMLKey.Brake, separatorChars, ref Train.Handles.LocoBrake.NotchDescriptions))
{
for (int j = 0; j < Train.Handles.LocoBrake.NotchDescriptions.Length; j++)
{
diff --git a/source/Plugins/Train.OpenBve/app.config b/source/Plugins/Train.OpenBve/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/Plugins/Train.OpenBve/app.config
+++ b/source/Plugins/Train.OpenBve/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/Plugins/Win32PluginProxy/App.config b/source/Plugins/Win32PluginProxy/App.config
index 15eb89674c..fd89cc910b 100644
--- a/source/Plugins/Win32PluginProxy/App.config
+++ b/source/Plugins/Win32PluginProxy/App.config
@@ -13,10 +13,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/RouteManager2/CurrentRoute.cs b/source/RouteManager2/CurrentRoute.cs
index e288ae4f80..27e23fdf4d 100644
--- a/source/RouteManager2/CurrentRoute.cs
+++ b/source/RouteManager2/CurrentRoute.cs
@@ -221,10 +221,13 @@ public void UpdateSection(Section Section, out Section PreviousSection)
foreach (AbstractTrain t in currentHost.Trains)
{
- if (t.State == TrainState.Available && t.TimetableDelta > b)
+ if (t.State == TrainState.Available)
{
- b = t.TimetableDelta;
- train = t;
+ if (t.TimetableDelta > b)
+ {
+ b = t.TimetableDelta;
+ train = t;
+ }
}
}
}
@@ -563,10 +566,13 @@ public bool ApplyPointOfInterest(TrackDirection direction)
t = double.NegativeInfinity;
for (int i = 0; i < PointsOfInterest.Length; i++)
{
- if (PointsOfInterest[i].TrackPosition < renderer.CameraTrackFollower.TrackPosition && PointsOfInterest[i].TrackPosition > t)
+ if (PointsOfInterest[i].TrackPosition < renderer.CameraTrackFollower.TrackPosition)
{
- t = PointsOfInterest[i].TrackPosition;
- j = i;
+ if (PointsOfInterest[i].TrackPosition > t)
+ {
+ t = PointsOfInterest[i].TrackPosition;
+ j = i;
+ }
}
}
}
@@ -575,10 +581,13 @@ public bool ApplyPointOfInterest(TrackDirection direction)
t = double.PositiveInfinity;
for (int i = 0; i < PointsOfInterest.Length; i++)
{
- if (PointsOfInterest[i].TrackPosition > renderer.CameraTrackFollower.TrackPosition && PointsOfInterest[i].TrackPosition < t)
+ if (PointsOfInterest[i].TrackPosition > renderer.CameraTrackFollower.TrackPosition)
{
- t = PointsOfInterest[i].TrackPosition;
- j = i;
+ if (PointsOfInterest[i].TrackPosition < t)
+ {
+ t = PointsOfInterest[i].TrackPosition;
+ j = i;
+ }
}
}
}
@@ -612,11 +621,14 @@ public int PlayerFirstStationIndex
{
for (int i = Stations.Length -1; i > 0; i--)
{
- if (!string.IsNullOrEmpty(InitialStationName) && string.Equals(InitialStationName, Stations[i].Name, StringComparison.InvariantCultureIgnoreCase))
+ if (!string.IsNullOrEmpty(InitialStationName))
{
- return i;
+ if (string.Equals(InitialStationName, Stations[i].Name, StringComparison.InvariantCultureIgnoreCase))
+ {
+ return i;
+ }
}
- if (Stations[i].StopMode == StationStopMode.AllStop | Stations[i].StopMode == StationStopMode.PlayerStop && Stations[i].Stops.Length != 0)
+ if (Stations[i].StopMode == StationStopMode.AllStop | Stations[i].StopMode == StationStopMode.PlayerStop & Stations[i].Stops.Length != 0)
{
if (f == false)
{
@@ -630,11 +642,14 @@ public int PlayerFirstStationIndex
{
for (int i = 0; i < Stations.Length; i++)
{
- if (!string.IsNullOrEmpty(InitialStationName) && string.Equals(InitialStationName, Stations[i].Name, StringComparison.InvariantCultureIgnoreCase))
+ if (!string.IsNullOrEmpty(InitialStationName))
{
- return i;
+ if (string.Equals(InitialStationName, Stations[i].Name, StringComparison.InvariantCultureIgnoreCase))
+ {
+ return i;
+ }
}
- if (Stations[i].StopMode == StationStopMode.AllStop | Stations[i].StopMode == StationStopMode.PlayerStop && Stations[i].Stops.Length != 0)
+ if (Stations[i].StopMode == StationStopMode.AllStop | Stations[i].StopMode == StationStopMode.PlayerStop & Stations[i].Stops.Length != 0)
{
if (f == false)
{
diff --git a/source/RouteManager2/Illustrations/RouteMap.cs b/source/RouteManager2/Illustrations/RouteMap.cs
index 27a151eab6..2e8a1fb7d4 100644
--- a/source/RouteManager2/Illustrations/RouteMap.cs
+++ b/source/RouteManager2/Illustrations/RouteMap.cs
@@ -18,6 +18,10 @@ namespace RouteManager2
/// Used for creating illustrations
public static class Illustrations
{
+ /// Holds the current lock for the illustrations drawing functions
+ /// GDI Plus is not thread-safe- This object should be locked on when drawing a route illustration / gradient profile
+ public static readonly object Locker = new object();
+
internal static CurrentRoute CurrentRoute;
private const double LeftPad = 8.0;
diff --git a/source/RouteManager2/RouteInformation.cs b/source/RouteManager2/RouteInformation.cs
index bb6dda2c4b..367ad5dabb 100644
--- a/source/RouteManager2/RouteInformation.cs
+++ b/source/RouteManager2/RouteInformation.cs
@@ -1,5 +1,4 @@
using System.Drawing;
-using LibRender2;
using OpenBveApi.Textures;
namespace RouteManager2
@@ -41,7 +40,7 @@ public class RouteInformation
public void LoadInformation()
{
- lock (BaseRenderer.GdiPlusLock)
+ lock (Illustrations.Locker)
{
RouteMap = Illustrations.CreateRouteMap(500, 500, true, out _);
RouteMinX = Illustrations.LastRouteMinX;
diff --git a/source/RouteManager2/app.config b/source/RouteManager2/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/RouteManager2/app.config
+++ b/source/RouteManager2/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/RouteViewer/Audio/Sounds.Update.cs b/source/RouteViewer/Audio/Sounds.Update.cs
index 642de11651..4a403706f8 100644
--- a/source/RouteViewer/Audio/Sounds.Update.cs
+++ b/source/RouteViewer/Audio/Sounds.Update.cs
@@ -24,7 +24,7 @@ protected override void UpdateInverseModel(double timeElapsed)
Vector3 listenerPosition = Program.Renderer.Camera.AbsolutePosition;
Orientation3 listenerOrientation = new Orientation3(Program.Renderer.Camera.AbsoluteSide, Program.Renderer.Camera.AbsoluteUp, Program.Renderer.Camera.AbsoluteDirection);
Vector3 listenerVelocity;
- if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior || Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead || Program.Renderer.Camera.CurrentMode == CameraViewMode.Exterior)
+ if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead | Program.Renderer.Camera.CurrentMode == CameraViewMode.Exterior)
{
CarBase car = TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar];
Vector3 diff = car.FrontAxle.Follower.WorldPosition - car.RearAxle.Follower.WorldPosition;
@@ -44,7 +44,7 @@ protected override void UpdateInverseModel(double timeElapsed)
AL.Listener(ALListener3f.Position, 0.0f, 0.0f, 0.0f);
AL.Listener(ALListener3f.Velocity, (float)listenerVelocity.X, (float)listenerVelocity.Y, (float)listenerVelocity.Z);
- float[] Orientation = { (float) listenerOrientation.Z.X, (float) listenerOrientation.Z.Y, (float) listenerOrientation.Z.Z,-(float) listenerOrientation.Y.X, -(float) listenerOrientation.Y.Y, -(float) listenerOrientation.Y.Z };
+ float[] Orientation = new[]{(float) listenerOrientation.Z.X, (float) listenerOrientation.Z.Y, (float) listenerOrientation.Z.Z,-(float) listenerOrientation.Y.X, -(float) listenerOrientation.Y.Y, -(float) listenerOrientation.Y.Z};
AL.Listener(ALListenerfv.Orientation, ref Orientation);
/*
* Set up the atmospheric attributes.
@@ -135,7 +135,7 @@ protected override void UpdateInverseModel(double timeElapsed)
if (Sources[i].State == SoundSourceState.Playing)
{
AL.GetSource(Sources[i].OpenAlSourceName, ALGetSourcei.SourceState, out int state);
- if (state != (int)ALSourceState.Initial && state != (int)ALSourceState.Playing)
+ if (state != (int)ALSourceState.Initial & state != (int)ALSourceState.Playing)
{
/*
* The sound is not playing any longer.
@@ -174,7 +174,7 @@ protected override void UpdateInverseModel(double timeElapsed)
Vector3 positionDifference = position - listenerPosition;
double distance = positionDifference.Norm();
double radius = Sources[i].Radius;
- if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior || Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead)
+ if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead)
{
if (Sources[i].Parent != TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar])
{
diff --git a/source/RouteViewer/FunctionScripts.cs b/source/RouteViewer/FunctionScripts.cs
index 02f6b4377b..80b3a67ce2 100644
--- a/source/RouteViewer/FunctionScripts.cs
+++ b/source/RouteViewer/FunctionScripts.cs
@@ -8,13 +8,12 @@
using TrainManager.Handles;
using TrainManager.Car.Systems;
using TrainManager.SafetySystems;
-using TrainManager.Trains;
namespace RouteViewer {
internal static class FunctionScripts {
// execute function script
- internal static void ExecuteFunctionScript(FunctionScript Function, TrainBase Train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState) {
+ internal static void ExecuteFunctionScript(FunctionScript Function, TrainManager.Train Train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState) {
int s = 0, c = 0;
for (int i = 0; i < Function.InstructionSet.Length; i++) {
switch (Function.InstructionSet[i]) {
@@ -264,17 +263,7 @@ internal static void ExecuteFunctionScript(FunctionScript Function, TrainBase Tr
Function.Stack[s] = 1;
}
s++; break;
- case Instructions.CameraCar:
- if (IsPartOfTrain && Train != null)
- {
- Function.Stack[s] = Train.CameraCar;
- }
- else
- {
- Function.Stack[s] = 0.0;
- }
- s++; break;
- // train
+ // train
case Instructions.PlayerTrain:
if (IsPartOfTrain && Train != null)
{
@@ -712,7 +701,13 @@ internal static void ExecuteFunctionScript(FunctionScript Function, TrainBase Tr
}
break;
case Instructions.PilotLamp:
+ //Not currently supported in viewers
+ Function.Stack[s] = 0.0;
+ s++; break;
case Instructions.PassAlarm:
+ //Not currently supported in viewers
+ Function.Stack[s] = 0.0;
+ s++; break;
case Instructions.StationAdjustAlarm:
//Not currently supported in viewers
Function.Stack[s] = 0.0;
diff --git a/source/RouteViewer/Game/Menu.cs b/source/RouteViewer/Game/Menu.cs
index bc88134b63..9e7a81f922 100644
--- a/source/RouteViewer/Game/Menu.cs
+++ b/source/RouteViewer/Game/Menu.cs
@@ -2,7 +2,6 @@
using System.ComponentModel;
using System.IO;
using System.Text;
-using System.Windows.Forms;
using LibRender2.Menu;
using LibRender2.Primitives;
using LibRender2.Screens;
@@ -453,7 +452,7 @@ private static void routeWorkerThread_doWork(object sender, DoWorkEventArgs e)
{
// ReSharper disable once RedundantCast
object Route = (object)Program.CurrentRoute; // must cast to allow us to use the ref keyword correctly.
- string RailwayFolder = Program.FileSystem.GetRailwayFolder(currentFile, Application.StartupPath);
+ string RailwayFolder = Loading.GetRailwayFolder(currentFile);
string ObjectFolder = Path.CombineDirectory(RailwayFolder, "Object");
string SoundFolder = Path.CombineDirectory(RailwayFolder, "Sound");
if (Program.CurrentHost.Plugins[i].Route.LoadRoute(currentFile, RouteEncoding, null, ObjectFolder, SoundFolder, true, ref Route))
@@ -466,7 +465,7 @@ private static void routeWorkerThread_doWork(object sender, DoWorkEventArgs e)
{
throw Program.CurrentHost.Plugins[i].Route.LastException; //Re-throw last exception generated by the route parser plugin so that the UI thread captures it
}
- routeDescriptionBox.Text = "An unknown error was encountered whilst attempting to parse the routefile " + currentFile;
+ routeDescriptionBox.Text = "An unknown error was enountered whilst attempting to parse the routefile " + currentFile;
RoutefileState = RouteState.Error;
}
loaded = true;
diff --git a/source/RouteViewer/LoadingR.cs b/source/RouteViewer/LoadingR.cs
index f79ba18d39..ed29a0d785 100644
--- a/source/RouteViewer/LoadingR.cs
+++ b/source/RouteViewer/LoadingR.cs
@@ -6,6 +6,7 @@
// ╚═════════════════════════════════════════════════════════════╝
using System;
+using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -49,6 +50,8 @@ internal static bool Cancel
private static string CurrentRouteFile;
private static Encoding CurrentRouteEncoding;
+ internal static bool JobAvailable;
+
// load
internal static void Load(string routeFile, Encoding routeEncoding, byte[] textureBytes)
{
@@ -67,10 +70,85 @@ internal static void Load(string routeFile, Encoding routeEncoding, byte[] textu
CurrentRouteFile = routeFile;
CurrentRouteEncoding = routeEncoding;
// thread
- LoadAsynchronously(CurrentRouteFile, CurrentRouteEncoding);
+ Loading.LoadAsynchronously(CurrentRouteFile, CurrentRouteEncoding);
RouteViewer.LoadingScreenLoop();
}
-
+
+ /// Gets the absolute Railway folder for a given route file
+ /// The absolute on-disk path of the railway folder
+ internal static string GetRailwayFolder(string RouteFile) {
+ try
+ {
+ string Folder = Path.GetDirectoryName(RouteFile);
+
+ while (true)
+ {
+ string Subfolder = Path.CombineDirectory(Folder, "Railway");
+ if (System.IO.Directory.Exists(Subfolder))
+ {
+ if (System.IO.Directory.EnumerateDirectories(Subfolder).Any() || System.IO.Directory.EnumerateFiles(Subfolder).Any())
+ {
+ //HACK: Ignore completely empty directories
+ //Doesn't handle wrong directories, or those with stuff missing, TODO.....
+ return Subfolder;
+ }
+ }
+
+ if (Folder == null) continue;
+ System.IO.DirectoryInfo Info = System.IO.Directory.GetParent(Folder);
+ if (Info == null) break;
+ Folder = Info.FullName;
+ }
+ }
+ catch
+ {
+ //ignored
+ }
+
+ //If the Route, Object and Sound folders exist, but are not in a railway folder.....
+ try
+ {
+ string Folder = Path.GetDirectoryName(RouteFile);
+ if (Folder == null)
+ {
+ // Unlikely to work, but attempt to make the best of it
+ return Application.StartupPath;
+ }
+ string candidate = null;
+ while (true)
+ {
+ string RouteFolder = Path.CombineDirectory(Folder, "Route");
+ string ObjectFolder = Path.CombineDirectory(Folder, "Object");
+ string SoundFolder = Path.CombineDirectory(Folder, "Sound");
+ if (System.IO.Directory.Exists(RouteFolder) && System.IO.Directory.Exists(ObjectFolder) && System.IO.Directory.Exists(SoundFolder))
+ {
+ return Folder;
+ }
+
+ if (System.IO.Directory.Exists(RouteFolder) && System.IO.Directory.Exists(ObjectFolder))
+ {
+ candidate = Folder;
+ }
+
+ System.IO.DirectoryInfo Info = System.IO.Directory.GetParent(Folder);
+ if (Info == null)
+ {
+ if (candidate != null)
+ {
+ return candidate;
+ }
+ break;
+ }
+ Folder = Info.FullName;
+ }
+ }
+ catch
+ {
+ //ignored
+ }
+ return Application.StartupPath;
+ }
+
// load threaded
private static async Task LoadThreaded()
{
@@ -102,7 +180,7 @@ internal static void LoadAsynchronously(string RouteFile, Encoding RouteEncoding
}
private static void LoadEverythingThreaded() {
- string RailwayFolder = Program.FileSystem.GetRailwayFolder(CurrentRouteFile, Application.StartupPath);
+ string RailwayFolder = GetRailwayFolder(CurrentRouteFile);
string ObjectFolder = Path.CombineDirectory(RailwayFolder, "Object");
string SoundFolder = Path.CombineDirectory(RailwayFolder, "Sound");
Program.Renderer.Camera.CurrentMode = CameraViewMode.Track;
diff --git a/source/RouteViewer/NewRendererR.cs b/source/RouteViewer/NewRendererR.cs
index 97c63764b0..85a7c75a18 100644
--- a/source/RouteViewer/NewRendererR.cs
+++ b/source/RouteViewer/NewRendererR.cs
@@ -108,7 +108,7 @@ internal void RenderScene(double timeElapsed)
}
else
{
- GL.ClearColor(Interface.CurrentOptions.ClearColor.R * inv255, Interface.CurrentOptions.ClearColor.G * inv255, Interface.CurrentOptions.ClearColor.B * inv255, 1.0f);
+ GL.ClearColor(0.67f, 0.67f, 0.67f, 1.0f);
}
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
diff --git a/source/RouteViewer/Options.cs b/source/RouteViewer/Options.cs
index defcfd3b44..9a38fbd730 100644
--- a/source/RouteViewer/Options.cs
+++ b/source/RouteViewer/Options.cs
@@ -39,15 +39,15 @@ public override void Save(string fileName)
Builder.AppendLine("windowWidth = " + Program.Renderer.Screen.Width.ToString(Culture));
Builder.AppendLine("windowHeight = " + Program.Renderer.Screen.Height.ToString(Culture));
Builder.AppendLine("isUseNewRenderer = " + (IsUseNewRenderer ? "true" : "false"));
+ Builder.AppendLine("viewingdistance = " + ViewingDistance);
+ Builder.AppendLine("nearclipbase = " + NearClipBase.ToString(Culture));
+ Builder.AppendLine("quadleafsize = " + QuadTreeLeafSize);
Builder.AppendLine();
Builder.AppendLine("[quality]");
Builder.AppendLine("interpolation = " + Interpolation);
Builder.AppendLine("anisotropicfilteringlevel = " + AnisotropicFilteringLevel.ToString(Culture));
Builder.AppendLine("antialiasinglevel = " + AntiAliasingLevel.ToString(Culture));
Builder.AppendLine("transparencyMode = " + ((int)TransparencyMode).ToString(Culture));
- Builder.AppendLine("viewingdistance = " + ViewingDistance);
- Builder.AppendLine("nearclipbase = " + NearClipBase.ToString(Culture));
- Builder.AppendLine("quadleafsize = " + QuadTreeLeafSize);
Builder.AppendLine("shadowresolution = " + (int)ShadowResolution);
Builder.AppendLine("shadowdrawdistance = " + ShadowDrawDistance);
Builder.AppendLine("shadowcascades = " + (int)ShadowCascades);
@@ -129,15 +129,6 @@ internal static void LoadOptions()
block.TryGetValue(OptionsKey.AnisotropicFilteringLevel, ref Interface.CurrentOptions.AnisotropicFilteringLevel);
block.TryGetValue(OptionsKey.AntiAliasingLevel, ref Interface.CurrentOptions.AntiAliasingLevel);
block.GetEnumValue(OptionsKey.TransparencyMode, out Interface.CurrentOptions.TransparencyMode);
- block.TryGetValue(OptionsKey.ViewingDistance, ref Interface.CurrentOptions.ViewingDistance, NumberRange.Positive);
- block.TryGetValue(OptionsKey.QuadLeafSize, ref Interface.CurrentOptions.QuadTreeLeafSize, NumberRange.Positive);
- block.TryGetValue(OptionsKey.NearClipBase, ref Interface.CurrentOptions.NearClipBase, NumberRange.Positive);
- // ensure viewing distance is greater than the near clipping plane to avoid rendering issues
- if (Interface.CurrentOptions.ViewingDistance <= Interface.CurrentOptions.NearClipBase)
-
- {
- Interface.CurrentOptions.ViewingDistance = (int)Math.Ceiling(Interface.CurrentOptions.NearClipBase) + 1;
- }
block.TryGetEnumValue(OptionsKey.ShadowResolution, ref Interface.CurrentOptions.ShadowResolution);
block.TryGetEnumValue(OptionsKey.ShadowDrawDistance, ref Interface.CurrentOptions.ShadowDrawDistance);
block.TryGetEnumValue(OptionsKey.ShadowCascades, ref Interface.CurrentOptions.ShadowCascades);
diff --git a/source/RouteViewer/ProgramR.cs b/source/RouteViewer/ProgramR.cs
index b718bd574f..ea85cf5a9d 100644
--- a/source/RouteViewer/ProgramR.cs
+++ b/source/RouteViewer/ProgramR.cs
@@ -109,45 +109,44 @@ internal static void Main(string[] args)
{
for (int i = 0; i < args.Length; i++)
{
- if (args[i] == null)
+ if (args[i] != null)
{
- continue;
- }
- if (System.IO.File.Exists(args[i]))
- {
- for (int j = 0; j < CurrentHost.Plugins.Length; j++)
+ if (System.IO.File.Exists(args[i]))
{
- if (CurrentHost.Plugins[j].Object != null && CurrentHost.Plugins[j].Object.CanLoadObject(args[i]))
+ for (int j = 0; j < CurrentHost.Plugins.Length; j++)
{
- objectsToLoad += args[i] + " ";
- continue;
- }
+ if (CurrentHost.Plugins[j].Object != null && CurrentHost.Plugins[j].Object.CanLoadObject(args[i]))
+ {
+ objectsToLoad += args[i] + " ";
+ continue;
+ }
- if (CurrentHost.Plugins[j].Route != null && CurrentHost.Plugins[j].Route.CanLoadRoute(args[i]))
- {
- if (string.IsNullOrEmpty(CurrentRouteFile))
+ if (CurrentHost.Plugins[j].Route != null && CurrentHost.Plugins[j].Route.CanLoadRoute(args[i]))
{
- CurrentRouteFile = args[i];
- processCommandLineArgs = true;
+ if (string.IsNullOrEmpty(CurrentRouteFile))
+ {
+ CurrentRouteFile = args[i];
+ processCommandLineArgs = true;
+ }
}
}
}
- }
- else if (args[i].ToLowerInvariant() == "/enablehacks")
- {
- //Deliberately undocumented option for debugging use
- Interface.CurrentOptions.EnableBveTsHacks = true;
- for (int j = 0; j < CurrentHost.Plugins.Length; j++)
+ else if (args[i].ToLowerInvariant() == "/enablehacks")
{
- if (CurrentHost.Plugins[j].Object != null)
+ //Deliberately undocumented option for debugging use
+ Interface.CurrentOptions.EnableBveTsHacks = true;
+ for (int j = 0; j < CurrentHost.Plugins.Length; j++)
{
- CompatabilityHacks enabledHacks = new CompatabilityHacks
+ if (CurrentHost.Plugins[j].Object != null)
{
- BveTsHacks = true,
- CylinderHack = false,
- BlackTransparency = true
- };
- CurrentHost.Plugins[j].Object.SetCompatibilityHacks(enabledHacks);
+ CompatabilityHacks enabledHacks = new CompatabilityHacks
+ {
+ BveTsHacks = true,
+ CylinderHack = false,
+ BlackTransparency = true
+ };
+ CurrentHost.Plugins[j].Object.SetCompatibilityHacks(enabledHacks);
+ }
}
}
}
diff --git a/source/RouteViewer/System/Gamewindow.cs b/source/RouteViewer/System/Gamewindow.cs
index 81473826fe..fe81d4def6 100644
--- a/source/RouteViewer/System/Gamewindow.cs
+++ b/source/RouteViewer/System/Gamewindow.cs
@@ -197,7 +197,7 @@ public static void LoadingScreenLoop()
double time = CPreciseTimer.GetElapsedTime();
double wait = 1000.0 / 60.0 - time * 1000 - 50;
if (wait > 0)
- Thread.Sleep((int)wait);
+ Thread.Sleep((int)(wait));
}
Program.Renderer.Loading.CompleteLoading();
if (!Loading.Cancel)
diff --git a/source/RouteViewer/System/Host.cs b/source/RouteViewer/System/Host.cs
index cd0f3a9209..78fdab2ba2 100644
--- a/source/RouteViewer/System/Host.cs
+++ b/source/RouteViewer/System/Host.cs
@@ -479,7 +479,7 @@ public override bool LoadObject(string path, System.Text.Encoding Encoding, out
public override void ExecuteFunctionScript(OpenBveApi.FunctionScripting.FunctionScript functionScript, AbstractTrain train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState)
{
- FunctionScripts.ExecuteFunctionScript(functionScript, (TrainBase)train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
+ FunctionScripts.ExecuteFunctionScript(functionScript, (TrainManager.Train)train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);
}
public override int CreateStaticObject(StaticObject Prototype, Vector3 Position, ObjectCreationParameters Parameters, Transformation WorldTransformation, Transformation LocalTransformation = null)
@@ -575,11 +575,11 @@ public override AbstractTrain ClosestTrain(AbstractTrain Train)
{
for (int i = 0; i < Program.TrainManager.Trains.Count; i++)
{
- if (Program.TrainManager.Trains[i] != baseTrain && Program.TrainManager.Trains[i].State == TrainState.Available && baseTrain.Cars.Length > 0)
+ if (Program.TrainManager.Trains[i] != baseTrain & Program.TrainManager.Trains[i].State == TrainState.Available & baseTrain.Cars.Length > 0)
{
int c = Program.TrainManager.Trains[i].Cars.Length - 1;
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;
- if (z >= baseTrain.FrontCarTrackPosition && z < bestLocation)
+ if (z >= baseTrain.FrontCarTrackPosition & z < bestLocation)
{
bestLocation = z;
closestTrain = Program.TrainManager.Trains[i];
diff --git a/source/RouteViewer/TrainManagerR.cs b/source/RouteViewer/TrainManagerR.cs
index 2722f1c903..3760e68763 100644
--- a/source/RouteViewer/TrainManagerR.cs
+++ b/source/RouteViewer/TrainManagerR.cs
@@ -9,7 +9,10 @@
using OpenBveApi;
using OpenBveApi.FileSystem;
using OpenBveApi.Hosts;
+using OpenBveApi.Trains;
using TrainManager;
+using TrainManager.Handles;
+using TrainManager.Trains;
namespace RouteViewer {
@@ -18,5 +21,22 @@ internal class TrainManager : TrainManagerBase {
public TrainManager(HostInterface host, BaseRenderer renderer, BaseOptions options, FileSystem fileSystem) : base(host, renderer, options, fileSystem)
{
}
+
+ // train
+ internal class Train : TrainBase {
+ internal Train() : base(TrainState.Pending, TrainType.LocalPlayerTrain)
+ {
+ Handles.Power = new PowerHandle(8, this);
+ Handles.Brake = new BrakeHandle(8, null, this);
+ Handles.HoldBrake = new HoldBrakeHandle(this);
+ }
+ public override int NumberOfCars => this.Cars.Length;
+
+ public override double FrontCarTrackPosition => Cars[0].FrontAxle.Follower.TrackPosition - Cars[0].FrontAxle.Position + 0.5 * Cars[0].Length;
+
+ public override double RearCarTrackPosition => Cars[Cars.Length - 1].RearAxle.Follower.TrackPosition - Cars[Cars.Length - 1].RearAxle.Position - 0.5 * Cars[Cars.Length - 1].Length;
+
+ public override bool IsPlayerTrain => true;
+ }
}
}
diff --git a/source/RouteViewer/app.config b/source/RouteViewer/app.config
index 8d045bfe8d..9706ed099b 100644
--- a/source/RouteViewer/app.config
+++ b/source/RouteViewer/app.config
@@ -16,10 +16,6 @@
-
-
-
-
diff --git a/source/RouteViewer/formOptions.Designer.cs b/source/RouteViewer/formOptions.Designer.cs
index 4292dca849..3315babef9 100644
--- a/source/RouteViewer/formOptions.Designer.cs
+++ b/source/RouteViewer/formOptions.Designer.cs
@@ -78,8 +78,6 @@ private void InitializeComponent()
this.numericUpDownShadowBias = new System.Windows.Forms.NumericUpDown();
this.labelShadowNormalBias = new System.Windows.Forms.Label();
this.numericUpDownShadowNormalBias = new System.Windows.Forms.NumericUpDown();
- this.labelShadowFilterCascades = new System.Windows.Forms.Label();
- this.checkBoxShadowFilterCascades = new System.Windows.Forms.CheckBox();
this.labelNearClip = new System.Windows.Forms.Label();
this.numericUpDownNearClip = new System.Windows.Forms.NumericUpDown();
this.button1 = new System.Windows.Forms.Button();
@@ -490,8 +488,6 @@ private void InitializeComponent()
this.tabPageShadows.Controls.Add(this.numericUpDownShadowBias);
this.tabPageShadows.Controls.Add(this.labelShadowNormalBias);
this.tabPageShadows.Controls.Add(this.numericUpDownShadowNormalBias);
- this.tabPageShadows.Controls.Add(this.checkBoxShadowFilterCascades);
- this.tabPageShadows.Controls.Add(this.labelShadowFilterCascades);
this.tabPageShadows.Location = new System.Drawing.Point(4, 22);
this.tabPageShadows.Name = "tabPageShadows";
this.tabPageShadows.Padding = new System.Windows.Forms.Padding(3);
@@ -590,7 +586,7 @@ private void InitializeComponent()
//
this.labelSunDirection.AutoSize = true;
this.labelSunDirection.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.labelSunDirection.Location = new System.Drawing.Point(6, 220);
+ this.labelSunDirection.Location = new System.Drawing.Point(6, 190);
this.labelSunDirection.Name = "labelSunDirection";
this.labelSunDirection.Size = new System.Drawing.Size(94, 15);
this.labelSunDirection.TabIndex = 36;
@@ -599,7 +595,7 @@ private void InitializeComponent()
// labelSunAzimuth
//
this.labelSunAzimuth.AutoSize = true;
- this.labelSunAzimuth.Location = new System.Drawing.Point(6, 242);
+ this.labelSunAzimuth.Location = new System.Drawing.Point(6, 212);
this.labelSunAzimuth.Name = "labelSunAzimuth";
this.labelSunAzimuth.Size = new System.Drawing.Size(47, 13);
this.labelSunAzimuth.TabIndex = 37;
@@ -607,7 +603,7 @@ private void InitializeComponent()
//
// trackBarSunAzimuth
//
- this.trackBarSunAzimuth.Location = new System.Drawing.Point(6, 258);
+ this.trackBarSunAzimuth.Location = new System.Drawing.Point(6, 228);
this.trackBarSunAzimuth.Maximum = 180;
this.trackBarSunAzimuth.Minimum = -180;
this.trackBarSunAzimuth.Name = "trackBarSunAzimuth";
@@ -620,7 +616,7 @@ private void InitializeComponent()
// labelSunAzimuthValue
//
this.labelSunAzimuthValue.AutoSize = true;
- this.labelSunAzimuthValue.Location = new System.Drawing.Point(247, 262);
+ this.labelSunAzimuthValue.Location = new System.Drawing.Point(247, 232);
this.labelSunAzimuthValue.Name = "labelSunAzimuthValue";
this.labelSunAzimuthValue.Size = new System.Drawing.Size(29, 13);
this.labelSunAzimuthValue.TabIndex = 39;
@@ -629,7 +625,7 @@ private void InitializeComponent()
// labelSunElevation
//
this.labelSunElevation.AutoSize = true;
- this.labelSunElevation.Location = new System.Drawing.Point(6, 306);
+ this.labelSunElevation.Location = new System.Drawing.Point(6, 276);
this.labelSunElevation.Name = "labelSunElevation";
this.labelSunElevation.Size = new System.Drawing.Size(54, 13);
this.labelSunElevation.TabIndex = 40;
@@ -637,7 +633,7 @@ private void InitializeComponent()
//
// trackBarSunElevation
//
- this.trackBarSunElevation.Location = new System.Drawing.Point(6, 322);
+ this.trackBarSunElevation.Location = new System.Drawing.Point(6, 292);
this.trackBarSunElevation.Maximum = 90;
this.trackBarSunElevation.Minimum = -90;
this.trackBarSunElevation.Name = "trackBarSunElevation";
@@ -650,7 +646,7 @@ private void InitializeComponent()
// labelSunElevationValue
//
this.labelSunElevationValue.AutoSize = true;
- this.labelSunElevationValue.Location = new System.Drawing.Point(247, 326);
+ this.labelSunElevationValue.Location = new System.Drawing.Point(247, 296);
this.labelSunElevationValue.Name = "labelSunElevationValue";
this.labelSunElevationValue.Size = new System.Drawing.Size(23, 13);
this.labelSunElevationValue.TabIndex = 42;
@@ -720,24 +716,6 @@ private void InitializeComponent()
0,
0});
//
- // labelShadowFilterCascades
- //
- this.labelShadowFilterCascades.AutoSize = true;
- this.labelShadowFilterCascades.Location = new System.Drawing.Point(6, 194);
- this.labelShadowFilterCascades.Name = "labelShadowFilterCascades";
- this.labelShadowFilterCascades.Size = new System.Drawing.Size(126, 13);
- this.labelShadowFilterCascades.TabIndex = 54;
- this.labelShadowFilterCascades.Text = "Per-cascade culling:";
- //
- // checkBoxShadowFilterCascades
- //
- this.checkBoxShadowFilterCascades.AutoSize = true;
- this.checkBoxShadowFilterCascades.Location = new System.Drawing.Point(160, 194);
- this.checkBoxShadowFilterCascades.Name = "checkBoxShadowFilterCascades";
- this.checkBoxShadowFilterCascades.Size = new System.Drawing.Size(15, 14);
- this.checkBoxShadowFilterCascades.TabIndex = 55;
- this.checkBoxShadowFilterCascades.UseVisualStyleBackColor = true;
- //
// labelNearClip
//
this.labelNearClip.AutoSize = true;
@@ -850,7 +828,7 @@ private void InitializeComponent()
private System.Windows.Forms.NumericUpDown numericUpDownViewingDistance;
private System.Windows.Forms.Label labelNearClip;
private System.Windows.Forms.NumericUpDown numericUpDownNearClip;
- private System.Windows.Forms.Label labelShadowResolution;
+ private System.Windows.Forms.Label labelShadowResolution;
private System.Windows.Forms.ComboBox comboBoxShadowResolution;
private System.Windows.Forms.Label labelShadowDistance;
private System.Windows.Forms.ComboBox comboBoxShadowDistance;
@@ -869,7 +847,5 @@ private void InitializeComponent()
private System.Windows.Forms.NumericUpDown numericUpDownShadowBias;
private System.Windows.Forms.Label labelShadowNormalBias;
private System.Windows.Forms.NumericUpDown numericUpDownShadowNormalBias;
- private System.Windows.Forms.Label labelShadowFilterCascades;
- private System.Windows.Forms.CheckBox checkBoxShadowFilterCascades;
}
}
diff --git a/source/RouteViewer/formOptions.cs b/source/RouteViewer/formOptions.cs
index 84ff0d240d..77a1988231 100644
--- a/source/RouteViewer/formOptions.cs
+++ b/source/RouteViewer/formOptions.cs
@@ -66,6 +66,10 @@ public FormOptions()
if (numericUpDownShadowStrength.Value < 1) numericUpDownShadowStrength.Value = 1;
numericUpDownShadowStrength.Refresh();
numericUpDownShadowBias.Value = (decimal)Interface.CurrentOptions.ShadowBias;
+ if (numericUpDownShadowBias.Value == 0)
+ {
+ numericUpDownShadowBias.Value = 0.000050m;
+ }
numericUpDownShadowBias.Refresh();
numericUpDownShadowNormalBias.DecimalPlaces = 2;
@@ -88,14 +92,13 @@ public FormOptions()
{
labelNearClip.Text = Translations.GetInterfaceString(OpenBveApi.Hosts.HostApplication.OpenBve, new[] { "options", "quality_distance_nearclip" });
}
- checkBoxShadowFilterCascades.Checked = Interface.CurrentOptions.ShadowFilterCascades;
}
private void InitializeSunSliders()
{
- trackBarSunElevation.Value = Math.Max(trackBarSunElevation.Minimum, Math.Min((int)Interface.CurrentOptions.LightElevation, trackBarSunElevation.Maximum));
- trackBarSunAzimuth.Value = Math.Max(trackBarSunAzimuth.Minimum, Math.Min((int)Interface.CurrentOptions.LightAzimuth, trackBarSunAzimuth.Maximum));
- labelSunAzimuthValue.Text = trackBarSunAzimuth.Value + "\u00b0";
+ trackBarSunElevation.Value = (int)Interface.CurrentOptions.LightElevation;
+ trackBarSunAzimuth.Value = (int)Interface.CurrentOptions.LightAzimuth;
+ labelSunAzimuthValue.Text = trackBarSunAzimuth.Value + "\u00b0";
labelSunElevationValue.Text = trackBarSunElevation.Value + "\u00b0";
}
@@ -112,7 +115,6 @@ private void UpdateShadowControlsEnabled()
trackBarSunAzimuth.Enabled = enabled;
trackBarSunElevation.Enabled = enabled;
- checkBoxShadowFilterCascades.Enabled = enabled;
}
private void comboBoxShadowResolution_SelectedIndexChanged(object sender, EventArgs e)
@@ -174,7 +176,6 @@ private void button1_Click(object sender, EventArgs e)
double previousShadowStrength = Interface.CurrentOptions.ShadowStrength;
double previousShadowBias = Interface.CurrentOptions.ShadowBias;
double previousShadowNormalBias = Interface.CurrentOptions.ShadowNormalBias;
- bool previousShadowFilterCascades = Interface.CurrentOptions.ShadowFilterCascades;
//Interpolation mode
InterpolationMode previousInterpolationMode = Interface.CurrentOptions.Interpolation;
@@ -292,7 +293,6 @@ private void button1_Click(object sender, EventArgs e)
Interface.CurrentOptions.ShadowStrength = (double)numericUpDownShadowStrength.Value / 100.0;
Interface.CurrentOptions.ShadowBias = (double)numericUpDownShadowBias.Value;
Interface.CurrentOptions.ShadowNormalBias = (double)numericUpDownShadowNormalBias.Value;
- Interface.CurrentOptions.ShadowFilterCascades = checkBoxShadowFilterCascades.Checked;
@@ -313,7 +313,7 @@ private void button1_Click(object sender, EventArgs e)
if (previousInterpolationMode != Interface.CurrentOptions.Interpolation || previousAnisotropicLevel != Interface.CurrentOptions.AnisotropicFilteringLevel || GraphicsModeChanged || Interface.CurrentOptions.ViewingDistance != previousViewingDistance ||
previousShadowResolution != Interface.CurrentOptions.ShadowResolution || previousShadowDistance != Interface.CurrentOptions.ShadowDrawDistance || previousShadowCascades != Interface.CurrentOptions.ShadowCascades ||
previousShadowStrength != Interface.CurrentOptions.ShadowStrength || previousShadowBias != Interface.CurrentOptions.ShadowBias || previousShadowNormalBias != Interface.CurrentOptions.ShadowNormalBias ||
- Interface.CurrentOptions.NearClipBase != previousNearClipBase || previousShadowFilterCascades != Interface.CurrentOptions.ShadowFilterCascades)
+ Interface.CurrentOptions.NearClipBase != previousNearClipBase)
{
this.DialogResult = DialogResult.OK;
}
diff --git a/source/SoundManager/app.config b/source/SoundManager/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/SoundManager/app.config
+++ b/source/SoundManager/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file
diff --git a/source/TrainEditor/app.config b/source/TrainEditor/app.config
index 2c700c093c..0a9966da17 100644
--- a/source/TrainEditor/app.config
+++ b/source/TrainEditor/app.config
@@ -11,10 +11,6 @@
-
-
-
-
diff --git a/source/TrainEditor2/App.config b/source/TrainEditor2/App.config
index a7794cc247..92fc90eb4e 100644
--- a/source/TrainEditor2/App.config
+++ b/source/TrainEditor2/App.config
@@ -27,10 +27,6 @@
-
-
-
-
diff --git a/source/TrainManager/Car/CarBase.cs b/source/TrainManager/Car/CarBase.cs
index a41e2a2010..38f42d7340 100644
--- a/source/TrainManager/Car/CarBase.cs
+++ b/source/TrainManager/Car/CarBase.cs
@@ -1143,46 +1143,34 @@ public void UpdateTopplingCantAndSpring(double TimeElapsed)
}
/// Updates the position of the camera relative to this car
- public void UpdateCamera(CarBase previousCar = null, double mu = 1.0)
+ public void UpdateCamera()
{
- var a2 = GetAnchor();
- var trackFollower = TrainManagerBase.Renderer.CameraTrackFollower;
- if (previousCar != null && mu < 1.0)
- {
- var a1 = previousCar.GetAnchor();
- trackFollower.WorldPosition = Vector3.CosineInterpolate(a1.worldPosition, a2.worldPosition, mu);
- trackFollower.WorldDirection = Vector3.CosineInterpolate(a1.worldDirection, a2.worldDirection, mu);
- trackFollower.WorldUp = Vector3.CosineInterpolate(a1.worldUp, a2.worldUp, mu);
- trackFollower.WorldSide = Vector3.CosineInterpolate(a1.worldSide, a2.worldSide, mu);
- double mu2 = (1.0 - Math.Cos(mu * Math.PI)) / 2.0;
- trackFollower.UpdateAbsolute(a1.trackPosition + (a2.trackPosition - a1.trackPosition) * mu2, false, false);
- }
- else
- {
- trackFollower.WorldPosition = a2.worldPosition;
- trackFollower.WorldDirection = a2.worldDirection;
- trackFollower.WorldUp = a2.worldUp;
- trackFollower.WorldSide = a2.worldSide;
- trackFollower.UpdateAbsolute(a2.trackPosition, false, false);
- }
- }
-
- public (Vector3 worldPosition, Vector3 worldDirection, Vector3 worldUp, Vector3 worldSide, double trackPosition) GetAnchor()
- {
- Vector3 worldDirection = FrontAxle.Follower.WorldPosition - RearAxle.Follower.WorldPosition;
- worldDirection.Normalize();
- Vector3 worldSide = Vector3.Cross(Up, worldDirection);
- Vector3 worldPosition = 0.5 * (FrontAxle.Follower.WorldPosition + RearAxle.Follower.WorldPosition);
+ Vector3 direction = new Vector3(FrontAxle.Follower.WorldPosition - RearAxle.Follower.WorldPosition);
+ direction *= direction.Magnitude();
+ double sx = direction.Z * Up.Y - direction.Y * Up.Z;
+ double sy = direction.X * Up.Z - direction.Z * Up.X;
+ double sz = direction.Y * Up.X - direction.X * Up.Y;
+ double rx = 0.5 * (FrontAxle.Follower.WorldPosition.X + RearAxle.Follower.WorldPosition.X);
+ double ry = 0.5 * (FrontAxle.Follower.WorldPosition.Y + RearAxle.Follower.WorldPosition.Y);
+ double rz = 0.5 * (FrontAxle.Follower.WorldPosition.Z + RearAxle.Follower.WorldPosition.Z);
+ Vector3 cameraPosition;
Vector3 driverPosition = HasInteriorView ? Driver : baseTrain.Cars[baseTrain.DriverCar].Driver;
- worldPosition += worldSide * driverPosition.X + Up * driverPosition.Y + worldDirection * driverPosition.Z;
- double interpolationRatio = (Driver.Z - RearAxle.Position) / (FrontAxle.Position - RearAxle.Position);
- if (double.IsNaN(interpolationRatio))
+ cameraPosition.X = rx + sx * driverPosition.X + Up.X * driverPosition.Y + direction.X * driverPosition.Z;
+ cameraPosition.Y = ry + sy * driverPosition.X + Up.Y * driverPosition.Y + direction.Y * driverPosition.Z;
+ cameraPosition.Z = rz + sz * driverPosition.X + Up.Z * driverPosition.Y + direction.Z * driverPosition.Z;
+
+ TrainManagerBase.Renderer.CameraTrackFollower.WorldPosition = cameraPosition;
+ TrainManagerBase.Renderer.CameraTrackFollower.WorldDirection = direction;
+ TrainManagerBase.Renderer.CameraTrackFollower.WorldUp = new Vector3(Up);
+ TrainManagerBase.Renderer.CameraTrackFollower.WorldSide = new Vector3(sx, sy, sz);
+ double f = (Driver.Z - RearAxle.Position) / (FrontAxle.Position - RearAxle.Position);
+ if (double.IsNaN(f))
{
// car with both axles at zero and a driver position of zero creates NaN (guarded against in original BVE parser)
- interpolationRatio = 0;
+ f = 0;
}
- double trackPosition = (1.0 - interpolationRatio) * RearAxle.Follower.TrackPosition + interpolationRatio * FrontAxle.Follower.TrackPosition;
- return (worldPosition, worldDirection, new Vector3(Up), worldSide, trackPosition);
+ double tp = (1.0 - f) * RearAxle.Follower.TrackPosition + f * FrontAxle.Follower.TrackPosition;
+ TrainManagerBase.Renderer.CameraTrackFollower.UpdateAbsolute(tp, false, false);
}
public void UpdateSpeed(double TimeElapsed, double DecelerationDueToMotor, double DecelerationDueToBrake, out double Speed)
diff --git a/source/TrainManager/Car/Systems/ReadhesionDevice.cs b/source/TrainManager/Car/Systems/ReadhesionDevice.cs
index 4dabce2ded..538c5cf0e5 100644
--- a/source/TrainManager/Car/Systems/ReadhesionDevice.cs
+++ b/source/TrainManager/Car/Systems/ReadhesionDevice.cs
@@ -1,4 +1,5 @@
-using TrainManager.Car.Systems;
+using System;
+using TrainManager.Car.Systems;
namespace TrainManager.Car
{
diff --git a/source/TrainManager/Car/Systems/RunSounds.cs b/source/TrainManager/Car/Systems/RunSounds.cs
index 13861b3707..11eea1d21b 100644
--- a/source/TrainManager/Car/Systems/RunSounds.cs
+++ b/source/TrainManager/Car/Systems/RunSounds.cs
@@ -45,14 +45,14 @@ public void Update(double TimeElapsed)
NextReasynchronizationPosition = baseCar.baseTrain.Cars[0].FrontAxle.Follower.TrackPosition;
}
}
- else if (double.IsPositiveInfinity(NextReasynchronizationPosition) & baseCar.FrontAxle.RunIndex >= 0)
+ else if (NextReasynchronizationPosition == double.MaxValue & baseCar.FrontAxle.RunIndex >= 0)
{
double distance = Math.Abs(baseCar.FrontAxle.Follower.TrackPosition - TrainManagerBase.Renderer.CameraTrackFollower.TrackPosition);
const double minDistance = 150.0;
const double maxDistance = 750.0;
if (distance > minDistance)
{
- if (Sounds.TryGetValue(baseCar.FrontAxle.RunIndex, out CarSound runSound) && runSound.Buffer != null)
+ if (Sounds.TryGetValue(baseCar.FrontAxle.RunIndex, out var runSound) && runSound.Buffer != null)
{
if (runSound.Buffer.Duration > 0.0)
{
@@ -65,7 +65,7 @@ public void Update(double TimeElapsed)
if (baseCar.FrontAxle.Follower.TrackPosition >= NextReasynchronizationPosition)
{
- NextReasynchronizationPosition = double.PositiveInfinity;
+ NextReasynchronizationPosition = double.MaxValue;
basegain = 0.0;
}
else
diff --git a/source/TrainManager/Car/Systems/Sanders.cs b/source/TrainManager/Car/Systems/Sanders.cs
index 2cc50d5b10..1058c1c3c6 100644
--- a/source/TrainManager/Car/Systems/Sanders.cs
+++ b/source/TrainManager/Car/Systems/Sanders.cs
@@ -71,7 +71,7 @@ public override void Update(double timeElapsed)
return;
}
- if (State == SandersState.Active)
+ if (State != SandersState.Inactive)
{
if ((ActivationSound != null && !ActivationSound.IsPlaying) || ActivationSound == null)
{
@@ -98,7 +98,7 @@ public override void Update(double timeElapsed)
}
else
{
- if (State == SandersState.Active && SandingRate > 0 && SandingRate < double.MaxValue)
+ if (SandingRate > 0 && SandingRate < double.MaxValue)
{
SandLevel -= SandingRate * timeElapsed;
}
@@ -179,7 +179,10 @@ public void SetActive(bool willBeActive)
ActivationSound?.Play(Car, false);
}
- State = willBeActive ? SandersState.Active : SandersState.Inactive;
+ if (willBeActive)
+ {
+ State = SandersState.Active;
+ }
}
public void Toggle()
diff --git a/source/TrainManager/Car/Windscreen/Windscreen.cs b/source/TrainManager/Car/Windscreen/Windscreen.cs
index 4760bc2157..ed9e8e9dd7 100644
--- a/source/TrainManager/Car/Windscreen/Windscreen.cs
+++ b/source/TrainManager/Car/Windscreen/Windscreen.cs
@@ -79,7 +79,7 @@ public void Update(double TimeElapsed)
{
int nextDrop = PickDrop();
dropTimer += TimeElapsed * 1000;
- int dev = (int)(0.4 * 2000 / Intensity);
+ var dev = (int)(0.4 * 2000 / Intensity);
int dropInterval = 2000 / Intensity + TrainManagerBase.RandomNumberGenerator.Next(dev, dev * 2);
if (dropTimer > dropInterval)
{
diff --git a/source/TrainManager/Handles/Brake/Handles.Brake.cs b/source/TrainManager/Handles/Brake/Handles.Brake.cs
index c4d031da58..291ee1f94d 100644
--- a/source/TrainManager/Handles/Brake/Handles.Brake.cs
+++ b/source/TrainManager/Handles/Brake/Handles.Brake.cs
@@ -187,25 +187,27 @@ public override string GetNotchDescription(out MessageColor color)
return Translations.QuickReferences.HandleBrakeNull;
}
-
- if (baseTrain.Handles.EmergencyBrake.Driver)
+ else
{
- color = MessageColor.Red;
- return NotchDescriptions[0];
- }
+ if (baseTrain.Handles.EmergencyBrake.Driver)
+ {
+ color = MessageColor.Red;
+ return NotchDescriptions[0];
+ }
- if (baseTrain.Handles.HasHoldBrake && baseTrain.Handles.HoldBrake.Driver) {
- color = MessageColor.Green;
- return NotchDescriptions[1];
- }
+ if (baseTrain.Handles.HasHoldBrake && baseTrain.Handles.HoldBrake.Driver) {
+ color = MessageColor.Green;
+ return NotchDescriptions[1];
+ }
- if (Driver != 0)
- {
- color = MessageColor.Orange;
- return NotchDescriptions[offset + Driver];
- }
+ if (Driver != 0)
+ {
+ color = MessageColor.Orange;
+ return NotchDescriptions[offset + Driver];
+ }
- return NotchDescriptions[offset];
+ return NotchDescriptions[offset];
+ }
}
}
diff --git a/source/TrainManager/Handles/Brake/Handles.EmergencyBrake.cs b/source/TrainManager/Handles/Brake/Handles.EmergencyBrake.cs
index de5f22d669..8c4ecdd397 100644
--- a/source/TrainManager/Handles/Brake/Handles.EmergencyBrake.cs
+++ b/source/TrainManager/Handles/Brake/Handles.EmergencyBrake.cs
@@ -1,4 +1,5 @@
-using OpenBveApi;
+using System;
+using OpenBveApi;
using OpenBveApi.Colors;
using OpenBveApi.Interface;
using RouteManager2.MessageManager;
diff --git a/source/TrainManager/Handles/Brake/Handles.LocoBrake.cs b/source/TrainManager/Handles/Brake/Handles.LocoBrake.cs
index cf1326c970..c0ad24e3d7 100644
--- a/source/TrainManager/Handles/Brake/Handles.LocoBrake.cs
+++ b/source/TrainManager/Handles/Brake/Handles.LocoBrake.cs
@@ -244,21 +244,23 @@ public override string GetNotchDescription(out MessageColor color)
return Translations.QuickReferences.HandleBrakeNull;
}
-
- if (baseTrain.Handles.EmergencyBrake.Driver)
+ else
{
- color = MessageColor.Red;
- return NotchDescriptions[0];
- }
+ if (baseTrain.Handles.EmergencyBrake.Driver)
+ {
+ color = MessageColor.Red;
+ return NotchDescriptions[0];
+ }
- if (Driver != 0)
- {
- color = MessageColor.Orange;
- return NotchDescriptions[Driver + 1];
- }
+ if (Driver != 0)
+ {
+ color = MessageColor.Orange;
+ return NotchDescriptions[Driver + 1];
+ }
- return NotchDescriptions[1];
+ return NotchDescriptions[1];
+ }
}
}
diff --git a/source/TrainManager/Handles/Power/PowerHandle.cs b/source/TrainManager/Handles/Power/PowerHandle.cs
index 1db8e065e7..32424a7aad 100644
--- a/source/TrainManager/Handles/Power/PowerHandle.cs
+++ b/source/TrainManager/Handles/Power/PowerHandle.cs
@@ -196,8 +196,10 @@ public override string GetNotchDescription(out MessageColor color)
return Translations.QuickReferences.HandlePowerNull;
}
-
- return NotchDescriptions[Driver];
+ else
+ {
+ return NotchDescriptions[Driver];
+ }
}
}
}
diff --git a/source/TrainManager/SafetySystems/Plugin/ProxyPlugin.cs b/source/TrainManager/SafetySystems/Plugin/ProxyPlugin.cs
index 21685b5f84..7a16886e57 100644
--- a/source/TrainManager/SafetySystems/Plugin/ProxyPlugin.cs
+++ b/source/TrainManager/SafetySystems/Plugin/ProxyPlugin.cs
@@ -52,10 +52,10 @@ internal ProxyPlugin(string pluginFile, TrainBase train)
externalCrashed = false;
PluginTitle = System.IO.Path.GetFileName(pluginFile);
//Load the plugin via the proxy callback
- IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
+ var handle = Process.GetCurrentProcess().MainWindowHandle;
try
{
- Process hostProcess = new Process();
+ var hostProcess = new Process();
hostProcess.StartInfo.FileName = @"Win32PluginProxy.exe";
hostProcess.Start();
HostInterface.Win32PluginHostReady.WaitOne();
@@ -134,24 +134,12 @@ public override bool Load(VehicleSpecs specs, InitializationModes mode)
public override void Unload()
{
- if (externalCrashed == false)
- {
- pipeProxy.Unload();
- }
+ pipeProxy.Unload();
}
public override void BeginJump(InitializationModes mode)
{
- try
- {
- pipeProxy.BeginJump(mode);
- }
- catch(Exception ex)
- {
- lastError = ex.ToString();
- externalCrashed = true;
- }
-
+ pipeProxy.BeginJump(mode);
if (SupportsAI == AISupport.Program)
{
AI.BeginJump(mode);
@@ -180,16 +168,15 @@ protected override void Elapse(ref ElapseData data)
}
}
Train.UnloadPlugin();
- if (!string.IsNullOrEmpty(lastError))
- {
-
- TrainManagerBase.currentHost.AddMessage("The train plugin " + PluginTitle + " has been unloaded due to an error. Some train features may no longer work.");
- TrainManagerBase.FileSystem.AppendToLogFile(lastError);
- lastError = string.Empty;
- }
return;
}
-
+ if (!string.IsNullOrEmpty(lastError))
+ {
+
+ //TrainManagercurrentHost.A("ERROR: The proxy plugin " + PluginFile + " generated the following error:");
+ //Program.FileSystem.AppendToLogFile(pluginProxy.callback.lastError);
+ lastError = string.Empty;
+ }
try
{
diff --git a/source/TrainManager/TrackFollowingObject/AI/TrackFollowingObject.AI.cs b/source/TrainManager/TrackFollowingObject/AI/TrackFollowingObject.AI.cs
index 9ec2862935..39fb210f9f 100644
--- a/source/TrainManager/TrackFollowingObject/AI/TrackFollowingObject.AI.cs
+++ b/source/TrainManager/TrackFollowingObject/AI/TrackFollowingObject.AI.cs
@@ -29,7 +29,6 @@
using OpenBveApi.Motor;
using OpenBveApi.Routes;
using OpenBveApi.Trains;
-using TrainManager.Car;
using TrainManager.Handles;
using TrainManager.Motor;
@@ -146,7 +145,7 @@ public override void Trigger(double TimeElapsed)
Train.Specs.CurrentAverageAcceleration = 0.0;
}
- foreach (CarBase Car in Train.Cars)
+ foreach (var Car in Train.Cars)
{
SetRailIndex(NewMileage, NewDirection, Car.FrontAxle.Follower);
SetRailIndex(NewMileage, NewDirection, Car.RearAxle.Follower);
diff --git a/source/TrainManager/TrackFollowingObject/ScriptedTrain.cs b/source/TrainManager/TrackFollowingObject/ScriptedTrain.cs
index 01ed06a8f9..5fffd05c15 100644
--- a/source/TrainManager/TrackFollowingObject/ScriptedTrain.cs
+++ b/source/TrainManager/TrackFollowingObject/ScriptedTrain.cs
@@ -1,7 +1,6 @@
using System;
using LibRender2.Trains;
using OpenBveApi.Trains;
-using TrainManager.Car;
using TrainManager.SafetySystems;
namespace TrainManager.Trains
@@ -135,7 +134,7 @@ private void UpdatePhysicsAndControls(double TimeElapsed)
UpdateDoors(TimeElapsed);
// Update Run and Motor sounds
- foreach (CarBase Car in Cars)
+ foreach (var Car in Cars)
{
Car.Run.Update(TimeElapsed);
Car.TractionModel?.Update(TimeElapsed);
diff --git a/source/TrainManager/Train/TrainBase.cs b/source/TrainManager/Train/TrainBase.cs
index 2a9a237d74..b673c1144f 100644
--- a/source/TrainManager/Train/TrainBase.cs
+++ b/source/TrainManager/Train/TrainBase.cs
@@ -1,4 +1,3 @@
-using LibRender2.Cameras;
using LibRender2.Screens;
using LibRender2.Trains;
using OpenBveApi;
@@ -16,6 +15,7 @@
using SoundManager;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
using System.Linq;
using TrainManager.BrakeSystems;
@@ -662,7 +662,7 @@ private void UpdateSpeeds(double timeElapsed)
double min = Cars[p].Coupler.MinimumDistanceBetweenCars;
double max = Cars[p].Coupler.MaximumDistanceBetweenCars;
double d = CenterOfCarPositions[p] - CenterOfCarPositions[s] - 0.5 * (Cars[p].Length + Cars[s].Length);
- if (d < min && min < max)
+ if (d < min)
{
double t = (min - d) / (Cars[p].CurrentMass + Cars[s].CurrentMass);
double tp = t * Cars[s].CurrentMass;
@@ -673,22 +673,6 @@ private void UpdateSpeeds(double timeElapsed)
CenterOfCarPositions[s] -= ts;
CouplerCollision[p] = true;
}
- else if (d < min)
- {
- /*
- * References:
- * https://github.com/leezer3/OpenBVE/issues/1258
- * https://github.com/leezer3/OpenBVE/issues/1298
- * If min == max we don't want to move our cars here
- * (as the following code may then move them again in the opposite direction, causing a 'vibrating' effect)
- *
- * However what the original fix overlooked, is that if we don't set the collision flag, and collision
- * is not detected in the following code, when the speed is updated the car carries on 'into' the car in front,
- * as the updates speeds loop relies on the CouplerCollisions array
- *
- */
- CouplerCollision[p] = true;
- }
else if (d > max & !Cars[p].Derailed & !Cars[s].Derailed)
{
double t = (d - max) / (Cars[p].CurrentMass + Cars[s].CurrentMass);
@@ -1115,31 +1099,25 @@ public void ChangeCameraCar(bool shouldIncrement)
// If in the reverse direction, the last car is Car0 and the direction of increase is reversed
shouldIncrement = !shouldIncrement;
}
-
- int currentTarget = TrainManagerBase.Renderer.Camera.TargetCameraCar != -1 ? TrainManagerBase.Renderer.Camera.TargetCameraCar : CameraCar;
- int nextCar = shouldIncrement ? currentTarget + 1 : currentTarget - 1;
-
- if (nextCar >= 0 && nextCar < Cars.Length)
+
+ if (shouldIncrement)
{
- TrainManagerBase.Renderer.Camera.TargetCameraCar = nextCar;
-
- if (!TrainManagerBase.Renderer.Camera.IsTransitioning)
+ if (CameraCar < Cars.Length - 1)
{
- TrainManagerBase.Renderer.Camera.PreviousCameraCar = CameraCar;
- CameraCar = nextCar;
- TrainManagerBase.Renderer.Camera.TargetCameraCar = -1;
- TrainManagerBase.Renderer.Camera.IsTransitioning = true;
- TrainManagerBase.Renderer.Camera.CameraCarTransitionTimer = 0.0;
+ CameraCar++;
+ TrainManagerBase.currentHost.AddMessage(Translations.GetInterfaceString(HostApplication.OpenBve, new [] {"notification","exterior"}) + " " + (CurrentDirection == TrackDirection.Reverse ? Cars.Length - CameraCar : CameraCar + 1), MessageDependency.CameraView, GameMode.Expert,
+ MessageColor.White, 2.0, null);
}
-
- TrainManagerBase.currentHost.AddMessage(
- Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "notification", "exterior" }) + " " + (CurrentDirection == TrackDirection.Reverse ? Cars.Length - nextCar : nextCar + 1),
- MessageDependency.CameraView,
- GameMode.Expert,
- MessageColor.White,
- 2.0,
- null);
}
+ else
+ {
+ if (CameraCar > 0)
+ {
+ CameraCar--;
+ TrainManagerBase.currentHost.AddMessage(Translations.GetInterfaceString(HostApplication.OpenBve, new [] {"notification","exterior"}) + " " + (CurrentDirection == TrackDirection.Reverse ? Cars.Length - CameraCar : CameraCar + 1), MessageDependency.CameraView, GameMode.Expert, MessageColor.White, 2.0, null);
+ }
+ }
+
}
public override void Couple(AbstractTrain train, bool front)
diff --git a/source/TrainManager/app.config b/source/TrainManager/app.config
index 8a787375cc..a1e2bff25d 100644
--- a/source/TrainManager/app.config
+++ b/source/TrainManager/app.config
@@ -10,10 +10,6 @@
-
-
-
-
\ No newline at end of file