예제 #1
0
        private void ValidateData(FileData data)
        {
            var decoder = new CsvB3dDecoder.Decoder();
            var manager = new MyTextureManager();
            var logger  = new MyErrorLogger();
            var options = new TrainsimApi.Codecs.MeshDecodingOptions(manager, logger);

                        #if !DEBUG
            try {
                                #endif
            Mesh mesh = decoder.Load(data.FullPath, options);
            Validator.CheckMeshFaces(mesh, logger);
            data.ErrorMessage = logger.Builder.ToString();
                                #if !DEBUG
        }

        catch (Exception ex) {
            data.ErrorMessage = "Unhandled exception:" + Environment.NewLine + ex.Message + Environment.NewLine + Environment.NewLine + "Please forward this error to the author of this program along with the file that caused the error.";
        }
                        #endif
            listviewFiles.Invoke(new ThreadStart(() => {
                if (listviewFiles.Items.Contains(data.Item))
                {
                    data.Item.SubItems[1].Text = logger.Count.ToString();
                    if (listviewFiles.SelectedItems.Count != 0 && listviewFiles.SelectedItems[0] == data.Item)
                    {
                        ListviewFilesSelectedIndexChanged(null, null);
                    }
                }
            }));
        }
예제 #2
0
		private void ValidateData(FileData data) {
			var decoder = new CsvB3dDecoder.Decoder();
			var manager = new MyTextureManager();
			var logger = new MyErrorLogger();
			var options = new TrainsimApi.Codecs.MeshDecodingOptions(manager, logger);
			#if !DEBUG
			try {
				#endif
				Mesh mesh = decoder.Load(data.FullPath, options);
				Validator.CheckMeshFaces(mesh, logger);
				data.ErrorMessage = logger.Builder.ToString();
				#if !DEBUG
			} catch (Exception ex) {
				data.ErrorMessage = "Unhandled exception:" + Environment.NewLine + ex.Message + Environment.NewLine + Environment.NewLine + "Please forward this error to the author of this program along with the file that caused the error.";
			}
			#endif
			listviewFiles.Invoke(new ThreadStart(() => {
			                                     	if (listviewFiles.Items.Contains(data.Item)) {
			                                     		data.Item.SubItems[1].Text = logger.Count.ToString();
			                                     		if (listviewFiles.SelectedItems.Count != 0 && listviewFiles.SelectedItems[0] == data.Item) {
			                                     			ListviewFilesSelectedIndexChanged(null, null);
			                                     		}
			                                     	}
			                                     }));
		}
예제 #3
0
		public abstract Mesh Load(string file, MeshDecodingOptions options);
예제 #4
0
 public abstract Mesh Load(string file, MeshDecodingOptions options);
