Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions source/LibRender2/BaseRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,17 @@ public void Reset()
VisibleObjects.Clear();
}

/// <summary>Resets the renderer state selectively from a given track position.</summary>
/// <param name="startPosition">The track position from which to clear objects.</param>
public void ResetSelective(double startPosition)
{
currentHost.AnimatedObjectCollectionCache.Clear();
// clear out world objects from the change point onwards so we can re-add them
StaticObjectStates.RemoveAll(s => s.TrackPosition >= startPosition || (s.TrackPosition == -1.0f && s.StartingDistance >= startPosition));
DynamicObjectStates.RemoveAll(s => s.TrackPosition >= startPosition || (s.TrackPosition == -1.0f && s.StartingDistance >= startPosition));
VisibleObjects.ClearSelective(startPosition);
}

public int CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, ObjectDisposalMode AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition)
{
Matrix4D Translate = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z);
Expand Down Expand Up @@ -643,6 +654,7 @@ public int CreateStaticObject(Vector3 Position, StaticObject Prototype, Transfor
Rotate = Rotate,
StartingDistance = startingDistance,
EndingDistance = endingDistance,
TrackPosition = (float)TrackPosition,
WorldPosition = Position
});

Expand Down
18 changes: 18 additions & 0 deletions source/LibRender2/Objects/ObjectLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,24 @@ public void Clear()
myOverlayAlphaFaces.Clear();
renderer.StaticObjectStates.Clear();
renderer.DynamicObjectStates.Clear();
quadTree.Clear();
}
}

/// <summary>Selective cleanup of objects and spatial partitioning tree.</summary>
/// <param name="startPosition">The track position from which to clear.</param>
public void ClearSelective(double startPosition)
{
lock (LockObject)
{
// remove objects effectively from the modification point onwards
List<ObjectState> toRemove = Objects.Keys.Where(s => s.StartingDistance >= startPosition).ToList();
foreach (var state in toRemove)
{
RemoveObject(state);
}
// clear the tree so it gets rebuilt properly with the new world objects
quadTree.Clear();
}
}

Expand Down
5 changes: 4 additions & 1 deletion source/OpenBveApi/Objects/ObjectState.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using OpenBveApi.Math;

namespace OpenBveApi.Objects
Expand Down Expand Up @@ -79,6 +79,8 @@ public Matrix4D ModelMatrix
public float StartingDistance;
/// <summary>The ending track position, for static objects only.</summary>
public float EndingDistance;
/// <summary>The track position marker (used for selective reload cleanup)</summary>
public float TrackPosition;

