Skip to content

Commit

Permalink
Automatic merge of T1.5.1-263-gd19a96a3d and 8 pull requests
Browse files Browse the repository at this point in the history
- Pull request #570 at b2b4dea: Experimental glTF 2.0 support with PBR lighting
- Pull request #722 at fb9079e: Fix Windows Forms deprecations in ActivityEditor
- Pull request #732 at 83002d7: Improvements for air brakes
- Pull request #751 at f947f29: Web interface to control cab controls with external hardware
- Pull request #753 at ab8fe32: Extends CabControls for user input
- Pull request #766 at f1759de: Control Car additional functionality
- Pull request #767 at 4cb5c77: Refine sunrise and sunset
- Pull request #769 at 1a99f43: Partial turntables https://blueprints.launchpad.net/or/+spec/partial-turntable
  • Loading branch information
openrails-bot committed Jan 27, 2023
10 parents 501a320 + d19a96a + b2b4dea + fb9079e + 83002d7 + f947f29 + ab8fe32 + f1759de + 4cb5c77 + 1a99f43 commit 52271dd
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 86 deletions.
18 changes: 10 additions & 8 deletions Source/RunActivity/Viewer3D/GltfShape.cs
Expand Up @@ -1668,25 +1668,27 @@ public class KHR_materials_clearcoat
/// <summary>
/// This method is part of the animation handling. Gets the parent that will be animated, for finding a bogie for wheels.
/// </summary>
public override int GetParentMatrix(int animationNumber)
public override int GetParentAnimation(int animationNumber)
{
var node = GltfAnimations.ElementAtOrDefault(animationNumber)?.Channels?.FirstOrDefault()?.TargetNode ?? 0;
var nodeAdnimation = -1;
var nodeAnimation = -1;
do
{
node = LodControls?.FirstOrDefault()?.DistanceLevels?.FirstOrDefault()?.SubObjects?.FirstOrDefault()?.ShapePrimitives?.FirstOrDefault()?.
Hierarchy?.ElementAtOrDefault(node) ?? -1;
nodeAdnimation = GltfAnimations.FindIndex(a => a.Channels?.FirstOrDefault()?.TargetNode == node);
nodeAnimation = GltfAnimations.FindIndex(a => a.Channels?.FirstOrDefault()?.TargetNode == node);
}
while (node > -1 && nodeAdnimation == -1);
return nodeAdnimation;
while (node > -1 && nodeAnimation == -1);
return nodeAnimation;
}

public override Matrix GetMatrixProduct(int iNode) => base.GetMatrixProduct(iNode) * PlusZToForward;
public override bool AnimationIsArticulation(int number) => GltfAnimations?.ElementAtOrDefault(number)?.Channels?.FirstOrDefault()?.TimeArray == null;
public override int GetArticulationTargetNode(int animationId) => GltfAnimations?.ElementAtOrDefault(animationId)?.Channels?.FirstOrDefault()?.TargetNode ?? 0;
public override int GetAnimationNamesCount() => GltfAnimations?.Count ?? 0;

public bool HasAnimation(int number) => GltfAnimations?.ElementAtOrDefault(number)?.Channels?.FirstOrDefault() != null;
public bool AnimationIsArticulation(int number) => GltfAnimations?.ElementAtOrDefault(number)?.Channels?.FirstOrDefault()?.TimeArray == null;
public float GetAnimationLength(int number) => GltfAnimations?.ElementAtOrDefault(number)?.Channels?.Select(c => c.TimeMax).Max() ?? 0;
public int GetAnimationCount() => GltfAnimations?.Count ?? 0;
public IEnumerable<int> GetArticulationTargetNodes(int number) => GltfAnimations?.ElementAtOrDefault(number)?.Channels?.Select(c => c.TargetNode);

/// <summary>
/// Calculate the animation matrices of a glTF animation.
Expand Down
107 changes: 36 additions & 71 deletions Source/RunActivity/Viewer3D/RollingStock/MSTSWagonViewer.cs
Expand Up @@ -338,14 +338,14 @@ public MSTSWagonViewer(Viewer viewer, MSTSWagon car)
Viewer.SoundProcess.AddSoundSource(this, new TrackSoundSource(MSTSWagon, Viewer));

