corrade-vassal – Rev 1

Subversion Repositories:
Rev:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using OpenMetaverse;
using OpenMetaverse.Rendering;

namespace PrimWorkshop
{
    public static class MeshToOBJ
    {
        public static bool MeshesToOBJ(List<FacetedMesh> meshes, string filename)
        {
            StringBuilder obj = new StringBuilder();
            StringBuilder mtl = new StringBuilder();

            FileInfo objFileInfo = new FileInfo(filename);

            string mtlFilename = objFileInfo.FullName.Substring(objFileInfo.DirectoryName.Length + 1,
                objFileInfo.FullName.Length - (objFileInfo.DirectoryName.Length + 1) - 4) + ".mtl";

            obj.AppendLine("# Created by libOpenMetaverse");
            obj.AppendLine("mtllib ./" + mtlFilename);
            obj.AppendLine();

            mtl.AppendLine("# Created by libOpenMetaverse");
            mtl.AppendLine();

            for (int i = 0; i < meshes.Count; i++)
            {
                FacetedMesh mesh = meshes[i];

                for (int j = 0; j < mesh.Faces.Count; j++)
                {
                    Face face = mesh.Faces[j];

                    if (face.Vertices.Count > 2)
                    {
                        string mtlName = String.Format("material{0}-{1}", i, face.ID);
                        Primitive.TextureEntryFace tex = face.TextureFace;
                        string texName = tex.TextureID.ToString() + ".tga";

                        // FIXME: Convert the source to TGA (if needed) and copy to the destination

                        float shiny = 0.00f;
                        switch (tex.Shiny)
                        {
                            case Shininess.High:
                                shiny = 1.00f;
                                break;
                            case Shininess.Medium:
                                shiny = 0.66f;
                                break;
                            case Shininess.Low:
                                shiny = 0.33f;
                                break;
                        }

                        mtl.AppendLine("newmtl " + mtlName);
                        mtl.AppendFormat("Ka {0} {1} {2}{3}", tex.RGBA.R, tex.RGBA.G, tex.RGBA.B, Environment.NewLine);
                        mtl.AppendFormat("Kd {0} {1} {2}{3}", tex.RGBA.R, tex.RGBA.G, tex.RGBA.B, Environment.NewLine);
                        //mtl.AppendFormat("Ks {0} {1} {2}{3}");
                        mtl.AppendLine("Tr " + tex.RGBA.A);
                        mtl.AppendLine("Ns " + shiny);
                        mtl.AppendLine("illum 1");
                        if (tex.TextureID != UUID.Zero && tex.TextureID != Primitive.TextureEntry.WHITE_TEXTURE)
                            mtl.AppendLine("map_Kd ./" + texName);
                        mtl.AppendLine();

                        #region Vertices

                        for (int k = 0; k < face.Vertices.Count; k++)
                        {
                            Vertex vertex = face.Vertices[k];
                            Vector3 pos = vertex.Position;
                            Vector3 norm = vertex.Normal;
                            Vector2 texc = vertex.TexCoord;

                            // Apply scaling
                            pos *= mesh.Prim.Scale;

                            // Apply rotation
                            pos *= mesh.Prim.Rotation;

                            // The root prim position is sim-relative, while child prim positions are
                            // parent-relative. We want to apply parent-relative translations but not
                            // sim-relative ones
                            if (mesh.Prim.ParentID != 0)
                                pos += mesh.Prim.Position;

                            // Normal
                            if (vertex.Normal.IsFinite())
                                obj.AppendFormat("vn {0} {1} {2}{3}",
                                    norm.X.ToString("N6"),
                                    norm.Y.ToString("N6"),
                                    norm.Z.ToString("N6"),
                                    Environment.NewLine);
                            else
                                obj.AppendLine("vn 0.0 1.0 0.0");

                            // Texture Coord
                            obj.AppendFormat("vt {0} {1}{2}",
                                texc.X.ToString("N6"),
                                texc.Y.ToString("N6"),
                                Environment.NewLine);

                            // Position
                            obj.AppendFormat("v {0} {1} {2}{3}",
                                pos.X.ToString("N6"),
                                pos.Y.ToString("N6"),
                                pos.Z.ToString("N6"),
                                Environment.NewLine);
                        }
                        obj.AppendLine();

                        #endregion Vertices
                    }
                }
            }

            int startOffset = 0;

            for (int i = 0; i < meshes.Count; i++)
            {
                FacetedMesh mesh = meshes[i];

                for (int j = 0; j < mesh.Faces.Count; j++)
                {
                    Face face = mesh.Faces[j];

                    if (face.Vertices.Count > 2)
                    {
                        //obj.AppendFormat("g face{0}-{1}{2}", i, face.ID, Environment.NewLine);

                        string mtlName = String.Format("material{0}-{1}", i, face.ID);
                        //obj.AppendLine("usemtl " + mtlName);

                        #region Elements

                        // Write all of the faces (triangles) for this side
                        for (int k = 0; k < face.Indices.Count / 3; k++)
                        {
                            obj.AppendFormat("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}{3}",
                                startOffset + face.Indices[k * 3 + 0] + 1,
                                startOffset + face.Indices[k * 3 + 1] + 1,
                                startOffset + face.Indices[k * 3 + 2] + 1,
                                Environment.NewLine);
                        }

                        obj.AppendFormat("# {0} faces{1}", face.Indices.Count / 3, Environment.NewLine);
                        obj.AppendLine();

                        for (int k = 0; k < face.Vertices.Count; k++)
                            ++startOffset;

                        #endregion Elements
                    }
                }
            }

            try
            {
                File.WriteAllText(filename, obj.ToString());
                File.WriteAllText(mtlFilename, mtl.ToString());
            }
            catch (Exception)
            {
                return false;
            }

            return true;
        }
    }
}