/// <summary> /// Only one copy of the model is loaded regardless of how many copies are placed in the scene. /// </summary> void LoadContent() { Trace.Write("S"); var filePath = FilePath; // commented lines allow reading the animation block from an additional file in an Openrails subfolder // string dir = Path.GetDirectoryName(filePath); // string file = Path.GetFileName(filePath); // string orFilePath = dir + @"\openrails\" + file; var sFile = new ShapeFile(filePath, viewer.Settings.SuppressShapeWarnings); // if (file.ToLower().Contains("turntable") && File.Exists(orFilePath)) // { // sFile.ReadAnimationBlock(orFilePath); // } var textureFlags = Helpers.TextureFlags.None; if (File.Exists(FilePath + "d")) { var sdFile = new ShapeDescriptorFile(FilePath + "d"); textureFlags = (Helpers.TextureFlags)sdFile.Shape.EsdAlternativeTexture; if (FilePath != null && FilePath.Contains("\\global\\")) { textureFlags |= Helpers.TextureFlags.SnowTrack; //roads and tracks are in global, as MSTS will always use snow texture in snow weather } HasNightSubObj = sdFile.Shape.EsdSubObject; if ((textureFlags & Helpers.TextureFlags.Night) != 0 && FilePath.Contains("\\trainset\\")) { textureFlags |= Helpers.TextureFlags.Underground; } SoundFileName = sdFile.Shape.EsdSoundFileName; BellAnimationFPS = sdFile.Shape.EsdBellAnimationFps; } Matrices = sFile.Shape.Matrices.ToArray(); MatrixNames = sFile.Shape.Matrices.MatrixNames; //var matrixCount = sFile.shape.matrices.Count; //MatrixNames.Capacity = matrixCount; //Matrices = new Matrix[matrixCount]; //for (var i = 0; i < matrixCount; ++i) //{ // MatrixNames.Add(sFile.shape.matrices[i].Name.ToUpper()); // Matrices[i] = XNAMatrixFromMSTS(sFile.shape.matrices[i]); //} Animations = sFile.Shape.Animations; #if DEBUG_SHAPE_HIERARCHY var debugShapeHierarchy = new StringBuilder(); debugShapeHierarchy.AppendFormat("Shape {0}:\n", Path.GetFileNameWithoutExtension(FilePath).ToUpper()); for (var i = 0; i < MatrixNames.Count; ++i) { debugShapeHierarchy.AppendFormat(" Matrix {0,-2}: {1}\n", i, MatrixNames[i]); } for (var i = 0; i < sFile.shape.prim_states.Count; ++i) { debugShapeHierarchy.AppendFormat(" PState {0,-2}: flags={1,-8:X8} shader={2,-15} alpha={3,-2} vstate={4,-2} lstate={5,-2} zbias={6,-5:F3} zbuffer={7,-2} name={8}\n", i, sFile.shape.prim_states[i].flags, sFile.shape.shader_names[sFile.shape.prim_states[i].ishader], sFile.shape.prim_states[i].alphatestmode, sFile.shape.prim_states[i].ivtx_state, sFile.shape.prim_states[i].LightCfgIdx, sFile.shape.prim_states[i].ZBias, sFile.shape.prim_states[i].ZBufMode, sFile.shape.prim_states[i].Name); } for (var i = 0; i < sFile.shape.vtx_states.Count; ++i) { debugShapeHierarchy.AppendFormat(" VState {0,-2}: flags={1,-8:X8} lflags={2,-8:X8} lstate={3,-2} material={4,-3} matrix2={5,-2}\n", i, sFile.shape.vtx_states[i].flags, sFile.shape.vtx_states[i].LightFlags, sFile.shape.vtx_states[i].LightCfgIdx, sFile.shape.vtx_states[i].LightMatIdx, sFile.shape.vtx_states[i].Matrix2); } for (var i = 0; i < sFile.shape.light_model_cfgs.Count; ++i) { debugShapeHierarchy.AppendFormat(" LState {0,-2}: flags={1,-8:X8} uv_ops={2,-2}\n", i, sFile.shape.light_model_cfgs[i].flags, sFile.shape.light_model_cfgs[i].uv_ops.Count); for (var j = 0; j < sFile.shape.light_model_cfgs[i].uv_ops.Count; ++j) { debugShapeHierarchy.AppendFormat(" UV OP {0,-2}: texture_address_mode={1,-2}\n", j, sFile.shape.light_model_cfgs[i].uv_ops[j].TexAddrMode); } } Trace.Write(debugShapeHierarchy.ToString()); #endif LodControls = (from Formats.Msts.Models.LodControl lod in sFile.Shape.LodControls select new LodControl(lod, textureFlags, sFile, this)).ToArray(); if (LodControls.Length == 0) { throw new InvalidDataException("Shape file missing lod_control section"); } else if (LodControls[0].DistanceLevels.Length > 0 && LodControls[0].DistanceLevels[0].SubObjects.Length > 0) { // Zero the position offset of the root matrix for compatibility with MSTS if (LodControls[0].DistanceLevels[0].SubObjects[0].ShapePrimitives.Length > 0 && LodControls[0].DistanceLevels[0].SubObjects[0].ShapePrimitives[0].Hierarchy[0] == -1) { Matrices[0].M41 = 0; Matrices[0].M42 = 0; Matrices[0].M43 = 0; } // Look for root subobject, it is not necessarily the first (see ProTrain signal) for (int soIndex = 0; soIndex <= LodControls[0].DistanceLevels[0].SubObjects.Length - 1; soIndex++) { Formats.Msts.Models.SubObject subObject = sFile.Shape.LodControls[0].DistanceLevels[0].SubObjects[soIndex]; if (subObject.SubObjectHeader.GeometryInfo.GeometryNodeMap[0] == 0) { RootSubObjectIndex = soIndex; break; } } } }
public SubObject(Formats.Msts.Models.SubObject sub_object, ref int totalPrimitiveIndex, int[] hierarchy, Helpers.TextureFlags textureFlags, ShapeFile sFile, SharedShape sharedShape) #endif { #if DEBUG_SHAPE_HIERARCHY var debugShapeHierarchy = new StringBuilder(); debugShapeHierarchy.AppendFormat(" Sub object {0}:\n", subObjectIndex); #endif var vertexBufferSet = new VertexBufferSet(sub_object, sFile, viewer.RenderProcess.GraphicsDevice); #if DEBUG_SHAPE_NORMALS var debugNormalsMaterial = viewer.MaterialManager.Load("DebugNormals"); #endif #if OPTIMIZE_SHAPES_ON_LOAD var primitiveMaterials = sub_object.primitives.Cast <primitive>().Select((primitive) => #else var primitiveIndex = 0; #if DEBUG_SHAPE_NORMALS ShapePrimitives = new ShapePrimitive[sub_object.primitives.Count * 2]; #else ShapePrimitives = new ShapePrimitive[sub_object.Primitives.Count]; #endif foreach (Primitive primitive in sub_object.Primitives) #endif { var primitiveState = sFile.Shape.PrimaryStates[primitive.PrimitiveStateIndex]; var vertexState = sFile.Shape.VertexStates[primitiveState.VertexStateIndex]; var lightModelConfiguration = sFile.Shape.LightModelConfigs[vertexState.LightConfigIndex]; var options = SceneryMaterialOptions.None; // Validate hierarchy position. var hierarchyIndex = vertexState.MatrixIndex; while (hierarchyIndex != -1) { if (hierarchyIndex < 0 || hierarchyIndex >= hierarchy.Length) { var hierarchyList = new List <int>(); hierarchyIndex = vertexState.MatrixIndex; while (hierarchyIndex >= 0 && hierarchyIndex < hierarchy.Length) { hierarchyList.Add(hierarchyIndex); hierarchyIndex = hierarchy[hierarchyIndex]; } hierarchyList.Add(hierarchyIndex); Trace.TraceWarning("Ignored invalid primitive hierarchy {1} in shape {0}", sharedShape.FilePath, String.Join(" ", hierarchyList.Select(hi => hi.ToString()).ToArray())); break; } hierarchyIndex = hierarchy[hierarchyIndex]; } if (lightModelConfiguration.UVOperations.Count > 0) { if (lightModelConfiguration.UVOperations[0].TextureAddressMode - 1 >= 0 && lightModelConfiguration.UVOperations[0].TextureAddressMode - 1 < UVTextureAddressModeMap.Length) { options |= UVTextureAddressModeMap[lightModelConfiguration.UVOperations[0].TextureAddressMode - 1]; } else if (!shapeWarnings.Contains("texture_addressing_mode:" + lightModelConfiguration.UVOperations[0].TextureAddressMode)) { Trace.TraceInformation("Skipped unknown texture addressing mode {1} first seen in shape {0}", sharedShape.FilePath, lightModelConfiguration.UVOperations[0].TextureAddressMode); shapeWarnings.Add("texture_addressing_mode:" + lightModelConfiguration.UVOperations[0].TextureAddressMode); } } if (primitiveState.AlphaTestMode == 1) { options |= SceneryMaterialOptions.AlphaTest; } if (ShaderNames.ContainsKey(sFile.Shape.ShaderNames[primitiveState.ShaderIndex])) { options |= ShaderNames[sFile.Shape.ShaderNames[primitiveState.ShaderIndex]]; } else if (!shapeWarnings.Contains("shader_name:" + sFile.Shape.ShaderNames[primitiveState.ShaderIndex])) { Trace.TraceInformation("Skipped unknown shader name {1} first seen in shape {0}", sharedShape.FilePath, sFile.Shape.ShaderNames[primitiveState.ShaderIndex]); shapeWarnings.Add("shader_name:" + sFile.Shape.ShaderNames[primitiveState.ShaderIndex]); } if (12 + vertexState.LightMatrixIndex >= 0 && 12 + vertexState.LightMatrixIndex < VertexLightModeMap.Length) { options |= VertexLightModeMap[12 + vertexState.LightMatrixIndex]; } else if (!shapeWarnings.Contains("lighting_model:" + vertexState.LightMatrixIndex)) { Trace.TraceInformation("Skipped unknown lighting model index {1} first seen in shape {0}", sharedShape.FilePath, vertexState.LightMatrixIndex); shapeWarnings.Add("lighting_model:" + vertexState.LightMatrixIndex); } if ((textureFlags & Helpers.TextureFlags.Night) != 0) { options |= SceneryMaterialOptions.NightTexture; } if ((textureFlags & Helpers.TextureFlags.Underground) != 0) { options |= SceneryMaterialOptions.UndergroundTexture; } Material material; if (primitiveState.TextureIndices.Length != 0) { var texture = sFile.Shape.Textures[primitiveState.TextureIndices[0]]; var imageName = sFile.Shape.ImageNames[texture.ImageIndex]; if (String.IsNullOrEmpty(sharedShape.ReferencePath)) { material = viewer.MaterialManager.Load("Scenery", Helpers.GetRouteTextureFile(viewer.Simulator, textureFlags, imageName), (int)options, texture.MipMapLODBias); } else { material = viewer.MaterialManager.Load("Scenery", Helpers.GetTextureFile(viewer.Simulator, textureFlags, sharedShape.ReferencePath, imageName), (int)options, texture.MipMapLODBias); } } else { material = viewer.MaterialManager.Load("Scenery", null, (int)options); } #if DEBUG_SHAPE_HIERARCHY debugShapeHierarchy.AppendFormat(" Primitive {0,-2}: pstate={1,-2} vstate={2,-2} lstate={3,-2} matrix={4,-2}", primitiveIndex, primitive.prim_state_idx, primitiveState.ivtx_state, vertexState.LightCfgIdx, vertexState.imatrix); var debugMatrix = vertexState.imatrix; while (debugMatrix >= 0) { debugShapeHierarchy.AppendFormat(" {0}", sharedShape.MatrixNames[debugMatrix]); debugMatrix = hierarchy[debugMatrix]; } debugShapeHierarchy.Append("\n"); #endif #if OPTIMIZE_SHAPES_ON_LOAD return(new { Key = material.ToString() + "/" + vertexState.imatrix.ToString(), Primitive = primitive, Material = material, HierachyIndex = vertexState.imatrix }); }).ToArray();