Пример #1
0
        /// <summary>
        /// Read the material data from the specified stream.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <param name="path">The path. This can be null - it is only used for recording diagnostic information.</param>
        /// <param name="loadTextureImages">if set to <c>true</c> [load texture images].</param>
        /// <returns>
        /// The results of the file load.
        /// </returns>
        private static FileLoadResult <List <Material> > Read(TextReader reader, string path, bool loadTextureImages)
        {
            //  The model we are loading is a list of materials. During loading, we'll keep
            //  track of messages that may be useful to consumers.
            var materials = new List <Material>();
            var messages  = new List <Message>();

            //  As we load, we're enriching the data of a Material object.
            Material currentMaterial = null;

            //  Go through each line, keeping track of the line number.
            var    lineNumberCounter = 0;
            string line;

            while ((line = reader.ReadLine()) != null)
            {
                ++lineNumberCounter;

                //  Strip any comments from the line and skip empty lines.
                line = LineData.StripComments(line);
                if (string.IsNullOrWhiteSpace(line))
                {
                    continue;
                }

                //  Try and read the line type and data.
                string lineType, lineData;
                if (LineData.TryReadLineType(line, out lineType, out lineData) == false)
                {
                    continue;
                }

                if (lineType.IsLineType(LineTypeNewMaterial))
                {
                    //  Add a new material to the list, store it as the current one and set the name.
                    currentMaterial = new Material {
                        Name = lineData
                    };
                    materials.Add(currentMaterial);
                }
                else if (currentMaterial != null)
                {
                    if (lineType.IsLineType(LineTypeMaterialAmbient))
                    {
                        currentMaterial.Ambient = ReadColour(lineData);
                    }
                    else if (lineType.IsLineType(LineTypeMaterialDiffuse))
                    {
                        currentMaterial.Diffuse = ReadColour(lineData);
                    }
                    else if (lineType.IsLineType(LineTypeMaterialSpecular))
                    {
                        currentMaterial.Specular = ReadColour(lineData);
                    }
                    else if (lineType.IsLineType(LineTypeMaterialShininess))
                    {
                        currentMaterial.Shininess = float.Parse(lineData);
                    }
                    else if (lineType.IsLineType(LineTypeOpticalDensity))
                    {
                        currentMaterial.OpticalDensity = float.Parse(lineData);
                    }
                    else if (lineType.IsLineType(LineTypeBumpStrength))
                    {
                        currentMaterial.BumpStrength = float.Parse(lineData);
                    }
                    else if (lineType.IsLineType(LineTypeTextureMapAmbient))
                    {
                        currentMaterial.TextureMapAmbient = ReadTextureMap(path, lineNumberCounter, messages, lineData, loadTextureImages);
                    }
                    else if (lineType.IsLineType(LineTypeTextureMapDiffuse))
                    {
                        currentMaterial.TextureMapDiffuse = ReadTextureMap(path, lineNumberCounter, messages, lineData, loadTextureImages);
                    }
                    else if (lineType.IsLineType(LineTypeTextureMapSpecular))
                    {
                        currentMaterial.TextureMapSpecular = ReadTextureMap(path, lineNumberCounter, messages, lineData, loadTextureImages);
                    }
                    else if (lineType.IsLineType(LineTypeTextureMapSpecularHighlight))
                    {
                        currentMaterial.TextureMapSpecularHighlight = ReadTextureMap(path, lineNumberCounter, messages, lineData, loadTextureImages);
                    }
                    else if (lineType.IsLineType(LineTypeTextureMapAlpha))
                    {
                        currentMaterial.TextureMapAlpha = ReadTextureMap(path, lineNumberCounter, messages, lineData, loadTextureImages);
                    }
                    else if (lineType.IsLineType(LineTypeTextureMapBump))
                    {
                        currentMaterial.TextureMapBump = ReadTextureMap(path, lineNumberCounter, messages, lineData, loadTextureImages);
                    }
                    else if (lineType.IsLineType(LineTypeDissolve) || lineType.IsLineType(LineTypeTransparent))
                    {
                        //  Read the transparency.
                        currentMaterial.Transparency = float.Parse(lineData);
                    }
                    else if (lineType.IsLineType(LineTypeIlluminationModel))
                    {
                        currentMaterial.IlluminationModel = int.Parse(lineData);
                    }
                    else if (lineType.IsLineType("Tf"))
                    {
                        currentMaterial.TransmissionFilter = ReadColour(lineData);
                    }
                    else
                    {
                        //  Anything we encounter here we don't understand.
                        messages.Add(new Message(MessageType.Warning, path, lineNumberCounter,
                                                 string.Format("Skipped unknown line type '{0}'.", lineType)));
                    }
                }
                else
                {
                    //  Anything we encounter here we don't understand.
                    messages.Add(new Message(MessageType.Warning, path, lineNumberCounter,
                                             string.Format("Skipped unknown or out of context line type '{0}'.", lineType)));
                }
            }

            //  Return the model and messages as a file load result.
            return(new FileLoadResult <List <Material> >(materials, messages));
        }