예제 #5
0
		public override Mesh Load(string file, MeshDecodingOptions options) {
			const bool strictParsing = true;
			
			// --- preparations ---
			bool isB3d = file.EndsWith(".b3d", StringComparison.OrdinalIgnoreCase);
			char commandArgumentSeparator = isB3d ? ' ' : ',';
			FileInformation fileInfo = new FileInformation(isB3d, file, strictParsing, options.Logger);
			List<MeshBuilder> meshBuilders = new List<MeshBuilder>();
			MeshBuilder currentMeshBuilder = new MeshBuilder();
			bool meshBuilderPresent = false;
			
			// --- line by line ---
			string[] lines = File.ReadAllLines(file, Encoding.UTF8);
			for (int l = 0; l < lines.Length; l++) {
				string line = lines[l];
				
				// --- trim comments and whitespace ---
				int semicolon = line.IndexOf(';');
				if (semicolon >= 0) {
					line = line.Substring(0, semicolon).Trim();
				} else {
					line = line.Trim();
				}
				if (line.Length != 0) {
					
					// --- split into command and argument sequence ---
					string command;
					string argumentSequence;
					int separator = line.IndexOf(commandArgumentSeparator);
					if (separator >= 0) {
						command = line.Substring(0, separator).TrimEnd();
						argumentSequence = line.Substring(separator + 1).TrimStart();
					} else {
						command = line;
						argumentSequence = string.Empty;
					}
					
					// --- handle malformed commands ---
					if (command.Length != 0) {
						if (isB3d) {
							int comma = command.IndexOf(',');
							if (comma >= 0) {
								argumentSequence = command.Substring(comma + 1).TrimStart() + ',' + argumentSequence;
								command = command.Substring(0, comma).TrimEnd();
								if (strictParsing) {
									string text = "Command \"" + command + "\" must be separated from its arguments by a space in B3D files on line " + (l + 1).ToString() + " in file \"" + file + "\".";
									options.Logger.Add(text);
								}
							}
						} else {
							int space = command.IndexOf(' ');
							if (space >= 0) {
								argumentSequence = command.Substring(space + 1).TrimStart() + ',' + argumentSequence;
								command = command.Substring(0, space).TrimEnd();
								if (strictParsing) {
									string text = "Command \"" + command + "\" must be separated from its arguments by a comma in CSV files on line " + (l + 1).ToString() + " in file \"" + file + "\".";
									options.Logger.Add(text);
								}
							}
						}
					}
					if (command.Length != 0) {
						
						// --- split into arguments and trim empty arguments from the end ---
						string[] arguments = argumentSequence.Split(',');
						for (int a = 0; a < arguments.Length; a++) {
							arguments[a] = arguments[a].Trim();
						}
						int argumentCount = 0;
						for (int a = arguments.Length - 1; a >= 0; a--) {
							if (arguments[a].Length != 0) {
								argumentCount = a + 1;
								break;
							}
						}

						// --- process commands ---
						LineInformation lineInfo = new LineInformation(command, arguments, argumentCount, l + 1, fileInfo);
						string commandLower = command.ToLowerInvariant();
						switch (commandLower) {
							case "[meshbuilder]":
							case "createmeshbuilder":
								{
									if (strictParsing) {
										CheckCommand(command, "[MeshBuilder]", "CreateMeshBuilder", lineInfo);
										CheckArgumentCount(command, argumentCount, 0, 0, lineInfo);
									}
									meshBuilders.Add(currentMeshBuilder);
									currentMeshBuilder = new MeshBuilder();
									meshBuilderPresent = true;
								}
								break;
							case "vertex":
							case "addvertex":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckCommand(command, "Vertex", "AddVertex", lineInfo);
										CheckArgumentCount(command, argumentCount, 0, 8, lineInfo);
									}
									double positionX = GetDoubleFromArgument(0, "positionX", 0.0, lineInfo);
									double positionY = GetDoubleFromArgument(1, "positionY", 0.0, lineInfo);
									double positionZ = GetDoubleFromArgument(2, "positionZ", 0.0, lineInfo);
									double normalX   = GetDoubleFromArgument(3, "normalX",   0.0, lineInfo);
									double normalY   = GetDoubleFromArgument(4, "normalY",   0.0, lineInfo);
									double normalZ   = GetDoubleFromArgument(5, "normalZ",   0.0, lineInfo);
									double textureX  = GetDoubleFromArgument(6, "textureX",  0.0, lineInfo);
									double textureY  = GetDoubleFromArgument(7, "textureY",  0.0, lineInfo);
									MeshBuilderVertex vertex = new MeshBuilderVertex(new Vector3d(positionX, positionY, positionZ), new Vector3d(normalX, normalY, normalZ), new Vector2d(textureX, textureY));
									currentMeshBuilder.Vertices.Add(vertex);
								}
								break;
							case "face":
							case "face2":
							case "addface":
							case "addface2":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
									}
									bool face2 = commandLower[commandLower.Length - 1] == '2';
									if (strictParsing) {
										string suffix = face2 ? "2" : string.Empty;
										CheckCommand(command, "Face" + suffix, "AddFace" + suffix, lineInfo);
									}
									bool success = CheckArgumentCount(command, argumentCount, 3, int.MaxValue, lineInfo);
									int[] indices = new int[argumentCount];
									for (int i = 0; i < argumentCount; i++) {
										if (!TryGetInt32FromArgument(i, "vertex" + (i + 1).ToString(), 0, currentMeshBuilder.Vertices.Count - 1, -1, false, lineInfo, out indices[i])) {
											success = false;
										}
									}
									if (success) {
										currentMeshBuilder.Faces.Add(new MeshBuilderFace(0, indices, lineInfo.LineNumber));
										if (face2) {
											Array.Reverse(indices);
											MeshBuilderFace face = new MeshBuilderFace(0, indices, lineInfo.LineNumber);
											face.Normals = MeshBuilderFaceNormals.Inverse;
											currentMeshBuilder.Faces.Add(face);
										}
									}
								}
								break;
							case "cube":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckArgumentCount(command, argumentCount, 0, 3, lineInfo);
									}
									double x = GetDoubleFromArgument(0, "x", 0.0, lineInfo);
									double y = GetDoubleFromArgument(1, "y", x,   lineInfo);
									double z = GetDoubleFromArgument(2, "z", x,   lineInfo);
									currentMeshBuilder.AddCube(x, y, z, lineInfo.LineNumber);
								}
								break;
							case "cylinder":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckArgumentCount(command, argumentCount, 1, 4, lineInfo);
									}
									int numVertices;
									bool success = TryGetInt32FromArgument(0, "numVertices", 2, int.MaxValue, 0, false, lineInfo, out numVertices);
									double upper  = GetDoubleFromArgument(1, "upper",  0.0, lineInfo);
									double lower  = GetDoubleFromArgument(2, "lower",  0.0, lineInfo);
									double height = GetDoubleFromArgument(3, "height", 0.0, lineInfo);
									if (success) {
										currentMeshBuilder.AddCylinder(numVertices, upper, lower, height, lineInfo.LineNumber);
									}
								}
								break;
							case "[texture]":
							case "generatenormals":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckCommand(command, "[Texture]", "GenerateNormals", lineInfo);
										CheckArgumentCount(command, argumentCount, 0, 0, lineInfo);
									}
								}
								break;
							case "translate":
							case "translateall":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckArgumentCount(command, argumentCount, 0, 3, lineInfo);
									}
									double x = GetDoubleFromArgument(0, "x", 0.0, lineInfo);
									double y = GetDoubleFromArgument(1, "y", 0.0, lineInfo);
									double z = GetDoubleFromArgument(2, "z", 0.0, lineInfo);
									Vector3d offset = new Vector3d(x, y, z);
									currentMeshBuilder.Translate(offset);
									if (commandLower == "translateall") {
										foreach (MeshBuilder meshBuilder in meshBuilders) {
											meshBuilder.Translate(offset);
										}
									}
								}
								break;
							case "scale":
							case "scaleall":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckArgumentCount(command, argumentCount, 0, 3, lineInfo);
									}
									double x = GetDoubleFromArgument(0, "x", 1.0, lineInfo);
									double y = GetDoubleFromArgument(1, "y", 1.0, lineInfo);
									double z = GetDoubleFromArgument(2, "z", 1.0, lineInfo);
									Vector3d factor = new Vector3d(x, y, z);
									currentMeshBuilder.Scale(factor);
									if (commandLower == "scaleall") {
										foreach (MeshBuilder meshBuilder in meshBuilders) {
											meshBuilder.Scale(factor);
										}
									}
								}
								break;
							case "rotate":
							case "rotateall":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckArgumentCount(command, argumentCount, 0, 4, lineInfo);
									}
									double x = GetDoubleFromArgument(0, "x",     0.0, lineInfo);
									double y = GetDoubleFromArgument(1, "y",     0.0, lineInfo);
									double z = GetDoubleFromArgument(2, "z",     0.0, lineInfo);
									double a = GetDoubleFromArgument(3, "angle", 0.0, lineInfo) * (Math.PI / 180.0);
									Vector3d direction = Vector3d.Normalize(new Vector3d(x, y, z));
									if (direction.IsZero()) {
										direction = Vector3d.Right;
									}
									Vector2d angle = new Vector2d(Math.Cos(a), Math.Sin(a));
									currentMeshBuilder.Rotate(direction, angle);
									if (commandLower == "rotateall") {
										foreach (MeshBuilder meshBuilder in meshBuilders) {
											meshBuilder.Rotate(direction, angle);
										}
									}
								}
								break;
							case "shear":
							case "shearall":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckArgumentCount(command, argumentCount, 0, 7, lineInfo);
									}
									double dx = GetDoubleFromArgument(0, "dx",    0.0, lineInfo);
									double dy = GetDoubleFromArgument(1, "dy",    0.0, lineInfo);
									double dz = GetDoubleFromArgument(2, "dz",    0.0, lineInfo);
									double sx = GetDoubleFromArgument(3, "sx",    0.0, lineInfo);
									double sy = GetDoubleFromArgument(4, "sy",    0.0, lineInfo);
									double sz = GetDoubleFromArgument(5, "sz",    0.0, lineInfo);
									double r  = GetDoubleFromArgument(6, "ratio", 0.0, lineInfo);
									Vector3d direction = Vector3d.Normalize(new Vector3d(dx, dy, dz));
									Vector3d shift     = Vector3d.Normalize(new Vector3d(sx, sy, sz));
									currentMeshBuilder.Shear(direction, shift, r);
									if (commandLower == "shearall") {
										foreach (MeshBuilder meshBuilder in meshBuilders) {
											meshBuilder.Shear(direction, shift, r);
										}
									}
								}
								break;
							case "color":
							case "setcolor":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckCommand(command, "Color", "SetColor", lineInfo);
										CheckArgumentCount(command, argumentCount, 0, 4, lineInfo);
									}
									double r, g, b, a;
									TryGetDoubleFromArgument(0, "red",   0.0, 255.0, 255.0, true, lineInfo, out r);
									TryGetDoubleFromArgument(1, "green", 0.0, 255.0, 255.0, true, lineInfo, out g);
									TryGetDoubleFromArgument(2, "blue",  0.0, 255.0, 255.0, true, lineInfo, out b);
									TryGetDoubleFromArgument(3, "alpha", 0.0, 255.0, 255.0, true, lineInfo, out a);
									Vector3f color = new Vector3f((float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f);
									for (int i = 0; i < currentMeshBuilder.Faces.Count; i++) {
										currentMeshBuilder.Faces[i].ReflectiveColor = color;
										currentMeshBuilder.Faces[i].Alpha = (float)a / 255.0f;
									}
								}
								break;
							case "emissivecolor":
							case "setemissivecolor":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckCommand(command, "EmissiveColor", "SetEmissiveColor", lineInfo);
										CheckArgumentCount(command, argumentCount, 0, 3, lineInfo);
									}
									double r, g, b;
									TryGetDoubleFromArgument(0, "red",   0.0, 255.0, 0.0, true, lineInfo, out r);
									TryGetDoubleFromArgument(1, "green", 0.0, 255.0, 0.0, true, lineInfo, out g);
									TryGetDoubleFromArgument(2, "blue",  0.0, 255.0, 0.0, true, lineInfo, out b);
									Vector3f color = new Vector3f((float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f);
									for (int i = 0; i < currentMeshBuilder.Faces.Count; i++) {
										currentMeshBuilder.Faces[i].EmissiveColor = color;
									}
								}
								break;
							case "blendmode":
							case "setblendmode":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckCommand(command, "BlendMode", "SetBlendMode", lineInfo);
										CheckArgumentCount(command, argumentCount, 0, 3, lineInfo);
									}
									string blendMode = argumentCount >= 1 && arguments[0].Length != 0 ? arguments[0] : "normal";
									double glowHalfDistance;
									TryGetDoubleFromArgument(1, "glowHalfDistance", 0.0, double.MaxValue, 0.0, true, lineInfo, out glowHalfDistance);
									string glowAttenuationMode = argumentCount >= 3 && arguments[2].Length != 0 ? arguments[2] : "divideexponent2";
									switch (blendMode.ToLowerInvariant()) {
										case "normal":
											break;
										case "additive":
											break;
										default:
											string text = "\"" + blendMode + "\" as argument 1 to command " + lineInfo.Command + " is not a valid blend mode on line " + lineInfo.LineNumber.ToString() + " in file \"" + lineInfo.FileInfo.File + "\".";
											options.Logger.Add(text);
											break;
									}
									switch (glowAttenuationMode.ToLowerInvariant()) {
										case "divideexponent2":
											break;
										case "divideexponent4":
											break;
										default:
											string text = "\"" + blendMode + "\" as argument 3 to command " + lineInfo.Command + " is not a valid glow attenuation mode on line " + lineInfo.LineNumber.ToString() + " in file \"" + lineInfo.FileInfo.File + "\".";
											options.Logger.Add(text);
											break;
									}
									
									// TODO: Not implemented.
									
								}
								break;
							case "load":
							case "loadtexture":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckCommand(command, "Load", "LoadTexture", lineInfo);
										CheckArgumentCount(command, argumentCount, 1, 2, lineInfo);
									}
									string daytimeTexture = null;
									string nighttimeTexture = null;
									if (argumentCount >= 1 && arguments[0].Length != 0) {
										daytimeTexture = arguments[0];
									}
									if (argumentCount >= 2 && arguments[1].Length != 0) {
										nighttimeTexture = arguments[1];
									}
									if (daytimeTexture != null) {
										currentMeshBuilder.DaytimeTexture = Platform.CombineFile(Path.GetDirectoryName(file), daytimeTexture);
									}
									
									// TODO: Nighttime textures.
									
								}
								break;
							case "transparent":
							case "setdecaltransparentcolor":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckCommand(command, "Transparent", "SetDecalTransparentColor", lineInfo);
										CheckArgumentCount(command, argumentCount, 0, 3, lineInfo);
									}
									int r, g, b;
									TryGetInt32FromArgument(0, "red",   0, 255, 0, true, lineInfo, out r);
									TryGetInt32FromArgument(1, "green", 0, 255, 0, true, lineInfo, out g);
									TryGetInt32FromArgument(2, "blue",  0, 255, 0, true, lineInfo, out b);
									currentMeshBuilder.TransparentColor = new Vector3b((byte)r, (byte)g, (byte)b);
									currentMeshBuilder.TransparentColorUsed = true;
								}
								break;
							case "coordinates":
							case "settexturecoordinates":
								{
									if (strictParsing) {
										CheckMeshBuilderPresence(command, lineInfo, ref meshBuilderPresent);
										CheckCommand(command, "Coordinates", "SetTextureCoordinates", lineInfo);
										CheckArgumentCount(command, argumentCount, 1, 3, lineInfo);
									}
									int v = -1;
									bool success;
									if (currentMeshBuilder.Vertices.Count == 0) {
										string text = lineInfo.Command + " cannot be used at this point because no vertices were defined in the mesh builder on line " + lineInfo.LineNumber.ToString() + " in file \"" + lineInfo.FileInfo.File + "\".";
										options.Logger.Add(text);
										success = false;
									} else {
										success = TryGetInt32FromArgument(0, "vertex", 0, currentMeshBuilder.Vertices.Count - 1, 0, false, lineInfo, out v);
									}
									double x = GetDoubleFromArgument(1, "x", 0.0, lineInfo);
									double y = GetDoubleFromArgument(2, "y", 0.0, lineInfo);
									if (success) {
										currentMeshBuilder.Vertices[v].Texture = new Vector2d(x, y);
									}
								}
								break;
							default:
								{
									string text = "Unsupported command \"" + command + "\" found on line " + (l + 1).ToString() + " in file \"" + file + "\".";
									options.Logger.Add(text);
								}
								break;
						}
					}
				}
			}
			meshBuilders.Add(currentMeshBuilder);
			currentMeshBuilder = null;
			
			// --- assemble mesh ---
			Dictionary<Vertex, int> hashedVertices = new Dictionary<Vertex, int>();
			Dictionary<Material, int> hashedMaterials = new Dictionary<Material, int>();
			List<Vertex> vertices = new List<Vertex>();
			List<Material> materials = new List<Material>();
			List<Face> faces = new List<Face>();
			foreach (MeshBuilder meshBuilder in meshBuilders) {
				foreach (MeshBuilderFace meshBuilderFace in meshBuilder.Faces) {
					
					// --- generate normal ---
					Vector3d normal;
					{
						Vector3d a = meshBuilder.Vertices[meshBuilderFace.Vertices[0]].Position;
						Vector3d b = meshBuilder.Vertices[meshBuilderFace.Vertices[1]].Position;
						Vector3d c = meshBuilder.Vertices[meshBuilderFace.Vertices[2]].Position;
						normal = Vector3d.Normalize(Vector3d.Cross(b - a, c - a));
						if (normal.IsZero()) {
							normal = Vector3d.Up;
						}
					}
					
					// --- vertices ---
					Vertex[] v = new Vertex[meshBuilderFace.Vertices.Length];
					for (int i = 0; i < meshBuilderFace.Vertices.Length; i++) {
						MeshBuilderVertex meshBuilderVertex = meshBuilder.Vertices[meshBuilderFace.Vertices[i]];
						v[i] = new Vertex((Vector3f)meshBuilderVertex.Position, (Vector3f)meshBuilderVertex.Normal, (Vector2f)meshBuilderVertex.Texture);
						if (meshBuilderFace.Normals == MeshBuilderFaceNormals.Generate || meshBuilderVertex.Normal.IsZero()) {
							v[i].Normal = (Vector3f)normal;
						} else if (meshBuilderFace.Normals == MeshBuilderFaceNormals.Inverse) {
							v[i].Normal = (Vector3f)(-meshBuilderVertex.Normal);
						}
					}
					int[] vertexIndices = new int[v.Length];
					for (int i = 0; i < v.Length; i++) {
						if (!hashedVertices.TryGetValue(v[i], out vertexIndices[i])) {
							vertexIndices[i] = vertices.Count;
							vertices.Add(v[i]);
							hashedVertices.Add(v[i], vertexIndices[i]);
						}
					}
					
					// --- material ---
					Material material = new Material();
					material.Alpha = meshBuilderFace.Alpha;
					material.EmissiveColor = meshBuilderFace.EmissiveColor;
					material.ReflectiveColor = meshBuilderFace.ReflectiveColor;
					if (meshBuilder.DaytimeTexture != null) {
						if (meshBuilder.TransparentColorUsed) {
							material.Texture = options.Manager.Add(meshBuilder.DaytimeTexture, meshBuilder.TransparentColor);
						} else {
							material.Texture = options.Manager.Add(meshBuilder.DaytimeTexture);
						}
					}
					int materialIndex;
					if (!hashedMaterials.TryGetValue(material, out materialIndex)) {
						materialIndex = materials.Count;
						materials.Add(material);
						hashedMaterials.Add(material, materialIndex);
					}
					
					// --- face ---
					Face face = new Face(vertexIndices, materialIndex, meshBuilderFace.LineNumber);
					faces.Add(face);
					
				}
			}
			return new Mesh(vertices.ToArray(), materials.ToArray(), faces.ToArray());
		}