/// <summary>Creates a new ObjectState</summary>
public ObjectState()
Expand All @@ -90,6 +92,7 @@ public ObjectState()
TextureTranslation = Matrix4D.Identity;
StartingDistance = 0.0f;
EndingDistance = 0.0f;
TrackPosition = -1.0f;
updateModelMatrix = false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,27 @@ public void Update(AbstractTrain Train, int CarIndex, double TrackPosition, Vect
/// <param name="sectionIndex">The index of the section if placed using a SigF command</param>
/// <param name="TrackPosition">The absolute track position</param>
public void CreateObject(Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, int sectionIndex, double TrackPosition)
{
CreateObject(Position, WorldTransformation, LocalTransformation, sectionIndex, 0.0f, 0.0f, TrackPosition);
}

/// <param name="StartingDistance">The starting distance</param>
/// <param name="EndingDistance">The ending distance</param>
/// <param name="TrackPosition">The absolute track position</param>
public void CreateObject(Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, int sectionIndex, double StartingDistance, double EndingDistance, double TrackPosition)
{
CreateObject(Position, WorldTransformation, LocalTransformation, sectionIndex, (float)StartingDistance, (float)EndingDistance, TrackPosition);
}

/// <summary>Creates the animated object within the worldspace</summary>
/// <param name="Position">The absolute position</param>
/// <param name="WorldTransformation">The world transformation to apply (e.g. ground, rail)</param>
/// <param name="LocalTransformation">The local transformation to apply in order to rotate the model</param>
/// <param name="sectionIndex">The index of the section if placed using a SigF command</param>
/// <param name="StartingDistance">The starting distance</param>
/// <param name="EndingDistance">The ending distance</param>
/// <param name="TrackPosition">The absolute track position</param>
public void CreateObject(Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, int sectionIndex, float StartingDistance, float EndingDistance, double TrackPosition)
{

int a = currentHost.AnimatedWorldObjectsUsed;
Expand All @@ -770,6 +791,9 @@ public void CreateObject(Vector3 Position, Transformation WorldTransformation, T
{
var o = this.Clone();
currentHost.CreateDynamicObject(ref o.internalObject);
o.internalObject.StartingDistance = StartingDistance;
o.internalObject.EndingDistance = EndingDistance;
o.internalObject.TrackPosition = (float)TrackPosition;
TrackFollowingObject currentObject = new TrackFollowingObject(currentHost)
{
Position = Position,
Expand Down Expand Up @@ -814,6 +838,9 @@ public void CreateObject(Vector3 Position, Transformation WorldTransformation, T
{
var o = this.Clone();
currentHost.CreateDynamicObject(ref o.internalObject);
o.internalObject.StartingDistance = StartingDistance;
o.internalObject.EndingDistance = EndingDistance;
o.internalObject.TrackPosition = (float)TrackPosition;
o.SectionIndex = sectionIndex;
AnimatedWorldObject currentObject = new AnimatedWorldObject(currentHost)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Linq;
using OpenBveApi.Hosts;
using OpenBveApi.Math;
Expand Down Expand Up @@ -75,7 +75,7 @@ public override void CreateObject(Vector3 Position, Transformation WorldTransfor
}
else
{
Objects[i].Clone().CreateObject(Position, WorldTransformation, LocalTransformation, SectionIndex, TrackPosition);
Objects[i].Clone().CreateObject(Position, WorldTransformation, LocalTransformation, SectionIndex, StartingDistance, EndingDistance, TrackPosition);
}
}
}
Expand All @@ -86,7 +86,7 @@ public override void CreateObject(Vector3 Position, Transformation WorldTransfor
{
if (Objects[i].States.Length != 0)
{
Objects[i].Clone().CreateObject(Position, WorldTransformation, LocalTransformation, SectionIndex, TrackPosition);
Objects[i].Clone().CreateObject(Position, WorldTransformation, LocalTransformation, SectionIndex, StartingDistance, EndingDistance, TrackPosition);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ public override void CreateObject(Vector3 position, Transformation worldTransfor
Objects[i].WorldPosition = position;
Objects[i].Rotate = Matrix4D.NoTransformation;
Objects[i].Translation = Matrix4D.NoTransformation;
Objects[i].StartingDistance = (float)startingDistance;
Objects[i].EndingDistance = (float)endingDistance;
Objects[i].TrackPosition = (float)trackPosition;
currentHost.ShowObject(Objects[i], ObjectType.Dynamic);
Objects[i].Matricies = matriciesToShader;
}
Expand Down
5 changes: 4 additions & 1 deletion source/OpenBveApi/Routes/RouteInterface.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;

namespace OpenBveApi.Routes
{
Expand Down Expand Up @@ -41,5 +41,8 @@ public virtual void Unload() { }

/// <summary>Holds the current loading progress</summary>
public double CurrentProgress;

/// <summary>The track position to start parsing from (for selective reloading)</summary>
public double StartTrackPosition = 0;
}
}
91 changes: 71 additions & 20 deletions source/Plugins/Route.CsvRw/CsvRwRouteParser.ApplyRouteData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -633,21 +633,31 @@ private void ApplyRouteData(string FileName, ref RouteData Data, bool PreviewOnl
int gi = Data.Blocks[i].Cycle[ci];
if (Data.Structure.Ground.ContainsKey(gi))
{
Data.Structure.Ground[Data.Blocks[i].Cycle[ci]].CreateObject(Position + new Vector3(0.0, -Data.Blocks[i].Height, 0.0), GroundTransformation, StartingDistance, EndingDistance, StartingDistance);
// only re-create objects if they are in the modified section
if (StartingDistance >= StartTrackPosition)
{
Data.Structure.Ground[Data.Blocks[i].Cycle[ci]].CreateObject(Position + new Vector3(0.0, -Data.Blocks[i].Height, 0.0), GroundTransformation, StartingDistance, EndingDistance, StartingDistance);
}
}
}
// ground-aligned free objects
if (!PreviewOnly)
{
for (int j = 0; j < Data.Blocks[i].GroundFreeObj.Count; j++)
{
Data.Blocks[i].GroundFreeObj[j].CreateGroundAligned(Data.Structure.FreeObjects, Position, GroundTransformation, Direction, Data.Blocks[i].Height, StartingDistance, EndingDistance);
if (StartingDistance >= StartTrackPosition)
{
Data.Blocks[i].GroundFreeObj[j].CreateGroundAligned(Data.Structure.FreeObjects, Position, GroundTransformation, Direction, Data.Blocks[i].Height, StartingDistance, EndingDistance);
}
}
}
if (!PreviewOnly && Data.Structure.WeatherObjects.ContainsKey(Data.Blocks[i].WeatherObject))
{
UnifiedObject obj = Data.Structure.WeatherObjects[Data.Blocks[i].WeatherObject];
obj.CreateObject(Position, GroundTransformation, Data.Blocks[i].Height, StartingDistance, EndingDistance);
if (StartingDistance >= StartTrackPosition)
{
UnifiedObject obj = Data.Structure.WeatherObjects[Data.Blocks[i].WeatherObject];
obj.CreateObject(Position, GroundTransformation, Data.Blocks[i].Height, StartingDistance, EndingDistance);
}
}
// rail-aligned objects
{
Expand Down Expand Up @@ -784,7 +794,10 @@ private void ApplyRouteData(string FileName, ref RouteData Data, bool PreviewOnl

if (Data.Structure.RailObjects.ContainsKey(Data.Blocks[i].RailType[railKey]))
{
Data.Structure.RailObjects[Data.Blocks[i].RailType[railKey]]?.CreateObject(pos, RailTransformation, StartingDistance, EndingDistance, StartingDistance);
if (StartingDistance >= StartTrackPosition)
{
Data.Structure.RailObjects[Data.Blocks[i].RailType[railKey]]?.CreateObject(pos, RailTransformation, StartingDistance, EndingDistance, StartingDistance);
}
}

// points of interest
Expand Down Expand Up @@ -822,19 +835,28 @@ private void ApplyRouteData(string FileName, ref RouteData Data, bool PreviewOnl
// poles
if (Data.Blocks[i].RailPole.Length > railKey)
{
Data.Blocks[i].RailPole[railKey].Create(Data.Structure.Poles, pos, RailTransformation, Direction, planar, updown, StartingDistance, EndingDistance);
if (StartingDistance >= StartTrackPosition)
{
Data.Blocks[i].RailPole[railKey].Create(Data.Structure.Poles, pos, RailTransformation, Direction, planar, updown, StartingDistance, EndingDistance);
}
}

// walls
if (Data.Blocks[i].RailWall.ContainsKey(railKey))
{
Data.Blocks[i].RailWall[railKey].Create(pos, RailTransformation, StartingDistance, EndingDistance);
if (StartingDistance >= StartTrackPosition)
{
Data.Blocks[i].RailWall[railKey].Create(pos, RailTransformation, StartingDistance, EndingDistance);
}
}

// dikes
if (Data.Blocks[i].RailDike.ContainsKey(railKey))
{
Data.Blocks[i].RailDike[railKey].Create(pos, RailTransformation, StartingDistance, EndingDistance);
if (StartingDistance >= StartTrackPosition)
{
Data.Blocks[i].RailDike[railKey].Create(pos, RailTransformation, StartingDistance, EndingDistance);
}
}

// sounds
Expand Down Expand Up @@ -873,7 +895,10 @@ private void ApplyRouteData(string FileName, ref RouteData Data, bool PreviewOnl
{
for (int k = 0; k < Data.Blocks[i].RailFreeObj[railKey].Count; k++)
{
Data.Blocks[i].RailFreeObj[railKey][k].CreateRailAligned(Data.Structure.FreeObjects, new Vector3(pos), RailTransformation, StartingDistance, EndingDistance);
if (StartingDistance >= StartTrackPosition)
{
Data.Blocks[i].RailFreeObj[railKey][k].CreateRailAligned(Data.Structure.FreeObjects, new Vector3(pos), RailTransformation, StartingDistance, EndingDistance);
}
}
}

Expand All @@ -891,9 +916,17 @@ private void ApplyRouteData(string FileName, ref RouteData Data, bool PreviewOnl
// patterns key off rail 0
while (Data.Blocks[i].PatternObjs[key].LastPlacement + Data.Blocks[i].PatternObjs[key].Interval < (i + 1) * Data.BlockInterval)
{
if (!Data.Blocks[i].PatternObjs[key].CreateRailAligned(Data.Structure.FreeObjects, new Vector3(pos), RailTransformation, StartingDistance, EndingDistance))
if (StartingDistance >= StartTrackPosition)
{
break;
if (!Data.Blocks[i].PatternObjs[key].CreateRailAligned(Data.Structure.FreeObjects, new Vector3(pos), RailTransformation, StartingDistance, EndingDistance))
{
break;
}
}
else
{
// we still need to "pretend" to place it to keep the state correct
Data.Blocks[i].PatternObjs[key].LastPlacement += Data.Blocks[i].PatternObjs[key].Interval;
}
}

Expand All @@ -910,18 +943,27 @@ private void ApplyRouteData(string FileName, ref RouteData Data, bool PreviewOnl
{
for (int k = 0; k < Data.Blocks[i].Transponders.Length; k++)
{
double b = 0.25 + 0.75 * Data.GetBrightness(Data.Blocks[i].Transponders[k].TrackPosition);
Data.Blocks[i].Transponders[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, b, Data.Structure.Beacon);
if (StartingDistance >= StartTrackPosition)
{
double b = 0.25 + 0.75 * Data.GetBrightness(Data.Blocks[i].Transponders[k].TrackPosition);
Data.Blocks[i].Transponders[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, b, Data.Structure.Beacon);
}
}

for (int k = 0; k < Data.Blocks[i].DestinationChanges.Length; k++)
{
Data.Blocks[i].DestinationChanges[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, Data.Structure.Beacon);
if (StartingDistance >= StartTrackPosition)
{
Data.Blocks[i].DestinationChanges[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, Data.Structure.Beacon);
}
}

for (int k = 0; k < Data.Blocks[i].HornBlows.Length; k++)
{
Data.Blocks[i].HornBlows[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, Data.Structure.Beacon);
if (StartingDistance >= StartTrackPosition)
{
Data.Blocks[i].HornBlows[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, Data.Structure.Beacon);
}
}
}

Expand All @@ -931,7 +973,10 @@ private void ApplyRouteData(string FileName, ref RouteData Data, bool PreviewOnl
// signals
for (int k = 0; k < Data.Blocks[i].Signals.Length; k++)
{
Data.Blocks[i].Signals[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, 0.27 + 0.75 * Data.GetBrightness(Data.Blocks[i].Signals[k].TrackPosition));
if (StartingDistance >= StartTrackPosition)
{
Data.Blocks[i].Signals[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, 0.27 + 0.75 * Data.GetBrightness(Data.Blocks[i].Signals[k].TrackPosition));
}
}

// sections
Expand All @@ -957,8 +1002,11 @@ private void ApplyRouteData(string FileName, ref RouteData Data, bool PreviewOnl
{
if (railKey == Data.Blocks[i].Limits[k].RailIndex)
{
double b = 0.25 + 0.75 * Data.GetBrightness(Data.Blocks[i].Limits[k].TrackPosition);
Data.Blocks[i].Limits[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, b, Data.UnitOfSpeed);
if (StartingDistance >= StartTrackPosition)
{
double b = 0.25 + 0.75 * Data.GetBrightness(Data.Blocks[i].Limits[k].TrackPosition);
Data.Blocks[i].Limits[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, b, Data.UnitOfSpeed);
}
}
}

Expand All @@ -967,8 +1015,11 @@ private void ApplyRouteData(string FileName, ref RouteData Data, bool PreviewOnl
{
for (int k = 0; k < Data.Blocks[i].StopPositions.Length; k++)
{
double b = 0.25 + 0.75 * Data.GetBrightness(Data.Blocks[i].StopPositions[k].TrackPosition);
Data.Blocks[i].StopPositions[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, b);
if (StartingDistance >= StartTrackPosition)
{
double b = 0.25 + 0.75 * Data.GetBrightness(Data.Blocks[i].StopPositions[k].TrackPosition);
Data.Blocks[i].StopPositions[k].Create(new Vector3(pos), RailTransformation, StartingDistance, EndingDistance, b);
}
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions source/Plugins/Route.CsvRw/CsvRwRouteParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ internal partial class Parser {
internal readonly bool IsRW;
internal readonly Plugin Plugin;
internal bool IsHmmsim;
internal double StartTrackPosition = 0;

internal Parser(Plugin plugin, bool isRW)
{
Expand Down Expand Up @@ -486,7 +487,19 @@ private void ParseRouteForData(string FileName, System.Text.Encoding Encoding, E
case "track":
if (Enum.TryParse(Command, true, out TrackCommand parsedCommand))
{
// speed up reloads by skipping objects before the edit point (we already have them in the renderer)
// however we still need to parse geometry/signaling stuff to keep the state correct
if (Data.TrackPosition < StartTrackPosition)
{
switch (parsedCommand)
{
case TrackCommand.FreeObj:
case TrackCommand.SigF:
goto skipCommand;
}
}
ParseTrackCommand(parsedCommand, Arguments, FileName, UnitOfLength, Expressions[j], ref Data, BlockIndex, PreviewOnly, IsRW);
skipCommand:;
}
else
{
Expand Down
1 change: 1 addition & 0 deletions source/Plugins/Route.CsvRw/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ public override bool LoadRoute(string path, Encoding textEncoding, string trainP
try
{
Parser parser = new Parser(this, isRw);
parser.StartTrackPosition = StartTrackPosition;
parser.ParseRoute(path, textEncoding, trainPath, objectPath, soundPath, PreviewOnly);
IsLoading = false;
return true;
Expand Down
Loading