예제 #1
0
        private static StringBuilder CreateObjGeometry(List <Dictionary <string, List <WorldVertex[]> > > geometryByTexture, ref WavefrontExportSettings data)
        {
            StringBuilder obj = new StringBuilder();
            Vector2D      offset;
            const string  vertexFormatter = "{0} {2} {1}\n";

            Dictionary <Vector3D, int> uniqueVerts   = new Dictionary <Vector3D, int>();
            Dictionary <Vector3D, int> uniqueNormals = new Dictionary <Vector3D, int>();
            Dictionary <PointF, int>   uniqueUVs     = new Dictionary <PointF, int>();

            var vertexDataByTexture = new Dictionary <string, Dictionary <WorldVertex, VertexIndices> >(StringComparer.Ordinal);
            int pc  = 0;
            int nc  = 0;
            int uvc = 0;

            Vector3D tl = new Vector3D(double.MaxValue, double.MinValue, double.MinValue);
            Vector3D br = new Vector3D(double.MinValue, double.MaxValue, double.MaxValue);

            //optimize geometry
            foreach (Dictionary <string, List <WorldVertex[]> > dictionary in geometryByTexture)
            {
                foreach (KeyValuePair <string, List <WorldVertex[]> > group in dictionary)
                {
                    Dictionary <WorldVertex, VertexIndices> vertsData = new Dictionary <WorldVertex, VertexIndices>();
                    foreach (WorldVertex[] verts in group.Value)
                    {
                        //vertex normals. biwa not sure why I need to invert the normal, but it seems to be necessary
                        Vector3D n = new Vector3D(verts[0].nx, verts[0].ny, verts[0].nz).GetNormal() * -1;
                        int      ni;
                        if (uniqueNormals.ContainsKey(n))
                        {
                            ni = uniqueNormals[n];
                        }
                        else
                        {
                            uniqueNormals.Add(n, ++nc);
                            ni = nc;
                        }

                        foreach (WorldVertex v in verts)
                        {
                            if (vertsData.ContainsKey(v))
                            {
                                continue;
                            }
                            VertexIndices indices = new VertexIndices();
                            indices.NormalIndex = ni;

                            //vertex coords
                            Vector3D vc = new Vector3D(v.x, v.y, v.z);
                            if (uniqueVerts.ContainsKey(vc))
                            {
                                indices.PositionIndex = uniqueVerts[vc];
                            }
                            else
                            {
                                uniqueVerts.Add(vc, ++pc);
                                indices.PositionIndex = pc;
                            }

                            //uv
                            PointF uv = new PointF(v.u, v.v);
                            if (uniqueUVs.ContainsKey(uv))
                            {
                                indices.UVIndex = uniqueUVs[uv];
                            }
                            else
                            {
                                uniqueUVs.Add(uv, ++uvc);
                                indices.UVIndex = uvc;
                            }

                            vertsData.Add(v, indices);
                        }
                    }

                    if (vertsData.Count > 0)
                    {
                        if (vertexDataByTexture.ContainsKey(group.Key))
                        {
                            foreach (KeyValuePair <WorldVertex, VertexIndices> g in vertsData)
                            {
                                vertexDataByTexture[group.Key].Add(g.Key, g.Value);
                            }
                        }
                        else
                        {
                            vertexDataByTexture.Add(group.Key, vertsData);
                        }
                    }
                }
            }

            // Get the dimensions of the model
            foreach (Dictionary <WorldVertex, VertexIndices> vdata in vertexDataByTexture.Values)
            {
                foreach (WorldVertex wv in vdata.Keys)
                {
                    if (wv.x < tl.x)
                    {
                        tl.x = wv.x;
                    }
                    if (wv.x > br.x)
                    {
                        br.x = wv.x;
                    }
                    if (wv.y > tl.y)
                    {
                        tl.y = wv.y;
                    }
                    if (wv.y < br.y)
                    {
                        br.y = wv.y;
                    }
                    if (wv.z > tl.z)
                    {
                        tl.z = wv.z;
                    }
                    if (wv.z < br.z)
                    {
                        br.z = wv.z;
                    }
                }
            }

            data.Radius = br.x - tl.x > tl.y - br.y ? (int)(tl.y - br.y) / 2 : (int)(br.x - tl.x) / 2;
            data.Height = (int)(tl.z - br.z);

            if (data.CenterModel)
            {
                offset = new Vector2D(tl.x + (br.x - tl.x) / 2.0, tl.y + (br.y - tl.y) / 2.0);
            }
            else
            {
                offset = new Vector2D(0.0, 0.0);
            }

            //write geometry
            //write vertices
            if (data.ExportForGZDoom)
            {
                foreach (KeyValuePair <Vector3D, int> group in uniqueVerts)
                {
                    double z = (group.Key.z - (data.NormalizeLowestVertex ? br.z : 0)) * data.Scale * 1.2f;

                    obj.Append(string.Format(CultureInfo.InvariantCulture, "v " + vertexFormatter, (group.Key.x - offset.x) * data.Scale, -(group.Key.y - offset.y) * data.Scale, z));
                }
            }
            else
            {
                // biwa. Not sure why the x-axis is flipped here, since it will result in wrong normals when using the model directly in GZDoom. For this reason
                // I disabled the flipping above
                foreach (KeyValuePair <Vector3D, int> group in uniqueVerts)
                {
                    double z = (group.Key.z - (data.NormalizeLowestVertex ? br.z : 0)) * data.Scale;

                    obj.Append(string.Format(CultureInfo.InvariantCulture, "v " + vertexFormatter, -(group.Key.x - offset.x) * data.Scale, (group.Key.y - offset.y) * data.Scale, z));
                }
            }

            //write normals
            foreach (KeyValuePair <Vector3D, int> group in uniqueNormals)
            {
                obj.Append(string.Format(CultureInfo.InvariantCulture, "vn " + vertexFormatter, group.Key.x, group.Key.y, group.Key.z));
            }

            //write UV coords
            foreach (KeyValuePair <PointF, int> group in uniqueUVs)
            {
                obj.Append(string.Format(CultureInfo.InvariantCulture, "vt {0} {1}\n", group.Key.X, -group.Key.Y));
            }

            // GZDoom ignores the material lib, so don't add it if the model is for GZDoom
            if (!data.ExportForGZDoom)
            {
                obj.Append("mtllib ").Append(data.ObjName + ".mtl").Append("\n");
            }

            //write materials and surface indices
            foreach (Dictionary <string, List <WorldVertex[]> > dictionary in geometryByTexture)
            {
                foreach (KeyValuePair <string, List <WorldVertex[]> > group in dictionary)
                {
                    //material
                    obj.Append("usemtl ").Append(group.Key).Append("\n");

                    foreach (WorldVertex[] verts in group.Value)
                    {
                        //surface indices
                        obj.Append("f");
                        foreach (WorldVertex v in verts)
                        {
                            VertexIndices vi = vertexDataByTexture[group.Key][v];
                            obj.Append(" " + vi.PositionIndex + "/" + vi.UVIndex + "/" + vi.NormalIndex);
                        }
                        obj.Append("\n");
                    }
                }
            }

            return(obj);
        }
