public MSTSWagonViewer(Viewer viewer, MSTSWagon car) : base(viewer, car) { string steamTexture = viewer.Simulator.BasePath + @"\GLOBAL\TEXTURES\smokemain.ace"; string dieselTexture = viewer.Simulator.BasePath + @"\GLOBAL\TEXTURES\dieselsmoke.ace"; // Particle Drawers called in Wagon so that wagons can also have steam effects. ParticleDrawers = ( from effect in MSTSWagon.EffectData select new KeyValuePair <string, List <ParticleEmitterViewer> >(effect.Key, new List <ParticleEmitterViewer>( from data in effect.Value select new ParticleEmitterViewer(viewer, data, car.WorldPosition)))).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); // Initaialise particle viewers for special steam effects foreach (var emitter in ParticleDrawers) { // Exhaust for steam heating boiler if (emitter.Key.ToLowerInvariant() == "heatingsteamboilerfx") { HeatingSteamBoiler.AddRange(emitter.Value); } foreach (var drawer in HeatingSteamBoiler) { drawer.Initialize(dieselTexture); } // Exhaust for HEP/Power Generator if (emitter.Key.ToLowerInvariant() == "wagongeneratorfx") { WagonGenerator.AddRange(emitter.Value); } foreach (var drawer in WagonGenerator) { drawer.Initialize(dieselTexture); } // Smoke for wood/coal fire if (emitter.Key.ToLowerInvariant() == "wagonsmokefx") { WagonSmoke.AddRange(emitter.Value); } foreach (var drawer in WagonSmoke) { drawer.Initialize(steamTexture); } // Steam leak in heating hose if (emitter.Key.ToLowerInvariant() == "heatinghosefx") { HeatingHose.AddRange(emitter.Value); } foreach (var drawer in HeatingHose) { drawer.Initialize(steamTexture); } } var wagonFolderSlash = Path.GetDirectoryName(car.WagFilePath) + @"\"; TrainCarShape = car.MainShapeFileName != string.Empty ? new PoseableShape(viewer, wagonFolderSlash + car.MainShapeFileName + '\0' + wagonFolderSlash, car.WorldPosition, ShapeFlags.ShadowCaster) : new PoseableShape(viewer, null, car.WorldPosition); // This insection initialises the MSTS style freight animation - can either be for a coal load, which will adjust with usage, or a static animation, such as additional shape. if (car.FreightShapeFileName != null) { car.HasFreightAnim = true; FreightShape = new AnimatedShape(viewer, wagonFolderSlash + car.FreightShapeFileName + '\0' + wagonFolderSlash, new WorldPosition(car.WorldPosition), ShapeFlags.ShadowCaster); // Reproducing MSTS "bug" of not allowing tender animation in case both minLevel and maxLevel are 0 or maxLevel < minLevel // Applies to both a standard tender locomotive or a tank locomotive (where coal load is on same "wagon" as the locomotive - for the coal load on a tender or tank locomotive - in operation it will raise or lower with caol usage if (MSTSWagon.WagonType == TrainCar.WagonTypes.Tender || MSTSWagon is MSTSSteamLocomotive) { var NonTenderSteamLocomotive = MSTSWagon as MSTSSteamLocomotive; if ((MSTSWagon.WagonType == TrainCar.WagonTypes.Tender || MSTSWagon is MSTSLocomotive && (MSTSWagon.EngineType == TrainCar.EngineTypes.Steam && NonTenderSteamLocomotive.IsTenderRequired == 0.0)) && MSTSWagon.FreightAnimMaxLevelM != 0 && MSTSWagon.FreightAnimFlag > 0 && MSTSWagon.FreightAnimMaxLevelM > MSTSWagon.FreightAnimMinLevelM) { // Force allowing animation: if (FreightShape.SharedShape.LodControls.Length > 0 && FreightShape.SharedShape.LodControls[0].DistanceLevels.Length > 0 && FreightShape.SharedShape.LodControls[0].DistanceLevels[0].SubObjects.Length > 0 && FreightShape.SharedShape.LodControls[0].DistanceLevels[0].SubObjects[0].ShapePrimitives.Length > 0 && FreightShape.SharedShape.LodControls[0].DistanceLevels[0].SubObjects[0].ShapePrimitives[0].Hierarchy.Length > 0) { FreightShape.SharedShape.LodControls[0].DistanceLevels[0].SubObjects[0].ShapePrimitives[0].Hierarchy[0] = 1; } } } } if (car.InteriorShapeFileName != null) { InteriorShape = new AnimatedShape(viewer, wagonFolderSlash + car.InteriorShapeFileName + '\0' + wagonFolderSlash, car.WorldPosition, ShapeFlags.Interior, 30.0f); } RunningGear = new AnimatedPart(TrainCarShape); Pantograph1 = new AnimatedPart(TrainCarShape); Pantograph2 = new AnimatedPart(TrainCarShape); Pantograph3 = new AnimatedPart(TrainCarShape); Pantograph4 = new AnimatedPart(TrainCarShape); LeftDoor = new AnimatedPart(TrainCarShape); RightDoor = new AnimatedPart(TrainCarShape); Mirrors = new AnimatedPart(TrainCarShape); Wipers = new AnimatedPart(TrainCarShape); UnloadingParts = new AnimatedPart(TrainCarShape); Bell = new AnimatedPart(TrainCarShape); if (car.FreightAnimations != null) { FreightAnimations = new FreightAnimationsViewer(viewer, car, wagonFolderSlash); } LoadCarSounds(wagonFolderSlash); //if (!(MSTSWagon is MSTSLocomotive)) // LoadTrackSounds(); 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++) { 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++) { if (TrainCarShape.SharedShape.MatrixNames[i].Equals("BOGIE1")) { bogieMatrix1 = i; numBogie1 += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("BOGIE2")) { bogieMatrix2 = i; numBogie2 += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("BOGIE")) { bogieMatrix1 = i; } // For now, the total axle count consisting of axles that are part of the bogie are being counted. if (TrainCarShape.SharedShape.MatrixNames[i].Contains("WHEELS")) { if (TrainCarShape.SharedShape.MatrixNames[i].Length == 8) { var tpmatrix = TrainCarShape.SharedShape.GetParentMatrix(i); if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS11") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS12") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS13") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS21") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS22") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS23") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS11") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS12") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS13") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS21") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS21") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS23") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } } } } // 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); } } car.SetUpWheels(); // If we have two pantographs, 2 is the forwards pantograph, unlike when there's only one. if (!car.Flipped && !Pantograph1.Empty() && !Pantograph2.Empty()) { AnimatedPart.Swap(ref Pantograph1, ref Pantograph2); } Pantograph1.SetState(MSTSWagon.Pantographs[1].CommandUp); Pantograph2.SetState(MSTSWagon.Pantographs[2].CommandUp); if (MSTSWagon.Pantographs.List.Count > 2) { Pantograph3.SetState(MSTSWagon.Pantographs[3].CommandUp); } if (MSTSWagon.Pantographs.List.Count > 3) { Pantograph4.SetState(MSTSWagon.Pantographs[4].CommandUp); } LeftDoor.SetState(MSTSWagon.DoorLeftOpen); RightDoor.SetState(MSTSWagon.DoorRightOpen); Mirrors.SetState(MSTSWagon.MirrorOpen); UnloadingParts.SetState(MSTSWagon.UnloadingPartsOpen); InitializeUserInputCommands(); }
public MSTSWagonViewer(Viewer viewer, MSTSWagon car) : base(viewer, car) { var wagonFolderSlash = Path.GetDirectoryName(car.WagFilePath) + @"\"; TrainCarShape = car.MainShapeFileName != string.Empty ? new PoseableShape(viewer, wagonFolderSlash + car.MainShapeFileName + '\0' + wagonFolderSlash, car.WorldPosition, ShapeFlags.ShadowCaster) : new PoseableShape(viewer, null, car.WorldPosition); if (car.FreightShapeFileName != null) { car.HasFreightAnim = true; FreightShape = new AnimatedShape(viewer, wagonFolderSlash + car.FreightShapeFileName + '\0' + wagonFolderSlash, new WorldPosition(car.WorldPosition), ShapeFlags.ShadowCaster); // Reproducing MSTS "bug" of not allowing tender animation in case both minLevel and maxLevel are 0 or maxLevel < minLevel if (MSTSWagon.WagonType == TrainCar.WagonTypes.Tender && MSTSWagon.FreightAnimMaxLevelM != 0 && MSTSWagon.FreightAnimFlag > 0 && MSTSWagon.FreightAnimMaxLevelM > MSTSWagon.FreightAnimMinLevelM) { // Force allowing animation: if (FreightShape.SharedShape.LodControls.Length > 0 && FreightShape.SharedShape.LodControls[0].DistanceLevels.Length > 0 && FreightShape.SharedShape.LodControls[0].DistanceLevels[0].SubObjects.Length > 0 && FreightShape.SharedShape.LodControls[0].DistanceLevels[0].SubObjects[0].ShapePrimitives.Length > 0 && FreightShape.SharedShape.LodControls[0].DistanceLevels[0].SubObjects[0].ShapePrimitives[0].Hierarchy.Length > 0) { FreightShape.SharedShape.LodControls[0].DistanceLevels[0].SubObjects[0].ShapePrimitives[0].Hierarchy[0] = 1; } } } if (car.InteriorShapeFileName != null) { InteriorShape = new AnimatedShape(viewer, wagonFolderSlash + car.InteriorShapeFileName + '\0' + wagonFolderSlash, car.WorldPosition, ShapeFlags.Interior, 30.0f); } RunningGear = new AnimatedPart(TrainCarShape); Pantograph1 = new AnimatedPart(TrainCarShape); Pantograph2 = new AnimatedPart(TrainCarShape); LeftDoor = new AnimatedPart(TrainCarShape); RightDoor = new AnimatedPart(TrainCarShape); Mirrors = new AnimatedPart(TrainCarShape); Wipers = new AnimatedPart(TrainCarShape); UnloadingParts = new AnimatedPart(TrainCarShape); if (car.FreightAnimations != null) { FreightAnimations = new FreightAnimationsViewer(viewer, car, wagonFolderSlash); } LoadCarSounds(wagonFolderSlash); //if (!(MSTSWagon is MSTSLocomotive)) // LoadTrackSounds(); 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++) { 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++) { if (TrainCarShape.SharedShape.MatrixNames[i].Equals("BOGIE1")) { bogieMatrix1 = i; numBogie1 += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("BOGIE2")) { bogieMatrix2 = i; numBogie2 += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("BOGIE")) { bogieMatrix1 = i; numBogie += 1; } // For now, the total axle count consisting of axles that are part of the bogie are being counted. if (TrainCarShape.SharedShape.MatrixNames[i].Contains("WHEELS")) { if (TrainCarShape.SharedShape.MatrixNames[i].Length == 8) { var tpmatrix = TrainCarShape.SharedShape.GetParentMatrix(i); if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS11") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS12") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS13") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS21") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS22") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS23") && tpmatrix == bogieMatrix1) { bogie1Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS11") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS12") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS13") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS21") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS21") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } if (TrainCarShape.SharedShape.MatrixNames[i].Equals("WHEELS23") && tpmatrix == bogieMatrix2) { bogie2Axles += 1; } } } } // 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); } } car.SetUpWheels(); // If we have two pantographs, 2 is the forwards pantograph, unlike when there's only one. if (!car.Flipped && !Pantograph1.Empty() && !Pantograph2.Empty()) { AnimatedPart.Swap(ref Pantograph1, ref Pantograph2); } Pantograph1.SetState(MSTSWagon.Pantographs[1].CommandUp); Pantograph2.SetState(MSTSWagon.Pantographs[2].CommandUp); LeftDoor.SetState(MSTSWagon.DoorLeftOpen); RightDoor.SetState(MSTSWagon.DoorRightOpen); Mirrors.SetState(MSTSWagon.MirrorOpen); UnloadingParts.SetState(MSTSWagon.UnloadingPartsOpen); InitializeUserInputCommands(); }
/// <summary> /// Construct with a link to the shape that contains the animated parts /// </summary> public AnimatedPart(PoseableShape poseableShape) { PoseableShape = poseableShape; }
public ThreeDimCabDPI(Viewer viewer, int iMatrix, string size, string aceFile, PoseableShape trainCarShape, CabViewControlRenderer c) // : base(viewer, iMatrix, size, aceFile, trainCarShape, c) { Size = int.Parse(size) * 0.001f;//input size is in mm if (aceFile != "") { AceFile = aceFile.ToUpper(); if (!AceFile.EndsWith(".ACE")) { AceFile = AceFile + ".ACE"; //need to add ace into it } } else { AceFile = ""; } CVFR = (DistributedPowerInterfaceRenderer)c; DPITable = CVFR.DPI.DPDefaultWindow.DPITable; DPIStatus = CVFR.DPI.DPIStatus; Viewer = viewer; TrainCarShape = trainCarShape; XNAMatrix = TrainCarShape.SharedShape.Matrices[iMatrix]; // 9 rows, 5 columns plus first one; first one has a couple of triangles for the whole string, // the other ones have a couple of triangles for each char, and there are max 7 chars per string; // this leads to 1944 vertices var maxVertex = 2048; //Material = viewer.MaterialManager.Load("Scenery", Helpers.GetRouteTextureFile(viewer.Simulator, Helpers.TextureFlags.None, texture), (int)(SceneryMaterialOptions.None | SceneryMaterialOptions.AlphaBlendingBlend), 0); Material = FindMaterial(false); //determine normal material // Create and populate a new ShapePrimitive NumVertices = NumIndices = 0; VertexList = new VertexPositionNormalTexture[maxVertex]; TriangleListIndices = new short[maxVertex / 2 * 3]; // as is NumIndices //start position is the center of the text var start = new Vector3(0, 0, 0); var rotation = 0; //find the left-most of text Vector3 offset; offset.X = 0; offset.Y = -Size; var param = new string(' ', MaxDigits); var color = ColorYellow; var headerIndex = 0; float tX, tY; Matrix rot; for (int iRow = 0; iRow < DPITable.NumberOfRowsFull; iRow++) { // fill with blanks at startup tX = 0.875f; tY = 0.125f; //the left-bottom vertex Vector3 v = new Vector3(offset.X, offset.Y, 0.01f); v += start; Vertex v1 = new Vertex(v.X, v.Y, v.Z, 0, 0, -1, tX, tY); //the right-bottom vertex v.X = offset.X + Size * 7 * 0.5f; v.Y = offset.Y; v += start; Vertex v2 = new Vertex(v.X, v.Y, v.Z, 0, 0, -1, tX + 0.125f, tY); //the right-top vertex v.X = offset.X + Size * 7 * 0.5f; v.Y = offset.Y + Size; v += start; Vertex v3 = new Vertex(v.X, v.Y, v.Z, 0, 0, -1, tX + 0.125f, tY - 0.0625f); //the left-top vertex v.X = offset.X; v.Y = offset.Y + Size; v += start; Vertex v4 = new Vertex(v.X, v.Y, v.Z, 0, 0, -1, tX, tY - 0.0625f); //create first triangle TriangleListIndices[NumIndices++] = (short)NumVertices; TriangleListIndices[NumIndices++] = (short)(NumVertices + 2); TriangleListIndices[NumIndices++] = (short)(NumVertices + 1); // Second triangle: TriangleListIndices[NumIndices++] = (short)NumVertices; TriangleListIndices[NumIndices++] = (short)(NumVertices + 3); TriangleListIndices[NumIndices++] = (short)(NumVertices + 2); //create vertex VertexList[NumVertices].Position = v1.Position; VertexList[NumVertices].Normal = v1.Normal; VertexList[NumVertices].TextureCoordinate = v1.TexCoord; VertexList[NumVertices + 1].Position = v2.Position; VertexList[NumVertices + 1].Normal = v2.Normal; VertexList[NumVertices + 1].TextureCoordinate = v2.TexCoord; VertexList[NumVertices + 2].Position = v3.Position; VertexList[NumVertices + 2].Normal = v3.Normal; VertexList[NumVertices + 2].TextureCoordinate = v3.TexCoord; VertexList[NumVertices + 3].Position = v4.Position; VertexList[NumVertices + 3].Normal = v4.Normal; VertexList[NumVertices + 3].TextureCoordinate = v4.TexCoord; NumVertices += 4; headerIndex++; offset.X = 0; for (int iCol = 1; iCol < NumColumns; iCol++) { for (int iChar = 0; iChar < param.Length; iChar++) { tX = GetTextureCoordX(param, iChar); tY = GetTextureCoordY(param, iChar, color); var offX = offset.X + Size * (1 + HeaderMaxDigits + (MaxDigits) * (iCol - 1)) * 0.5f; //the left-bottom vertex Vector3 va = new Vector3(offX, offset.Y, 0.01f); va += start; Vertex v5 = new Vertex(va.X, va.Y, va.Z, 0, 0, -1, tX, tY); //the right-bottom vertex va.X = offX + Size * 0.5f; va.Y = offset.Y; va += start; Vertex v6 = new Vertex(va.X, va.Y, va.Z, 0, 0, -1, tX + 0.125f, tY); //the right-top vertex va.X = offX + Size * 0.5f; va.Y = offset.Y + Size; va += start; Vertex v7 = new Vertex(va.X, va.Y, va.Z, 0, 0, -1, tX + 0.125f, tY - 0.0625f); //the left-top vertex va.X = offX; va.Y = offset.Y + Size; va += start; Vertex v8 = new Vertex(va.X, va.Y, va.Z, 0, 0, -1, tX, tY - 0.0625f); //create first triangle TriangleListIndices[NumIndices++] = (short)NumVertices; TriangleListIndices[NumIndices++] = (short)(NumVertices + 2); TriangleListIndices[NumIndices++] = (short)(NumVertices + 1); // Second triangle: TriangleListIndices[NumIndices++] = (short)NumVertices; TriangleListIndices[NumIndices++] = (short)(NumVertices + 3); TriangleListIndices[NumIndices++] = (short)(NumVertices + 2); //create vertex VertexList[NumVertices].Position = v5.Position; VertexList[NumVertices].Normal = v5.Normal; VertexList[NumVertices].TextureCoordinate = v5.TexCoord; VertexList[NumVertices + 1].Position = v6.Position; VertexList[NumVertices + 1].Normal = v6.Normal; VertexList[NumVertices + 1].TextureCoordinate = v6.TexCoord; VertexList[NumVertices + 2].Position = v7.Position; VertexList[NumVertices + 2].Normal = v7.Normal; VertexList[NumVertices + 2].TextureCoordinate = v7.TexCoord; VertexList[NumVertices + 3].Position = v8.Position; VertexList[NumVertices + 3].Normal = v8.Normal; VertexList[NumVertices + 3].TextureCoordinate = v8.TexCoord; NumVertices += 4; offset.X += Size * 0.5f; offset.Y += 0; //move to next digit } offset.X = 0; } offset.Y -= Size; //move to next digit } //create the shape primitive shapePrimitive = new MutableShapePrimitive(Material, NumVertices, NumIndices, new[] { -1 }, 0); UpdateShapePrimitive(Material); }