Пример #2
0
        /// <summary>
        /// Internally used to reads the scene.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <param name="path">The path.</param>
        /// <param name="loadTextureImages">if set to <c>true</c> [load texture images].</param>
        /// <returns>
        /// The file load result.
        /// </returns>
        private static FileLoadResult <Scene> ReadScene(StreamReader reader, string path, bool loadTextureImages)
        {
            //  Keep track of messages and the raw data we will use to build a scene.
            var    messages     = new List <Message>();
            var    uvs          = new List <Vector2>();
            var    normals      = new List <Vector3>();
            var    vertices     = new List <Vector3>();
            var    interimFaces = new List <InterimFace>();
            var    materials    = new List <Material>();
            var    groups       = new List <Group>();
            string objectName   = null;

            //  State changing data is loaded as we go through the file - once loaded, state changing
            //  data applies to all subsequent elements until it is explicitly changed by introducing
            //  new state changing data.
            Group  currentGroup        = null;
            string currentMaterialName = null;

            //  Read line by line.
            string line;
            int    lineNumberCounter = 0;

            while ((line = reader.ReadLine()) != null)
            {
                ++lineNumberCounter;

                //  Strip any comments from the line and skip empty lines.
                line = LineData.StripComments(line);
                if (string.IsNullOrWhiteSpace(line))
                {
                    continue;
                }

                //  Try and read the line type and data.
                string lineType, lineData;
                if (LineData.TryReadLineType(line, out lineType, out lineData) == false)
                {
                    continue;
                }

                //  Read texture coordinates.
                if (lineType.IsLineType(LineTypeTextureCoordinate))
                {
                    try
                    {
                        //  Split the line data into texture coordinates.
                        var dataStrings = lineData.Split(dataSeparators, StringSplitOptions.RemoveEmptyEntries);

                        //  Add the UV.
                        uvs.Add(new Vector2
                        {
                            X = float.Parse(dataStrings[0]),
                            Y = float.Parse(dataStrings[1])
                        });
                    }
                    catch (Exception exception)
                    {
                        messages.Add(new Message(MessageType.Error, path, lineNumberCounter,
                                                 "There was an error reading the texture coordinate data.", exception));
                    }
                }
                else if (lineType.IsLineType(LineTypeNormalCoordinate))
                {
                    try
                    {
                        //  Split the line data into normal coordinates.
                        var dataStrings = lineData.Split(dataSeparators, StringSplitOptions.RemoveEmptyEntries);
                        normals.Add(new Vector3
                        {
                            X = float.Parse(dataStrings[0]),
                            Y = float.Parse(dataStrings[1]),
                            Z = float.Parse(dataStrings[2])
                        });
                    }
                    catch (Exception exception)
                    {
                        messages.Add(new Message(MessageType.Error, path, lineNumberCounter,
                                                 "There was an error reading the normal data.", exception));
                    }
                }
                else if (lineType.IsLineType(LineTypeVertex))
                {
                    try
                    {
                        //  Split the line data into vertex coordinates.
                        var dataStrings = lineData.Split(dataSeparators, StringSplitOptions.RemoveEmptyEntries);
                        vertices.Add(new Vector3
                        {
                            X = float.Parse(dataStrings[0]),
                            Y = float.Parse(dataStrings[1]),
                            Z = float.Parse(dataStrings[2])
                        });
                    }
                    catch (Exception exception)
                    {
                        messages.Add(new Message(MessageType.Error, path, lineNumberCounter,
                                                 "There was an error reading the vertex data.", exception));
                    }
                }
                else if (lineType.IsLineType(LineTypeFace))
                {
                    try
                    {
                        var indices = new List <Index>();

                        //  Split the line data into index strings.
                        var indexStrings = lineData.Split(dataSeparators, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var indexString in indexStrings)
                        {
                            //  Split the parts.
                            var parts  = indexString.Split(new[] { '/' }, StringSplitOptions.None);
                            var vertex = MapIndex(vertices.Count, int.Parse(parts[0]));
                            var uv     = (parts.Length > 1 && parts[1].Length > 0) ? (int?)MapIndex(uvs.Count, int.Parse(parts[1])) : null;
                            var normal = (parts.Length > 2 && parts[2].Length > 0) ? (int?)MapIndex(normals.Count, int.Parse(parts[2])) : null;
                            indices.Add(new Index
                            {
                                Vertex = vertex,
                                Uv     = uv,
                                Normal = normal
                            });
                        }
                        interimFaces.Add(new InterimFace
                        {
                            materialName = currentMaterialName,
                            indices      = indices,
                            @group       = currentGroup
                        });
                    }
                    catch (Exception exception)
                    {
                        messages.Add(new Message(MessageType.Error, path, lineNumberCounter,
                                                 "There was an error reading the index data.", exception));
                    }
                }
                else if (lineType.IsLineType(LineTypeMaterialLibrary))
                {
                    //  The material file path is the line data.
                    var materialPath = lineData;

                    //  If the path is relative, make it absolute based on the current directory (if we've been passed a path).
                    if (Path.IsPathRooted(lineData) == false && path != null)
                    {
                        materialPath = Path.Combine(Path.GetDirectoryName(path), materialPath);
                    }

                    //  Read the material file.
                    try
                    {
                        var fileLoadResult = FileFormatMtl.Load(GD, materialPath, loadTextureImages);
                        materials.AddRange(fileLoadResult.Model);
                        messages.AddRange(fileLoadResult.Messages);
                    }
                    catch (Exception exception)
                    {
                        messages.Add(new Message(MessageType.Error, path, lineNumberCounter,
                                                 string.Format("Failed to load material file '{0}'.", materialPath), exception));
                    }
                }
                else if (lineType.IsLineType(LineTypeUseMaterial))
                {
                    //  The material name is simply the line data.
                    currentMaterialName = lineData;
                }
                else if (lineType.IsLineType(LineTypeGroup))
                {
                    //  Create a new group.
                    var groupNames = lineData.Split(dataSeparators, StringSplitOptions.RemoveEmptyEntries);
                    currentGroup = new Group(groupNames);
                    groups.Add(currentGroup);
                }
                else if (lineType.IsLineType(LineTypeSmoothingGroup))
                {
                    //  If we have no current group, we cannot set a smoothing group.
                    if (currentGroup == null)
                    {
                        messages.Add(new Message(MessageType.Warning, path, lineNumberCounter,
                                                 string.Format("Cannot set smoothing group '{0}' as the current context has no group.", lineData)));
                    }
                    else
                    {
                        //  The smoothing group is an int, if we can get it.
                        int smoothingGroup;
                        if (int.TryParse(lineData, out smoothingGroup))
                        {
                            currentGroup.SetSmoothingGroup(smoothingGroup);
                        }
                        currentGroup.SetSmoothingGroup(null);
                    }
                }
                else if (lineType.IsLineType(LineTypeObjectName))
                {
                    //  Set the object name, warning if it's already set.
                    if (objectName != null)
                    {
                        messages.Add(new Message(MessageType.Warning, path, lineNumberCounter,
                                                 string.Format("An object name statement to set the name to '{0}' will overwrite the current object name '{1}'.", lineData, objectName)));
                    }
                    objectName = lineData;
                }
                else
                {
                    messages.Add(new Message(MessageType.Warning, path, lineNumberCounter,
                                             string.Format("Skipped unknown line type '{0}'.", lineType)));
                }
            }

            //  Currently we don't have faces, just indexes and material names. But now that we've loaded
            //  the entire file, we can map the material names to the actual materials.
            var ungroupedFaces = new List <Face>();

            foreach (var interimFace in interimFaces)
            {
                //  If we have a material named but not in the set of materials, warn.
                var material = materials.FirstOrDefault(m => m.Name == interimFace.materialName);
                if (material == null)
                {
                    messages.Add(new Message(MessageType.Warning, path, lineNumberCounter,
                                             string.Format("Material '{0}' is referenced for a face, but not included in any material files.", interimFace.materialName)));
                }

                //  If the face is grouped, add it to the group. Otherwise add it to the ungrouped faces.
                var face = new Face(material, interimFace.indices);
                if (interimFace.group != null)
                {
                    interimFace.group.AddFace(face);
                }
                else
                {
                    ungroupedFaces.Add(face);
                }
            }

            return(new FileLoadResult <Scene>(new Scene(vertices, uvs, normals, ungroupedFaces, groups, materials, objectName), messages));
        }