예제 #2
0
        private static void CreateObjFromSelection(ICollection <Sector> sectors, ref WavefrontExportSettings data)
        {
            BaseVisualMode mode = new BaseVisualMode();
            bool           renderingEffectsDisabled = false;

            if (!General.Settings.EnhancedRenderingEffects)
            {
                renderingEffectsDisabled = true;
                mode.ToggleEnhancedRendering();
            }

            mode.RebuildElementData();

            List <BaseVisualSector> visualSectors = new List <BaseVisualSector>();

            //create visual geometry
            foreach (Sector s in sectors)
            {
                bool addvs = true;

                // Check if the sector has, or shares a line with a 3D floor control sector, and ignore it if necessary
                if (data.ExportForGZDoom && data.IgnoreControlSectors)
                {
                    foreach (Sidedef sd in s.Sidedefs)
                    {
                        if (sd.Line.Action == 160)
                        {
                            addvs = false;
                            break;
                        }
                    }
                }

                if (addvs)
                {
                    BaseVisualSector bvs = mode.CreateBaseVisualSector(s);
                    if (bvs != null)
                    {
                        visualSectors.Add(bvs);
                    }
                }
            }

            if (visualSectors.Count == 0)
            {
                General.ErrorLogger.Add(ErrorType.Error, "OBJ Exporter: no visual sectors to export!");
                return;
            }

            //sort geometry
            List <Dictionary <string, List <WorldVertex[]> > > geometryByTexture = SortGeometry(visualSectors, data.SkipTextures, !data.ExportForGZDoom);

            //restore vm settings
            if (renderingEffectsDisabled)
            {
                mode.ToggleEnhancedRendering();
            }
            mode.Dispose();

            //create obj
            StringBuilder obj = CreateObjGeometry(geometryByTexture, ref data);

            if (obj.Length == 0)
            {
                General.ErrorLogger.Add(ErrorType.Error, "OBJ Exporter: failed to create geometry!");
                return;
            }

            //add header
            obj.Insert(0, "o " + General.Map.Options.LevelName + Environment.NewLine);             //name
            obj.Insert(0, "# Created by Ultimate Doom Builder " + Application.ProductVersion + Environment.NewLine + Environment.NewLine);
            obj.Insert(0, "# " + General.Map.FileTitle + ", map " + General.Map.Options.LevelName + Environment.NewLine);
            data.Obj = obj.ToString();

            string[] textures = new string[geometryByTexture[0].Keys.Count];
            geometryByTexture[0].Keys.CopyTo(textures, 0);
            Array.Sort(textures);
            data.Textures = textures;

            string[] flats = new string[geometryByTexture[1].Keys.Count];
            geometryByTexture[1].Keys.CopyTo(flats, 0);
            Array.Sort(flats);
            data.Flats = flats;

            data.Valid = true;
        }