// Determine if it has first pantograph. So we can match unnamed panto parts correctly
for (var i = 0; i < TrainCarShape.Hierarchy.Length; i++)
for (var i = 0; i < TrainCarShape.SharedShape.GetAnimationNamesCount(); i++)
if (TrainCarShape.SharedShape.MatrixNames[i].Contains('1'))
{
if (TrainCarShape.SharedShape.MatrixNames[i].ToUpper().StartsWith("PANTO")) { HasFirstPanto = true; break; }
}

// Check bogies and wheels to find out what we have.
for (var i = 0; i < TrainCarShape.Hierarchy.Length; i++)
for (var i = 0; i < TrainCarShape.SharedShape.GetAnimationNamesCount(); i++)
{
if (TrainCarShape.SharedShape.MatrixNames[i].Equals("BOGIE1"))
{
Expand All @@ -365,7 +365,7 @@ public MSTSWagonViewer(Viewer viewer, MSTSWagon car)
if (TrainCarShape.SharedShape.MatrixNames[i].Contains("WHEELS"))
if (TrainCarShape.SharedShape.MatrixNames[i].Length == 8)
{
var tpmatrix = TrainCarShape.SharedShape.GetParentMatrix(i);
var tpmatrix = TrainCarShape.SharedShape.GetParentAnimation(i);
if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS11") && tpmatrix == bogieMatrix1)
bogie1Axles += 1;
if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS12") && tpmatrix == bogieMatrix1)
Expand Down Expand Up @@ -395,19 +395,10 @@ public MSTSWagonViewer(Viewer viewer, MSTSWagon car)
}

// Using only animations not parented by other animations, thus wheels part of a bogie will be enumerated in another round.
if (TrainCarShape.SharedShape is GltfShape gltfShape)
{
for (var i = 0; i < gltfShape.GetAnimationCount(); i++)
if (gltfShape.GetParentMatrix(i) == -1)
MatchMatrixToPart(car, i, 0);
}
else
{
// Match up all the matrices with their parts.
for (var i = 0; i < TrainCarShape.Hierarchy.Length; i++)
if (TrainCarShape.Hierarchy[i] == -1)
MatchMatrixToPart(car, i, 0);
}
// Match up all the matrices with their parts.
for (var i = 0; i < TrainCarShape.SharedShape.GetAnimationNamesCount(); i++)
if (TrainCarShape.SharedShape.GetParentAnimation(i) == -1)
MatchMatrixToPart(car, i, 0);

car.SetUpWheels();

Expand All @@ -429,74 +420,57 @@ public MSTSWagonViewer(Viewer viewer, MSTSWagon car)
InitializeUserInputCommands();
}

/// <summary>
/// This is part of the animation handling. Enlisting the various animations and structuring them into their specific class.
/// </summary>
/// <param name="car">The car to process.</param>
/// <param name="matrix">For stf files it is the target node id, for gltf shapes it is the animation id.</param>
/// <param name="bogieMatrix">The node id of the containing bogie. 0 if there is no bogie above.</param>
void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
{
var matrixName = TrainCarShape.SharedShape.MatrixNames[matrix].ToUpper();
var targetNode = TrainCarShape.SharedShape.GetArticulationTargetNode(matrix);
// Gate all RunningGearPartIndexes on this!
var matrixAnimated = TrainCarShape.SharedShape.Animations != null && TrainCarShape.SharedShape.Animations.Count > 0 && TrainCarShape.SharedShape.Animations[0].anim_nodes.Count > matrix && TrainCarShape.SharedShape.Animations[0].anim_nodes[matrix].controllers.Count > 0;
matrixAnimated |= (TrainCarShape.SharedShape as GltfShape)?.AnimationIsArticulation(matrix) == false;
var matrixAnimated = !TrainCarShape.SharedShape.AnimationIsArticulation(matrix);
if (matrixName.StartsWith("WHEELS") && (matrixName.Length == 7 || matrixName.Length == 8 || matrixName.Length == 9))
{
// Standard WHEELS length would be 8 to test for WHEELS11. Came across WHEELS tag that used a period(.) between the last 2 numbers, changing max length to 9.
// Changing max length to 9 is not a problem since the initial WHEELS test will still be good.
var m = TrainCarShape.SharedShape.GetMatrixProduct(matrix);
var m = TrainCarShape.SharedShape.GetMatrixProduct(targetNode);
//someone uses wheel to animate fans, thus check if the wheel is not too high (lower than 3m), will animate it as real wheel
if (m.M42 < 3)
{
var id = 0;
// Model makers are not following the standard rules, For example, one tender uses naming convention of wheels11/12 instead of using Wheels1,2,3 when not part of a bogie.
// The next 2 lines will sort out these axles.
var tmatrix = TrainCarShape.SharedShape.GetParentMatrix(matrix);
var tmatrix = TrainCarShape.SharedShape.GetParentMatrix(targetNode);
if (matrixName.Length == 8 && bogieMatrix == 0 && tmatrix == 0) // In this test, both tmatrix and bogieMatrix are 0 since these wheels are not part of a bogie.
matrixName = TrainCarShape.SharedShape.MatrixNames[matrix].Substring(0, 7); // Changing wheel name so that it reflects its actual use since it is not p
if (matrixName.Length == 8 || matrixName.Length == 9)
Int32.TryParse(matrixName.Substring(6, 1), out id);
matrixName = matrixName.Substring(0, 7); // Changing wheel name so that it reflects its actual use since it is not p
if (matrixName.Length == 8 || matrixName.Length == 9 || !matrixAnimated)
WheelPartIndexes.Add((TrainCarShape.SharedShape as GltfShape)?.GetArticulationTargetNodes(matrix)?.FirstOrDefault() ?? matrix);
WheelPartIndexes.Add(targetNode);
else
RunningGear.AddMatrix(matrix);
if (!(TrainCarShape.SharedShape is GltfShape))
{
var pmatrix = TrainCarShape.SharedShape.GetParentMatrix(matrix);
car.AddWheelSet(m.M43, id, pmatrix, matrixName.ToString(), bogie1Axles, bogie2Axles);
}
RunningGear.AddMatrix(matrix); // TODO: test this in the gltf case
var id = 0;
if (matrixName.Length == 8 || matrixName.Length == 9)
Int32.TryParse(matrixName.Substring(6, 1), out id);
var pmatrix = TrainCarShape.SharedShape.GetArticulationTargetNode(TrainCarShape.SharedShape.GetParentAnimation(matrix));
car.AddWheelSet(m.M43, id, pmatrix, matrixName.ToString(), bogie1Axles, bogie2Axles);
}
// Standard wheels are processed above, but wheels used as animated fans that are greater than 3m are processed here.
else
RunningGear.AddMatrix(matrix);
RunningGear.AddMatrix(matrixAnimated ? matrix : targetNode);
}
else if (matrixName.StartsWith("BOGIE") && matrixName.Length <= 6) //BOGIE1 is valid, BOGIE11 is not, it is used by some modelers to indicate this is part of bogie1
{
var id = 1;
if (matrixName.Length == 6)
{
var id = 1;
Int32.TryParse(matrixName.Substring(5), out id);
var m = TrainCarShape.SharedShape.GetMatrixProduct(matrix);
car.AddBogie(m.M43, matrix, id, matrixName.ToString(), numBogie1, numBogie2);
bogieMatrix = matrix; // Bogie matrix needs to be saved for test with axles.
}
else
{
// Since the string content is BOGIE, Int32.TryParse(matrixName.Substring(5), out id) is not needed since its sole purpose is to
// parse the string number from the string.
var id = 1;
var m = TrainCarShape.SharedShape.GetMatrixProduct(matrix);
car.AddBogie(m.M43, matrix, id, matrixName.ToString(), numBogie1, numBogie2);
bogieMatrix = matrix; // Bogie matrix needs to be saved for test with axles.
}
var m = TrainCarShape.SharedShape.GetMatrixProduct(targetNode);
car.AddBogie(m.M43, targetNode, id, matrixName.ToString(), numBogie1, numBogie2);
bogieMatrix = targetNode; // Bogie matrix needs to be saved for test with axles.
// Bogies contain wheels!
if (TrainCarShape.SharedShape is GltfShape gltfShape)
{
for (var i = 0; i < gltfShape.GetAnimationCount(); i++)
if (gltfShape.GetParentMatrix(i) == matrix)
MatchMatrixToPart(car, i, bogieMatrix);
}
else
{
for (var i = 0; i < TrainCarShape.Hierarchy.Length; i++)
if (TrainCarShape.Hierarchy[i] == matrix)
MatchMatrixToPart(car, i, bogieMatrix);
}
for (var i = 0; i < TrainCarShape.SharedShape.GetAnimationNamesCount(); i++)
if (TrainCarShape.SharedShape.GetParentAnimation(i) == matrix)
MatchMatrixToPart(car, i, bogieMatrix);
}
else if (matrixName.StartsWith("WIPER")) // wipers
{
Expand Down Expand Up @@ -603,18 +577,9 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
if (matrixAnimated && matrix != 0)
RunningGear.AddMatrix(matrix);

if (TrainCarShape.SharedShape is GltfShape gltfShape)
{
for (var i = 0; i < gltfShape.GetAnimationCount(); i++)
if (gltfShape.GetParentMatrix(i) == matrix)
MatchMatrixToPart(car, i, 0);
}
else
{
for (var i = 0; i < TrainCarShape.Hierarchy.Length; i++)
if (TrainCarShape.Hierarchy[i] == matrix)
MatchMatrixToPart(car, i, 0);
}
for (var i = 0; i < TrainCarShape.SharedShape.GetAnimationNamesCount(); i++)
if (TrainCarShape.SharedShape.GetParentAnimation(i) == targetNode)
MatchMatrixToPart(car, i, 0);
}
}

Expand Down
40 changes: 33 additions & 7 deletions Source/RunActivity/Viewer3D/Shapes.cs
Expand Up @@ -2649,26 +2649,52 @@ public virtual Matrix SetRenderMatrices(ShapePrimitive shapePrimitive, Matrix[]
return xnaMatrix;
}

public Matrix GetMatrixProduct(int iNode)
public virtual Matrix GetMatrixProduct(int iNode)
{
int[] h = LodControls[0].DistanceLevels[0].SubObjects[0].ShapePrimitives[0].Hierarchy;
var h = LodControls?.FirstOrDefault()?.DistanceLevels?.FirstOrDefault()?.SubObjects?.FirstOrDefault()?.ShapePrimitives?.FirstOrDefault()?.Hierarchy;
Matrix matrix = Matrix.Identity;
while (iNode != -1)
if (h != null && h.Length > iNode)
{
matrix *= Matrices[iNode];
iNode = h[iNode];
while (iNode != -1)
{
matrix *= Matrices[iNode];
iNode = h[iNode];
}
}
return matrix;
}

/// <summary>
/// This method is part of the animation handling. Gets the parent that will be animated, for finding a bogie for wheels.
/// </summary>
public virtual int GetParentMatrix(int iNode)
public int GetParentMatrix(int iNode)
{
return LodControls[0].DistanceLevels[0].SubObjects[0].ShapePrimitives[0].Hierarchy[iNode];
return LodControls?.FirstOrDefault()?.DistanceLevels?.FirstOrDefault()?.SubObjects?.FirstOrDefault()?.ShapePrimitives?.FirstOrDefault()?.Hierarchy?.ElementAtOrDefault(iNode) ?? -1;
}

/// <summary>
/// Searches for the parent animation.
/// </summary>
/// <param name="animationId">For stf files it is the node id, for gltf files it is the animation id.</param>
/// <returns>The parent animation id.</returns>
public virtual int GetParentAnimation(int animationId) => GetParentMatrix(animationId);

/// <summary>
/// Tells whether the animation is an internal sequence defined within the shape, or is just a tag that needs external animation.
/// </summary>
/// <param name="animationId">For stf files it is the node id, for gltf files it is the animation id.</param>
/// <returns>true if there is no internal seqence defined in the shape.</returns>
public virtual bool AnimationIsArticulation(int animationId) => Animations?.FirstOrDefault()?.anim_nodes?.ElementAtOrDefault(animationId)?.controllers.Count > 0;

/// <summary>
/// Returns the parent animation id.
/// </summary>
/// <param name="animationId">For stf files it is the node id, for gltf files it is the animation id.</param>
/// <returns>Returns for stf files the node id itself, for gltf files the target node id of the animation.</returns>
public virtual int GetArticulationTargetNode(int animationId) => animationId;

public virtual int GetAnimationNamesCount() => LodControls?.FirstOrDefault()?.DistanceLevels?.FirstOrDefault()?.SubObjects?.FirstOrDefault().ShapePrimitives?.FirstOrDefault()?.Hierarchy?.Length ?? 0;

[CallOnThread("Loader")]
internal void Mark()
{
Expand Down

0 comments on commit 52271dd

Please sign in to comment.