private static bool ProcessStructure(string FileName, Structure Structure, out ObjectManager.StaticObject Object, ObjectManager.ObjectLoadMode LoadMode, bool ForceTextureRepeatX, bool ForceTextureRepeatY) {
System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
Object = new ObjectManager.StaticObject();
Object.Mesh.Faces = new World.MeshFace[] { };
Object.Mesh.Materials = new World.MeshMaterial[] { };
Object.Mesh.Vertices = new World.Vertex[] { };
// file
for (int i = 0; i < Structure.Data.Length; i++) {
Structure f = Structure.Data[i] as Structure;
if (f == null) {
Interface.AddMessage(Interface.MessageType.Error, false, "Top-level inlined arguments are invalid in x object file " + FileName);
return false;
}
switch (f.Name) {
case "Mesh":
{
// mesh
if (f.Data.Length < 4) {
Interface.AddMessage(Interface.MessageType.Error, false, "Mesh is expected to have at least 4 arguments in x object file " + FileName);
return false;
} else if (!(f.Data[0] is int)) {
Interface.AddMessage(Interface.MessageType.Error, false, "nVertices is expected to be a DWORD in Mesh in x object file " + FileName);
return false;
} else if (!(f.Data[1] is Structure[])) {
Interface.AddMessage(Interface.MessageType.Error, false, "vertices[nVertices] is expected to be a Vector array in Mesh in x object file " + FileName);
return false;
} else if (!(f.Data[2] is int)) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaces is expected to be a DWORD in Mesh in x object file " + FileName);
return false;
} else if (!(f.Data[3] is Structure[])) {
Interface.AddMessage(Interface.MessageType.Error, false, "faces[nFaces] is expected to be a MeshFace array in Mesh in x object file " + FileName);
return false;
}
int nVertices = (int)f.Data[0];
if (nVertices < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "nVertices is expected to be non-negative in Mesh in x object file " + FileName);
return false;
}
Structure[] vertices = (Structure[])f.Data[1];
if (nVertices != vertices.Length) {
Interface.AddMessage(Interface.MessageType.Error, false, "nVertices does not match with the length of array vertices in Mesh in x object file " + FileName);
return false;
}
int nFaces = (int)f.Data[2];
if (nFaces < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaces is expected to be non-negative in Mesh in x object file " + FileName);
return false;
}
Structure[] faces = (Structure[])f.Data[3];
if (nFaces != faces.Length) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaces does not match with the length of array faces in Mesh in x object file " + FileName);
return false;
}
// collect vertices
World.Vertex[] Vertices = new World.Vertex[nVertices];
for (int j = 0; j < nVertices; j++) {
if (vertices[j].Name != "Vector") {
Interface.AddMessage(Interface.MessageType.Error, false, "vertices[" + j.ToString(Culture) + "] is expected to be of template Vertex in Mesh in x object file " + FileName);
return false;
} else if (vertices[j].Data.Length != 3) {
Interface.AddMessage(Interface.MessageType.Error, false, "vertices[" + j.ToString(Culture) + "] is expected to have 3 arguments in Mesh in x object file " + FileName);
return false;
} else if (!(vertices[j].Data[0] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "x is expected to be a float in vertices[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
return false;
} else if (!(vertices[j].Data[1] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "y is expected to be a float in vertices[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
return false;
} else if (!(vertices[j].Data[2] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "z is expected to be a float in vertices[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
return false;
}
double x = (double)vertices[j].Data[0];
double y = (double)vertices[j].Data[1];
double z = (double)vertices[j].Data[2];
Vertices[j].Coordinates = new World.Vector3D(x, y, z);
}
// collect faces
int[][] Faces = new int[nFaces][];
World.Vector3Df[][] FaceNormals = new World.Vector3Df[nFaces][];
int[] FaceMaterials = new int[nFaces];
for (int j = 0; j < nFaces; j++) {
FaceMaterials[j] = -1;
}
for (int j = 0; j < nFaces; j++) {
if (faces[j].Name != "MeshFace") {
Interface.AddMessage(Interface.MessageType.Error, false, "faces[" + j.ToString(Culture) + "] is expected to be of template MeshFace in Mesh in x object file " + FileName);
return false;
} else if (faces[j].Data.Length != 2) {
Interface.AddMessage(Interface.MessageType.Error, false, "face[" + j.ToString(Culture) + "] is expected to have 2 arguments in Mesh in x object file " + FileName);
return false;
} else if (!(faces[j].Data[0] is int)) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices is expected to be a DWORD in face[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
return false;
} else if (!(faces[j].Data[1] is int[])) {
Interface.AddMessage(Interface.MessageType.Error, false, "faceVertexIndices[nFaceVertexIndices] is expected to be a DWORD array in face[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
return false;
}
int nFaceVertexIndices = (int)faces[j].Data[0];
if (nFaceVertexIndices < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices is expected to be non-negative in MeshFace in Mesh in x object file " + FileName);
return false;
}
int[] faceVertexIndices = (int[])faces[j].Data[1];
if (nFaceVertexIndices != faceVertexIndices.Length) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices does not match with the length of array faceVertexIndices in face[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
return false;
}
Faces[j] = new int[nFaceVertexIndices];
FaceNormals[j] = new World.Vector3Df[nFaceVertexIndices];
for (int k = 0; k < nFaceVertexIndices; k++) {
if (faceVertexIndices[k] < 0 | faceVertexIndices[k] >= nVertices) {
Interface.AddMessage(Interface.MessageType.Error, false, "faceVertexIndices[" + k.ToString(Culture) + "] does not reference a valid vertex in face[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
return false;
}
Faces[j][k] = faceVertexIndices[k];
FaceNormals[j][k] = new World.Vector3Df(0.0f, 0.0f, 0.0f);
}
}
// collect additional templates
Material[] Materials = new Material[] { };
for (int j = 4; j < f.Data.Length; j++) {
Structure g = f.Data[j] as Structure;
if (g == null) {
Interface.AddMessage(Interface.MessageType.Error, false, "Unexpected inlined argument encountered in Mesh in x object file " + FileName);
return false;
}
switch (g.Name) {
case "MeshMaterialList":
{
// meshmateriallist
if (g.Data.Length < 3) {
Interface.AddMessage(Interface.MessageType.Error, false, "MeshMaterialList is expected to have at least 3 arguments in Mesh in x object file " + FileName);
return false;
} else if (!(g.Data[0] is int)) {
Interface.AddMessage(Interface.MessageType.Error, false, "nMaterials is expected to be a DWORD in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(g.Data[1] is int)) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceIndexes is expected to be a DWORD in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(g.Data[2] is int[])) {
Interface.AddMessage(Interface.MessageType.Error, false, "faceIndexes[nFaceIndexes] is expected to be a DWORD array in MeshMaterialList in Mesh in x object file " + FileName);
return false;
}
int nMaterials = (int)g.Data[0];
if (nMaterials < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "nMaterials is expected to be non-negative in MeshMaterialList in Mesh in x object file " + FileName);
return false;
}
int nFaceIndexes = (int)g.Data[1];
if (nFaceIndexes < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceIndexes is expected to be non-negative in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (nFaceIndexes > nFaces) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceIndexes does not reference valid faces in MeshMaterialList in Mesh in x object file " + FileName);
return false;
}
int[] faceIndexes = (int[])g.Data[2];
if (nFaceIndexes != faceIndexes.Length) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceIndexes does not match with the length of array faceIndexes in face[" + j.ToString(Culture) + "] in Mesh in x object file " + FileName);
return false;
}
for (int k = 0; k < nFaceIndexes; k++) {
if (faceIndexes[k] < 0 | faceIndexes[k] >= nMaterials) {
Interface.AddMessage(Interface.MessageType.Error, false, "faceIndexes[" + k.ToString(Culture) + "] does not reference a valid Material template in MeshMaterialList in Mesh in x object file " + FileName);
return false;
}
}
// collect material templates
int mn = Materials.Length;
Array.Resize<Material>(ref Materials, mn + nMaterials);
for (int k = 0; k < nMaterials; k++) {
Materials[mn + k].faceColor = new World.ColorRGBA(255, 255, 255, 255);
Materials[mn + k].specularColor = new World.ColorRGB(0, 0, 0);
Materials[mn + k].emissiveColor = new World.ColorRGB(0, 0, 0);
Materials[mn + k].TextureFilename = null;
}
int MaterialIndex = mn;
for (int k = 3; k < g.Data.Length; k++) {
Structure h = g.Data[k] as Structure;
if (h == null) {
Interface.AddMessage(Interface.MessageType.Error, false, "Unexpected inlined argument encountered in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (h.Name != "Material") {
Interface.AddMessage(Interface.MessageType.Error, false, "Material template expected in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else {
// material
if (h.Data.Length < 4) {
Interface.AddMessage(Interface.MessageType.Error, false, "Material is expected to have at least 4 arguments in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(h.Data[0] is Structure)) {
Interface.AddMessage(Interface.MessageType.Error, false, "faceColor is expected to be a ColorRGBA in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(h.Data[1] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "power is expected to be a float in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(h.Data[2] is Structure)) {
Interface.AddMessage(Interface.MessageType.Error, false, "specularColor is expected to be a ColorRGBA in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(h.Data[3] is Structure)) {
Interface.AddMessage(Interface.MessageType.Error, false, "emissiveColor is expected to be a ColorRGBA in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
}
Structure faceColor = (Structure)h.Data[0];
Structure specularColor = (Structure)h.Data[2];
Structure emissiveColor = (Structure)h.Data[3];
double red, green, blue, alpha;
// collect face color
if (faceColor.Name != "ColorRGBA") {
Interface.AddMessage(Interface.MessageType.Error, false, "faceColor is expected to be a ColorRGBA in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (faceColor.Data.Length != 4) {
Interface.AddMessage(Interface.MessageType.Error, false, "faceColor is expected to have 4 arguments in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(faceColor.Data[0] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be a float in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(faceColor.Data[1] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be a float in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(faceColor.Data[2] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be a float in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(faceColor.Data[3] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "alpha is expected to be a float in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
}
red = (double)faceColor.Data[0];
green = (double)faceColor.Data[1];
blue = (double)faceColor.Data[2];
alpha = (double)faceColor.Data[3];
if (red < 0.0 | red > 1.0) {
Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be in the range from 0.0 to 1.0 in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
red = red < 0.5 ? 0.0 : 1.0;
}
if (green < 0.0 | green > 1.0) {
Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be in the range from 0.0 to 1.0 in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
green = green < 0.5 ? 0.0 : 1.0;
}
if (blue < 0.0 | blue > 1.0) {
Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be in the range from 0.0 to 1.0 in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
blue = blue < 0.5 ? 0.0 : 1.0;
}
if (alpha < 0.0 | alpha > 1.0) {
Interface.AddMessage(Interface.MessageType.Error, false, "alpha is expected to be in the range from 0.0 to 1.0 in faceColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
alpha = alpha < 0.5 ? 0.0 : 1.0;
}
Materials[MaterialIndex].faceColor = new World.ColorRGBA((byte)Math.Round(255.0 * red), (byte)Math.Round(255.0 * green), (byte)Math.Round(255.0 * blue), (byte)Math.Round(255.0 * alpha));
// collect specular color
if (specularColor.Name != "ColorRGB") {
Interface.AddMessage(Interface.MessageType.Error, false, "specularColor is expected to be a ColorRGB in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (specularColor.Data.Length != 3) {
Interface.AddMessage(Interface.MessageType.Error, false, "specularColor is expected to have 3 arguments in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(specularColor.Data[0] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be a float in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(specularColor.Data[1] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be a float in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(specularColor.Data[2] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be a float in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
}
red = (double)specularColor.Data[0];
green = (double)specularColor.Data[1];
blue = (double)specularColor.Data[2];
if (red < 0.0 | red > 1.0) {
Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be in the range from 0.0 to 1.0 in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
red = red < 0.5 ? 0.0 : 1.0;
}
if (green < 0.0 | green > 1.0) {
Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be in the range from 0.0 to 1.0 in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
green = green < 0.5 ? 0.0 : 1.0;
}
if (blue < 0.0 | blue > 1.0) {
Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be in the range from 0.0 to 1.0 in specularColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
blue = blue < 0.5 ? 0.0 : 1.0;
}
Materials[MaterialIndex].specularColor = new World.ColorRGB((byte)Math.Round(255.0 * red), (byte)Math.Round(255.0 * green), (byte)Math.Round(255.0 * blue));
// collect emissive color
if (emissiveColor.Name != "ColorRGB") {
Interface.AddMessage(Interface.MessageType.Error, false, "emissiveColor is expected to be a ColorRGBA in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (emissiveColor.Data.Length != 3) {
Interface.AddMessage(Interface.MessageType.Error, false, "emissiveColor is expected to have 3 arguments in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(emissiveColor.Data[0] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be a float in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(emissiveColor.Data[1] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be a float in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(emissiveColor.Data[2] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be a float in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
}
red = (double)emissiveColor.Data[0];
green = (double)emissiveColor.Data[1];
blue = (double)emissiveColor.Data[2];
if (red < 0.0 | red > 1.0) {
Interface.AddMessage(Interface.MessageType.Error, false, "red is expected to be in the range from 0.0 to 1.0 in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
red = red < 0.5 ? 0.0 : 1.0;
}
if (green < 0.0 | green > 1.0) {
Interface.AddMessage(Interface.MessageType.Error, false, "green is expected to be in the range from 0.0 to 1.0 in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
green = green < 0.5 ? 0.0 : 1.0;
}
if (blue < 0.0 | blue > 1.0) {
Interface.AddMessage(Interface.MessageType.Error, false, "blue is expected to be in the range from 0.0 to 1.0 in emissiveColor in Material in MeshMaterialList in Mesh in x object file " + FileName);
blue = blue < 0.5 ? 0.0 : 1.0;
}
Materials[MaterialIndex].emissiveColor = new World.ColorRGB((byte)Math.Round(255.0 * red), (byte)Math.Round(255.0 * green), (byte)Math.Round(255.0 * blue));
// collect additional templates
for (int l = 4; l < h.Data.Length; l++) {
Structure e = h.Data[l] as Structure;
if (e == null) {
Interface.AddMessage(Interface.MessageType.Error, false, "Unexpected inlined argument encountered in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
}
switch (e.Name) {
case "TextureFilename":
{
// texturefilename
if (e.Data.Length != 1) {
Interface.AddMessage(Interface.MessageType.Error, false, "filename is expected to have 1 argument in TextureFilename in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
} else if (!(e.Data[0] is string)) {
Interface.AddMessage(Interface.MessageType.Error, false, "filename is expected to be a string in TextureFilename in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
}
string filename = (string)e.Data[0];
if (Interface.ContainsInvalidPathChars(filename)) {
Interface.AddMessage(Interface.MessageType.Error, false, "filename contains illegal characters in TextureFilename in Material in MeshMaterialList in Mesh in x object file " + FileName);
} else {
string File = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), filename);
if (System.IO.File.Exists(File)) {
Materials[MaterialIndex].TextureFilename = File;
} else {
Interface.AddMessage(Interface.MessageType.Error, true, "The texture file " + File + " could not be found in TextureFilename in Material in MeshMaterialList in Mesh in x object file " + FileName);
}
}
} break;
default:
// unknown
Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported template " + e.Name + " encountered in MeshMaterialList in Mesh in x object file " + FileName);
break;
}
}
// finish
MaterialIndex++;
}
} if (MaterialIndex != mn + nMaterials) {
Interface.AddMessage(Interface.MessageType.Error, false, "nMaterials does not match the number of Material templates encountered in Material in MeshMaterialList in Mesh in x object file " + FileName);
return false;
}
// assign materials
for (int k = 0; k < nFaceIndexes; k++) {
FaceMaterials[k] = faceIndexes[k];
}
if (nMaterials != 0) {
for (int k = 0; k < nFaces; k++) {
if (FaceMaterials[k] == -1) {
FaceMaterials[k] = 0;
}
}
}
} break;
case "MeshTextureCoords":
{
// meshtexturecoords
if (g.Data.Length != 2) {
Interface.AddMessage(Interface.MessageType.Error, false, "MeshTextureCoords is expected to have 2 arguments in Mesh in x object file " + FileName);
return false;
} else if (!(g.Data[0] is int)) {
Interface.AddMessage(Interface.MessageType.Error, false, "nTextureCoords is expected to be a DWORD in MeshTextureCoords in Mesh in x object file " + FileName);
return false;
} else if (!(g.Data[1] is Structure[])) {
Interface.AddMessage(Interface.MessageType.Error, false, "textureCoords[nTextureCoords] is expected to be a Coords2d array in MeshTextureCoords in Mesh in x object file " + FileName);
return false;
}
int nTextureCoords = (int)g.Data[0];
Structure[] textureCoords = (Structure[])g.Data[1];
if (nTextureCoords < 0 | nTextureCoords > nVertices) {
Interface.AddMessage(Interface.MessageType.Error, false, "nTextureCoords does not reference valid vertices in MeshTextureCoords in Mesh in x object file " + FileName);
return false;
}
for (int k = 0; k < nTextureCoords; k++) {
if (textureCoords[k].Name != "Coords2d") {
Interface.AddMessage(Interface.MessageType.Error, false, "textureCoords[" + k.ToString(Culture) + "] is expected to be a Coords2d in MeshTextureCoords in Mesh in x object file " + FileName);
return false;
} else if (textureCoords[k].Data.Length != 2) {
Interface.AddMessage(Interface.MessageType.Error, false, "textureCoords[" + k.ToString(Culture) + "] is expected to have 2 arguments in MeshTextureCoords in Mesh in x object file " + FileName);
return false;
} else if (!(textureCoords[k].Data[0] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "u is expected to be a float in textureCoords[" + k.ToString(Culture) + "] in MeshTextureCoords in Mesh in x object file " + FileName);
return false;
} else if (!(textureCoords[k].Data[1] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "v is expected to be a float in textureCoords[" + k.ToString(Culture) + "] in MeshTextureCoords in Mesh in x object file " + FileName);
return false;
}
double u = (double)textureCoords[k].Data[0];
double v = (double)textureCoords[k].Data[1];
Vertices[k].TextureCoordinates = new World.Vector2Df((float)u, (float)v);
}
} break;
case "MeshNormals":
{
// meshnormals
if (g.Data.Length != 4) {
Interface.AddMessage(Interface.MessageType.Error, false, "MeshNormals is expected to have 4 arguments in Mesh in x object file " + FileName);
return false;
} else if (!(g.Data[0] is int)) {
Interface.AddMessage(Interface.MessageType.Error, false, "nNormals is expected to be a DWORD in MeshNormals in Mesh in x object file " + FileName);
return false;
} else if (!(g.Data[1] is Structure[])) {
Interface.AddMessage(Interface.MessageType.Error, false, "normals is expected to be a Vector array in MeshNormals in Mesh in x object file " + FileName);
return false;
} else if (!(g.Data[2] is int)) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceNormals is expected to be a DWORD in MeshNormals in Mesh in x object file " + FileName);
return false;
} else if (!(g.Data[3] is Structure[])) {
Interface.AddMessage(Interface.MessageType.Error, false, "faceNormals is expected to be a MeshFace array in MeshNormals in Mesh in x object file " + FileName);
return false;
}
int nNormals = (int)g.Data[0];
if (nNormals < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "nNormals is expected to be non-negative in MeshNormals in Mesh in x object file " + FileName);
return false;
}
Structure[] normals = (Structure[])g.Data[1];
if (nNormals != normals.Length) {
Interface.AddMessage(Interface.MessageType.Error, false, "nNormals does not match with the length of array normals in MeshNormals in Mesh in x object file " + FileName);
return false;
}
int nFaceNormals = (int)g.Data[2];
if (nFaceNormals < 0 | nFaceNormals > nFaces) {
Interface.AddMessage(Interface.MessageType.Error, false, "nNormals does not reference valid vertices in MeshNormals in Mesh in x object file " + FileName);
return false;
}
Structure[] faceNormals = (Structure[])g.Data[3];
if (nFaceNormals != faceNormals.Length) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceNormals does not match with the length of array faceNormals in MeshNormals in Mesh in x object file " + FileName);
return false;
}
// collect normals
World.Vector3Df[] Normals = new World.Vector3Df[nNormals];
for (int k = 0; k < nNormals; k++) {
if (normals[k].Name != "Vector") {
Interface.AddMessage(Interface.MessageType.Error, false, "normals[" + k.ToString(Culture) + "] is expected to be of template Vertex in MeshNormals in Mesh in x object file " + FileName);
return false;
} else if (normals[k].Data.Length != 3) {
Interface.AddMessage(Interface.MessageType.Error, false, "normals[" + k.ToString(Culture) + "] is expected to have 3 arguments in MeshNormals in Mesh in x object file " + FileName);
return false;
} else if (!(normals[k].Data[0] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "x is expected to be a float in normals[" + k.ToString(Culture) + "] in MeshNormals in Mesh in x object file " + FileName);
return false;
} else if (!(normals[k].Data[1] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "y is expected to be a float in normals[" + k.ToString(Culture) + " ]in MeshNormals in Mesh in x object file " + FileName);
return false;
} else if (!(normals[k].Data[2] is double)) {
Interface.AddMessage(Interface.MessageType.Error, false, "z is expected to be a float in normals[" + k.ToString(Culture) + "] in MeshNormals in Mesh in x object file " + FileName);
return false;
}
double x = (double)normals[k].Data[0];
double y = (double)normals[k].Data[1];
double z = (double)normals[k].Data[2];
World.Normalize(ref x, ref y, ref z);
Normals[k] = new World.Vector3Df((float)x, (float)y, (float)z);
}
// collect faces
for (int k = 0; k < nFaceNormals; k++) {
if (faceNormals[k].Name != "MeshFace") {
Interface.AddMessage(Interface.MessageType.Error, false, "faceNormals[" + k.ToString(Culture) + "] is expected to be of template MeshFace in MeshNormals in Mesh in x object file " + FileName);
return false;
} else if (faceNormals[k].Data.Length != 2) {
Interface.AddMessage(Interface.MessageType.Error, false, "faceNormals[" + k.ToString(Culture) + "] is expected to have 2 arguments in MeshNormals in Mesh in x object file " + FileName);
return false;
} else if (!(faceNormals[k].Data[0] is int)) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices is expected to be a DWORD in faceNormals[" + k.ToString(Culture) + "] in MeshNormals in Mesh in x object file " + FileName);
return false;
} else if (!(faceNormals[k].Data[1] is int[])) {
Interface.AddMessage(Interface.MessageType.Error, false, "faceVertexIndices[nFaceVertexIndices] is expected to be a DWORD array in faceNormals[" + k.ToString(Culture) + "] in MeshNormals in Mesh in x object file " + FileName);
return false;
}
int nFaceVertexIndices = (int)faceNormals[k].Data[0];
if (nFaceVertexIndices < 0 | nFaceVertexIndices > Faces[k].Length) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices does not reference a valid vertex in MeshFace in MeshNormals in Mesh in x object file " + FileName);
return false;
}
int[] faceVertexIndices = (int[])faceNormals[k].Data[1];
if (nFaceVertexIndices != faceVertexIndices.Length) {
Interface.AddMessage(Interface.MessageType.Error, false, "nFaceVertexIndices does not match with the length of array faceVertexIndices in faceNormals[" + k.ToString(Culture) + "] in MeshFace in MeshNormals in Mesh in x object file " + FileName);
return false;
}
for (int l = 0; l < nFaceVertexIndices; l++) {
if (faceVertexIndices[l] < 0 | faceVertexIndices[l] >= nNormals) {
Interface.AddMessage(Interface.MessageType.Error, false, "faceVertexIndices[" + l.ToString(Culture) + "] does not reference a valid normal in faceNormals[" + k.ToString(Culture) + "] in MeshFace in MeshNormals in Mesh in x object file " + FileName);
return false;
}
FaceNormals[k][l] = Normals[faceVertexIndices[l]];
}
}
} break;
default:
// unknown
Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported template " + g.Name + " encountered in Mesh in x object file " + FileName);
break;
}
}
// default material
if (Materials.Length == 0) {
Materials = new Material[1];
Materials[0].faceColor = new World.ColorRGBA(255, 255, 255, 255);
Materials[0].emissiveColor = new World.ColorRGB(0, 0, 0);
Materials[0].specularColor = new World.ColorRGB(0, 0, 0);
Materials[0].TextureFilename = null;
for (int j = 0; j < nFaces; j++) {
FaceMaterials[j] = 0;
}
}
// create mesh
int mf = Object.Mesh.Faces.Length;
int mm = Object.Mesh.Materials.Length;
int mv = Object.Mesh.Vertices.Length;
Array.Resize<World.MeshFace>(ref Object.Mesh.Faces, mf + nFaces);
Array.Resize<World.MeshMaterial>(ref Object.Mesh.Materials, mm + Materials.Length);
Array.Resize<World.Vertex>(ref Object.Mesh.Vertices, mv + Vertices.Length);
for (int j = 0; j < Materials.Length; j++) {
bool emissive = Materials[j].emissiveColor.R != 0 | Materials[j].emissiveColor.G != 0 | Materials[j].emissiveColor.B != 0;
bool transparent;
if (Materials[j].TextureFilename != null) {
TextureManager.TextureWrapMode WrapX, WrapY;
if (ForceTextureRepeatX) {
WrapX = TextureManager.TextureWrapMode.Repeat;
} else {
WrapX = TextureManager.TextureWrapMode.ClampToEdge;
}
if (ForceTextureRepeatY) {
WrapY = TextureManager.TextureWrapMode.Repeat;
} else {
WrapY = TextureManager.TextureWrapMode.ClampToEdge;
}
if (WrapX != TextureManager.TextureWrapMode.Repeat | WrapY != TextureManager.TextureWrapMode.Repeat) {
for (int k = 0; k < nFaces; k++) {
for (int h = 0; h < Faces[k].Length; h++) {
if (Vertices[Faces[k][h]].TextureCoordinates.X < 0.0 | Vertices[Faces[k][h]].TextureCoordinates.X > 1.0) {
WrapX = TextureManager.TextureWrapMode.Repeat;
}
if (Vertices[Faces[k][h]].TextureCoordinates.Y < 0.0 | Vertices[Faces[k][h]].TextureCoordinates.Y > 1.0) {
WrapY = TextureManager.TextureWrapMode.Repeat;
}
}
}
}
int tday = TextureManager.RegisterTexture(Materials[j].TextureFilename, new World.ColorRGB(0, 0, 0), 1, TextureManager.TextureLoadMode.Normal, WrapX, WrapY, LoadMode != ObjectManager.ObjectLoadMode.Normal, 0, 0, 0, 0);
Object.Mesh.Materials[mm + j].DaytimeTextureIndex = tday;
transparent = true;
} else {
Object.Mesh.Materials[mm + j].DaytimeTextureIndex = -1;
transparent = false;
}
Object.Mesh.Materials[mm + j].Flags = (byte)((transparent ? World.MeshMaterial.TransparentColorMask : 0) | (emissive ? World.MeshMaterial.EmissiveColorMask : 0));
Object.Mesh.Materials[mm + j].Color = Materials[j].faceColor;
Object.Mesh.Materials[mm + j].TransparentColor = new World.ColorRGB(0, 0, 0);
Object.Mesh.Materials[mm + j].EmissiveColor = Materials[j].emissiveColor;
Object.Mesh.Materials[mm + j].NighttimeTextureIndex = -1;
Object.Mesh.Materials[mm + j].BlendMode = World.MeshMaterialBlendMode.Normal;
Object.Mesh.Materials[mm + j].GlowAttenuationData = 0;
}
for (int j = 0; j < nFaces; j++) {
Object.Mesh.Faces[mf + j].Material = (ushort)FaceMaterials[j];
Object.Mesh.Faces[mf + j].Vertices = new World.MeshFaceVertex[Faces[j].Length];
for (int k = 0; k < Faces[j].Length; k++) {
Object.Mesh.Faces[mf + j].Vertices[mv + k] = new World.MeshFaceVertex(mv + Faces[j][k], FaceNormals[j][k]);
}
}
for (int j = 0; j < Vertices.Length; j++) {
Object.Mesh.Vertices[mv + j] = Vertices[j];
}
break;
}
case "Header":
break;
default:
// unknown
Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported template " + f.Name + " encountered in x object file " + FileName);
break;
}
}
// return
World.CreateNormals(ref Object.Mesh);
return true;
}