예제 #3
0
        public void Export(ICollection <Sector> sectors, WavefrontExportSettings settings)
        {
            CreateObjFromSelection(sectors, ref settings);

            if (!settings.Valid)
            {
                General.Interface.DisplayStatus(StatusType.Warning, "OBJ creation failed. Check 'Errors and Warnings' window for details.");
                return;
            }

            // Export Textures, but only of it's not exporting for GZDoom
            if (settings.ExportTextures && !settings.ExportForGZDoom)
            {
                //save all used textures
                if (settings.Textures != null)
                {
                    foreach (string s in settings.Textures)
                    {
                        if (s == DEFAULT)
                        {
                            continue;
                        }
                        if (General.Map.Data.GetTextureExists(s))
                        {
                            ImageData id = General.Map.Data.GetTextureImage(s);
                            if (id.Width == 0 || id.Height == 0)
                            {
                                General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture \"" + s + "\" has invalid size (" + id.Width + "x" + id.Height + ")!");
                                continue;
                            }

                            Bitmap bmp = id.ExportBitmap();
                            lock (bmp)
                            {
                                string filepath = Path.Combine(settings.ObjPath, Path.GetDirectoryName(s), Path.GetFileNameWithoutExtension(s) + ".png");

                                // Make sure the directory is there
                                Directory.CreateDirectory(Path.GetDirectoryName(filepath));

                                bmp.Save(filepath, ImageFormat.Png);
                            }
                        }
                        else
                        {
                            General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture \"" + s + "\" does not exist!");
                        }
                    }
                }

                if (settings.Flats != null)
                {
                    foreach (string s in settings.Flats)
                    {
                        if (s == DEFAULT)
                        {
                            continue;
                        }
                        if (General.Map.Data.GetFlatExists(s))
                        {
                            ImageData id = General.Map.Data.GetFlatImage(s);
                            if (id.Width == 0 || id.Height == 0)
                            {
                                General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat \"" + s + "\" has invalid size (" + id.Width + "x" + id.Height + ")!");
                                continue;
                            }

                            Bitmap bmp = id.ExportBitmap();

                            // Handle duplicate names
                            string flatname = s;
                            if (settings.Textures != null && Array.IndexOf(settings.Textures, s) != -1)
                            {
                                flatname += "_FLAT";
                            }

                            lock (bmp)
                            {
                                bmp.Save(Path.Combine(settings.ObjPath, Path.GetFileNameWithoutExtension(flatname) + ".PNG"), ImageFormat.Png);
                            }
                        }
                        else
                        {
                            General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat \"" + s + "\" does not exist!");
                        }
                    }
                }
            }

            //write obj
            string savePath;

            if (settings.ExportForGZDoom)
            {
                savePath = Path.Combine(settings.ModelPath, settings.ActorName + ".obj");
            }
            else
            {
                savePath = Path.Combine(settings.ObjPath, settings.ObjName + ".obj");
            }

            // Make sure the directory is there
            Directory.CreateDirectory(Path.GetDirectoryName(savePath));

            using (StreamWriter sw = new StreamWriter(savePath, false))
                sw.Write(settings.Obj);

            //create mtl
            StringBuilder mtl = new StringBuilder();

            mtl.Append("# MTL for " + General.Map.FileTitle + ", map " + General.Map.Options.LevelName + Environment.NewLine);
            mtl.Append("# Created by Ultimate Doom Builder " + Application.ProductVersion + Environment.NewLine + Environment.NewLine);

            if (settings.Textures != null)
            {
                foreach (string s in settings.Textures)
                {
                    if (s == DEFAULT)
                    {
                        continue;
                    }

                    string filepath = Path.Combine(settings.ObjPath, Path.GetDirectoryName(s), Path.GetFileNameWithoutExtension(s) + ".png");

                    mtl.Append("newmtl " + s + Environment.NewLine);
                    mtl.Append("Kd 1.0 1.0 1.0" + Environment.NewLine);
                    if (settings.ExportTextures)
                    {
                        mtl.Append("map_Kd " + filepath + Environment.NewLine);
                    }
                    mtl.Append(Environment.NewLine);
                }
            }

            if (settings.Flats != null)
            {
                foreach (string s in settings.Flats)
                {
                    if (s == DEFAULT)
                    {
                        continue;
                    }
                    mtl.Append("newmtl " + s + Environment.NewLine);
                    mtl.Append("Kd 1.0 1.0 1.0" + Environment.NewLine);
                    if (settings.ExportTextures)
                    {
                        // Handle duplicate names
                        string flatsuffix = string.Empty;
                        if (settings.Textures != null && Array.IndexOf(settings.Textures, s) != -1)
                        {
                            flatsuffix = "_FLAT";
                        }

                        string filepath = Path.Combine(settings.ObjPath, Path.GetDirectoryName(s), Path.GetFileNameWithoutExtension(s) + flatsuffix + ".png");

                        mtl.Append("map_Kd " + Path.Combine(settings.ObjPath, filepath) + Environment.NewLine);
                    }
                    mtl.Append(Environment.NewLine);
                }
            }

            if (!settings.ExportForGZDoom)
            {
                // Make sure the directory is there
                Directory.CreateDirectory(Path.GetDirectoryName(savePath));

                string mtlPath = Path.Combine(Path.GetDirectoryName(savePath), Path.GetFileNameWithoutExtension(savePath) + ".mtl");

                // Write mtl (only if not exporting for GZDoom, since it will be ignored anyway
                using (StreamWriter sw = new StreamWriter(mtlPath, false))
                    sw.Write(mtl.ToString());
            }
            else
            {
                // Create ZScript or DECORATE
                Stream stream;
                string path = Path.Combine(settings.ActorPath, settings.ActorName);

                if (settings.ZScript)
                {
                    stream = BuilderPlug.Me.GetResourceStream("ObjExportZScriptTemplate.txt");
                    path  += ".zs";
                }
                else
                {
                    stream = BuilderPlug.Me.GetResourceStream("ObjExportDecorateTemplate.txt");
                    path  += ".txt";
                }

                using (StreamReader reader = new StreamReader(stream, Encoding.ASCII))
                {
                    string template = reader.ReadToEnd();

                    template = template.Replace("{ActorName}", settings.ActorName);
                    template = template.Replace("{Sprite}", settings.Sprite);
                    template = template.Replace("{FlagNoGravity}", settings.NoGravity ? "+NOGRAVITY" : "");
                    template = template.Replace("{FlagSpawnOnCeiling}", settings.SpawnOnCeiling ? "+SPAWNCEILING" : "");
                    template = template.Replace("{FlagSolid}", settings.Solid ? "+SOLID" : "");
                    template = template.Replace("{FlagInvulnerable}", settings.Solid ? "+INVULNERABLE" : "");
                    template = template.Replace("{FlagNoDamage}", settings.Solid ? "+NODAMAGE" : "");
                    template = template.Replace("{FlagShootable}", settings.Solid ? "+SHOOTABLE" : "");
                    template = template.Replace("{FlagNotAutoAimed}", settings.Solid ? "+NOTAUTOAIMED" : "");
                    template = template.Replace("{FlagNeverTarget}", settings.Solid ? "+NEVERTARGET" : "");
                    template = template.Replace("{FlagDontThrust}", settings.Solid ? "+DONTTHRUST" : "");
                    template = template.Replace("{PropRadius}", settings.Radius.ToString());
                    template = template.Replace("{PropHeight}", settings.Height.ToString());

                    // Make sure the directory is there
                    Directory.CreateDirectory(Path.GetDirectoryName(path));

                    using (StreamWriter sw = new StreamWriter(path, false))
                        sw.Write(template);
                }

                // Create MODELDEF
                stream = BuilderPlug.Me.GetResourceStream("ObjExportModeldefTemplate.txt");

                using (StreamReader reader = new StreamReader(stream, Encoding.ASCII))
                {
                    path = Path.Combine(settings.BasePath, "modeldef." + settings.ActorName + ".txt");
                    string template = reader.ReadToEnd();

                    // The path to the model is relative to the base path, so generate the base path
                    string basepath  = settings.BasePath.Trim();
                    string modelpath = settings.ModelPath.Trim();

                    // Make sue there's a directory separator at the end of the paths, otherwise it'll not work correctly
                    if (!basepath.EndsWith(Path.DirectorySeparatorChar.ToString()))
                    {
                        basepath += Path.DirectorySeparatorChar;
                    }

                    if (!modelpath.EndsWith(Path.DirectorySeparatorChar.ToString()))
                    {
                        modelpath += Path.DirectorySeparatorChar;
                    }

                    Uri baseUri  = new Uri(basepath);
                    Uri modelUri = new Uri(modelpath);

                    Uri    relativeUri  = baseUri.MakeRelativeUri(modelUri);
                    string relativepath = Uri.UnescapeDataString(relativeUri.OriginalString);

                    template = template.Replace("{ActorName}", settings.ActorName);
                    template = template.Replace("{ModelPath}", relativepath);
                    template = template.Replace("{Sprite}", settings.Sprite);

                    // Make sure the directory is there
                    Directory.CreateDirectory(Path.GetDirectoryName(path));

                    using (StreamWriter sw = new StreamWriter(path, false))
                        sw.Write(template);
                }
            }

            //done
            General.Interface.DisplayStatus(StatusType.Warning, "Geometry exported to \"" + savePath);
        }
        public void Export(ICollection <Sector> sectors, WavefrontExportSettings settings)
        {
            CreateObjFromSelection(sectors, ref settings);

            if (!settings.Valid)
            {
                General.Interface.DisplayStatus(StatusType.Warning, "OBJ creation failed. Check 'Errors and Warnings' window for details.");
                return;
            }

            if (settings.ExportTextures)
            {
                //save all used textures
                if (settings.Textures != null)
                {
                    foreach (string s in settings.Textures)
                    {
                        if (s == DEFAULT)
                        {
                            continue;
                        }
                        if (General.Map.Data.GetTextureExists(s))
                        {
                            ImageData id = General.Map.Data.GetTextureImage(s);
                            if (id.Width == 0 || id.Height == 0)
                            {
                                General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture \"" + s + "\" has invalid size (" + id.Width + "x" + id.Height + ")!");
                                continue;
                            }

                            Bitmap bmp = id.ExportBitmap();
                            lock (bmp)
                            {
                                bmp.Save(Path.Combine(settings.ObjPath, Path.GetFileNameWithoutExtension(s) + ".PNG"), ImageFormat.Png);
                            }
                        }
                        else
                        {
                            General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture \"" + s + "\" does not exist!");
                        }
                    }
                }

                if (settings.Flats != null)
                {
                    foreach (string s in settings.Flats)
                    {
                        if (s == DEFAULT)
                        {
                            continue;
                        }
                        if (General.Map.Data.GetFlatExists(s))
                        {
                            ImageData id = General.Map.Data.GetFlatImage(s);
                            if (id.Width == 0 || id.Height == 0)
                            {
                                General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat \"" + s + "\" has invalid size (" + id.Width + "x" + id.Height + ")!");
                                continue;
                            }

                            Bitmap bmp = id.ExportBitmap();

                            // Handle duplicate names
                            string flatname = s;
                            if (settings.Textures != null && Array.IndexOf(settings.Textures, s) != -1)
                            {
                                flatname += "_FLAT";
                            }

                            lock (bmp)
                            {
                                bmp.Save(Path.Combine(settings.ObjPath, Path.GetFileNameWithoutExtension(flatname) + ".PNG"), ImageFormat.Png);
                            }
                        }
                        else
                        {
                            General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat \"" + s + "\" does not exist!");
                        }
                    }
                }
            }

            //write obj
            string savePath = Path.Combine(settings.ObjPath, settings.ObjName);

            using (StreamWriter sw = new StreamWriter(savePath + ".obj", false))
                sw.Write(settings.Obj);

            //create mtl
            StringBuilder mtl = new StringBuilder();

            mtl.Append("# MTL for " + General.Map.FileTitle + ", map " + General.Map.Options.LevelName + Environment.NewLine);
            mtl.Append("# Created by Ultimate Doom Builder " + Application.ProductVersion + Environment.NewLine + Environment.NewLine);

            if (settings.Textures != null)
            {
                foreach (string s in settings.Textures)
                {
                    if (s == DEFAULT)
                    {
                        continue;
                    }
                    mtl.Append("newmtl " + s.ToUpperInvariant() + Environment.NewLine);
                    mtl.Append("Kd 1.0 1.0 1.0" + Environment.NewLine);
                    if (settings.ExportTextures)
                    {
                        mtl.Append("map_Kd " + Path.Combine(settings.ObjPath, s.ToUpperInvariant() + ".PNG") + Environment.NewLine);
                    }
                    mtl.Append(Environment.NewLine);
                }
            }

            if (settings.Flats != null)
            {
                foreach (string s in settings.Flats)
                {
                    if (s == DEFAULT)
                    {
                        continue;
                    }
                    mtl.Append("newmtl " + s.ToUpperInvariant() + Environment.NewLine);
                    mtl.Append("Kd 1.0 1.0 1.0" + Environment.NewLine);
                    if (settings.ExportTextures)
                    {
                        // Handle duplicate names
                        string flatname = s;
                        if (settings.Textures != null && Array.IndexOf(settings.Textures, s) != -1)
                        {
                            flatname += "_FLAT";
                        }

                        mtl.Append("map_Kd " + Path.Combine(settings.ObjPath, flatname.ToUpperInvariant() + ".PNG") + Environment.NewLine);
                    }
                    mtl.Append(Environment.NewLine);
                }
            }

            //write mtl
            using (StreamWriter sw = new StreamWriter(savePath + ".mtl", false))
                sw.Write(mtl.ToString());

            //done
            General.Interface.DisplayStatus(StatusType.Warning, "Geometry exported to \"" + savePath + ".obj\"");
        }
        private static StringBuilder CreateObjGeometry(List <Dictionary <string, List <WorldVertex[]> > > geometryByTexture, WavefrontExportSettings data)
        {
            StringBuilder obj             = new StringBuilder();
            const string  vertexFormatter = "{0} {2} {1}\n";

            Dictionary <Vector3D, int> uniqueVerts   = new Dictionary <Vector3D, int>();
            Dictionary <Vector3D, int> uniqueNormals = new Dictionary <Vector3D, int>();
            Dictionary <PointF, int>   uniqueUVs     = new Dictionary <PointF, int>();

            var vertexDataByTexture = new Dictionary <string, Dictionary <WorldVertex, VertexIndices> >(StringComparer.Ordinal);
            int pc  = 0;
            int nc  = 0;
            int uvc = 0;

            //optimize geometry
            foreach (Dictionary <string, List <WorldVertex[]> > dictionary in geometryByTexture)
            {
                foreach (KeyValuePair <string, List <WorldVertex[]> > group in dictionary)
                {
                    Dictionary <WorldVertex, VertexIndices> vertsData = new Dictionary <WorldVertex, VertexIndices>();
                    foreach (WorldVertex[] verts in group.Value)
                    {
                        //vertex normals
                        Vector3D n = new Vector3D(verts[0].nx, verts[0].ny, verts[0].nz).GetNormal();
                        int      ni;
                        if (uniqueNormals.ContainsKey(n))
                        {
                            ni = uniqueNormals[n];
                        }
                        else
                        {
                            uniqueNormals.Add(n, ++nc);
                            ni = nc;
                        }

                        foreach (WorldVertex v in verts)
                        {
                            if (vertsData.ContainsKey(v))
                            {
                                continue;
                            }
                            VertexIndices indices = new VertexIndices();
                            indices.NormalIndex = ni;

                            //vertex coords
                            Vector3D vc = new Vector3D(v.x, v.y, v.z);
                            if (uniqueVerts.ContainsKey(vc))
                            {
                                indices.PositionIndex = uniqueVerts[vc];
                            }
                            else
                            {
                                uniqueVerts.Add(vc, ++pc);
                                indices.PositionIndex = pc;
                            }

                            //uv
                            PointF uv = new PointF(v.u, v.v);
                            if (uniqueUVs.ContainsKey(uv))
                            {
                                indices.UVIndex = uniqueUVs[uv];
                            }
                            else
                            {
                                uniqueUVs.Add(uv, ++uvc);
                                indices.UVIndex = uvc;
                            }

                            vertsData.Add(v, indices);
                        }
                    }

                    if (vertsData.Count > 0)
                    {
                        if (vertexDataByTexture.ContainsKey(group.Key))
                        {
                            foreach (KeyValuePair <WorldVertex, VertexIndices> g in vertsData)
                            {
                                vertexDataByTexture[group.Key].Add(g.Key, g.Value);
                            }
                        }
                        else
                        {
                            vertexDataByTexture.Add(group.Key, vertsData);
                        }
                    }
                }
            }

            //write geometry
            //write vertices
            if (data.FixScale)
            {
                foreach (KeyValuePair <Vector3D, int> group in uniqueVerts)
                {
                    obj.Append(string.Format(CultureInfo.InvariantCulture, "v " + vertexFormatter, -group.Key.x * data.Scale, group.Key.y * data.Scale, group.Key.z * data.Scale * 1.2f));
                }
            }
            else
            {
                foreach (KeyValuePair <Vector3D, int> group in uniqueVerts)
                {
                    obj.Append(string.Format(CultureInfo.InvariantCulture, "v " + vertexFormatter, -group.Key.x * data.Scale, group.Key.y * data.Scale, group.Key.z * data.Scale));
                }
            }

            //write normals
            foreach (KeyValuePair <Vector3D, int> group in uniqueNormals)
            {
                obj.Append(string.Format(CultureInfo.InvariantCulture, "vn " + vertexFormatter, group.Key.x, group.Key.y, group.Key.z));
            }

            //write UV coords
            foreach (KeyValuePair <PointF, int> group in uniqueUVs)
            {
                obj.Append(string.Format(CultureInfo.InvariantCulture, "vt {0} {1}\n", group.Key.X, -group.Key.Y));
            }

            //write material library
            obj.Append("mtllib ").Append(data.ObjName + ".mtl").Append("\n");

            //write materials and surface indices
            foreach (Dictionary <string, List <WorldVertex[]> > dictionary in geometryByTexture)
            {
                foreach (KeyValuePair <string, List <WorldVertex[]> > group in dictionary)
                {
                    //material
                    obj.Append("usemtl ").Append(group.Key).Append("\n");

                    foreach (WorldVertex[] verts in group.Value)
                    {
                        //surface indices
                        obj.Append("f");
                        foreach (WorldVertex v in verts)
                        {
                            VertexIndices vi = vertexDataByTexture[group.Key][v];
                            obj.Append(" " + vi.PositionIndex + "/" + vi.UVIndex + "/" + vi.NormalIndex);
                        }
                        obj.Append("\n");
                    }
                }
            }

            return(obj);
        }
예제 #6
0
        private static void CreateObjFromSelection(ICollection <Sector> sectors, ref WavefrontExportSettings data)
        {
            BaseVisualMode mode = new BaseVisualMode();
            bool           renderingEffectsDisabled = false;

            if (!General.Settings.GZDoomRenderingEffects)
            {
                renderingEffectsDisabled = true;
                mode.ToggleGZDoomRenderingEffects();
            }

            mode.RebuildElementData();

            List <BaseVisualSector> visualSectors = new List <BaseVisualSector>();

            //create visual geometry
            foreach (Sector s in sectors)
            {
                BaseVisualSector bvs = mode.CreateBaseVisualSector(s);
                if (bvs != null)
                {
                    visualSectors.Add(bvs);
                }
            }

            if (visualSectors.Count == 0)
            {
                General.ErrorLogger.Add(ErrorType.Error, "OBJ Exporter: no visual sectors to export!");
                return;
            }

            //sort geometry
            List <Dictionary <string, List <WorldVertex[]> > > geometryByTexture = SortGeometry(visualSectors);

            //restore vm settings
            if (renderingEffectsDisabled)
            {
                mode.ToggleGZDoomRenderingEffects();
            }
            mode.Dispose();

            //create obj
            StringBuilder obj = CreateObjGeometry(geometryByTexture, data);

            if (obj.Length == 0)
            {
                General.ErrorLogger.Add(ErrorType.Error, "OBJ Exporter: failed to create geometry!");
                return;
            }

            //add header
            obj.Insert(0, "o " + General.Map.Options.LevelName + Environment.NewLine);             //name
            obj.Insert(0, "# Created by 3DGE Builder " + Application.ProductVersion + Environment.NewLine + Environment.NewLine);
            obj.Insert(0, "# " + General.Map.FileTitle + ", map " + General.Map.Options.LevelName + Environment.NewLine);
            data.Obj = obj.ToString();

            string[] textures = new string[geometryByTexture[0].Keys.Count];
            geometryByTexture[0].Keys.CopyTo(textures, 0);
            Array.Sort(textures);
            data.Textures = textures;

            string[] flats = new string[geometryByTexture[1].Keys.Count];
            geometryByTexture[1].Keys.CopyTo(flats, 0);
            Array.Sort(flats);
            data.Flats = flats;

            data.Valid = true;
        }