예제 #1
0
        public void LoadWMO()
        {
            WMOReader reader = new WMOReader(basedir);

            reader.LoadWMO(modelPath);

            WMOMaterial[] materials = new WMOMaterial[reader.wmofile.materials.Count()];
            for (int i = 0; i < reader.wmofile.materials.Count(); i++)
            {
                for (int ti = 0; ti < reader.wmofile.textures.Count(); ti++)
                {
                    if (reader.wmofile.textures[ti].startOffset == reader.wmofile.materials[i].texture1)
                    {
                        Texture2D texture;
                        var       blp = new BLPReader(basedir);
                        blp.LoadBLP(reader.wmofile.textures[ti].filename);
                        if (blp.bmp == null)
                        {
                            texture = Texture2D.FromFile <Texture2D>(device, "missingtexture.jpg");
                        }
                        else
                        {
                            MemoryStream s = new MemoryStream();
                            blp.bmp.Save(s, System.Drawing.Imaging.ImageFormat.Png);
                            s.Seek(0, SeekOrigin.Begin);
                            texture = Texture2D.FromMemory <Texture2D>(device, s.ToArray());
                            s.Dispose();
                        }
                        materials[i].materialID = (uint)i;
                        materials[i].filename   = reader.wmofile.textures[ti].filename;
                        materials[i].texture    = texture;
                    }
                }
            }

            WoWWMOGroup[] groups = new WoWWMOGroup[reader.wmofile.header.nGroups];

            for (int i = 0; i < reader.wmofile.header.nGroups; i++)
            {
                groups[i] = LoadGroupWMO(reader.wmofile.group[i]);
            }

            wmo.materials = materials;
            wmo.groups    = groups;
        }
예제 #2
0
        private void Form_WMOExport_Load(object sender, EventArgs e)
        {
            checkBox1.Checked = Managers.ConfigurationManager.WMOExportM2;
            checkBox1.Text    = "Export doodads";

            label1.Hide();

            checkBox2.Text    = "Doodads use global paths";
            checkBox2.Checked = Managers.ConfigurationManager.WMODoodadsGlobalPath;
            checkBox3.Text    = "Doodads placement global paths";
            checkBox3.Checked = Managers.ConfigurationManager.WMODoodadsPlacementGlobalPath;

            button1.Text = "Export";
            this.Text    = filename;

            try
            {
                WMOReader reader = new WMOReader();
                reader.LoadWMO(filename);

                if (reader.wmofile.doodadNames != null)
                {
                    try
                    {
                        for (int i = 0; i < reader.wmofile.doodadNames.Length; i++)
                        {
                            listBox1.Items.Add(reader.wmofile.doodadNames[i].filename.ToLower());
                        }
                    }
                    catch
                    {
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
예제 #3
0
파일: WMO.cs 프로젝트: ser0ja/WoWFormatTest
        public void Compile(string wmoname)
        {
            WMOReader wmoreader = new WMOReader();

            wmoreader.LoadWMO(wmoname);

            WoWFormatLib.Structs.WMO.WMO wmo = wmoreader.wmofile;

            Console.WriteLine(wmoname);

            if (wmo.group.Count() == 0)
            {
                Console.WriteLine("WMO " + wmoname + " has no groups! Skipping..");
                return;
            }

            int wmo_minx = 999999999;
            int wmo_maxx = 0;
            int wmo_miny = 999999999;
            int wmo_maxy = 0;
            int numtiles = 0;

            //Determine min max offset
            for (int i = 0; i < wmo.group.Count(); i++)
            {
                string groupid = i.ToString().PadLeft(3, '0');

                double drawx1 = wmo.groupInfo[i].boundingBox1.X * 2;
                double drawy1 = wmo.groupInfo[i].boundingBox1.Y * 2;

                double drawx2 = wmo.groupInfo[i].boundingBox2.X * 2;
                double drawy2 = wmo.groupInfo[i].boundingBox2.Y * 2;

                if (drawx1 < wmo_minx)
                {
                    wmo_minx = (int)drawx1;
                }
                if (drawx1 > wmo_maxx)
                {
                    wmo_maxx = (int)drawx1;
                }

                if (drawy1 < wmo_miny)
                {
                    wmo_miny = (int)drawy1;
                }
                if (drawy1 > wmo_maxy)
                {
                    wmo_maxy = (int)drawy1;
                }

                if (drawx2 < wmo_minx)
                {
                    wmo_minx = (int)drawx2;
                }
                if (drawx2 > wmo_maxx)
                {
                    wmo_maxx = (int)drawx2;
                }

                if (drawy2 < wmo_miny)
                {
                    wmo_minx = (int)drawy2;
                }
                if (drawy2 > wmo_maxy)
                {
                    wmo_maxx = (int)drawy2;
                }
            }

            int wmoresx = 0;
            int wmoresy = 0;

            //Determine image height
            for (int i = 0; i < wmo.group.Count(); i++)
            {
                string groupid = i.ToString().PadLeft(3, '0');

                double drawx1 = wmo.groupInfo[i].boundingBox1.X * 2;
                double drawy1 = wmo.groupInfo[i].boundingBox1.Y * 2;

                double drawx2 = wmo.groupInfo[i].boundingBox2.X * 2;
                double drawy2 = wmo.groupInfo[i].boundingBox2.Y * 2;

                int greenx1 = (int)drawx1 + Math.Abs(wmo_minx);
                int greeny1 = (int)drawy1 + Math.Abs(wmo_miny);

                int greenx2 = (int)drawx2 + Math.Abs(wmo_minx);
                int greeny2 = (int)drawy2 + Math.Abs(wmo_miny);

                if (greenx2 > wmoresx)
                {
                    wmoresx = greenx2;
                }
                if (greeny2 > wmoresy)
                {
                    wmoresy = greeny2;
                }
            }

            if (wmoresx == 0 || wmoresy == 0)
            {
                Console.WriteLine("WMO " + wmoname + " has invalid calculated resolution (" + wmoresx + "x" + wmoresy + ")");
                return;
            }

            Bitmap   wmobmp = new Bitmap(wmoresx, wmoresy);
            Graphics wmog   = Graphics.FromImage(wmobmp);

            /*
             * string wmodirname = Path.GetDirectoryName(wmoname.Replace("World" + Path.DirectorySeparatorChar, String.Empty));
             *
             * if (!Directory.Exists(Path.Combine(basedir, "World", "Minimaps", wmodirname + Path.DirectorySeparatorChar)))
             * {
             *  Console.WriteLine("WMO has no minimaps directory (" + Path.Combine(basedir, "World", "Minimaps", wmodirname + Path.DirectorySeparatorChar) + "). Skipping..");
             *  return;
             * }
             */

            for (int i = 0; i < wmo.group.Count(); i++)
            {
                string groupid = i.ToString().PadLeft(3, '0');

                double drawx1 = wmo.groupInfo[i].boundingBox1.X * 2;
                double drawy1 = wmo.groupInfo[i].boundingBox1.Y * 2;

                double drawx2 = wmo.groupInfo[i].boundingBox2.X * 2;
                double drawy2 = wmo.groupInfo[i].boundingBox2.Y * 2;

                int greenx1 = (int)drawx1 + Math.Abs(wmo_minx);
                int greeny1 = (int)drawy1 + Math.Abs(wmo_miny);

                int greenx2 = (int)drawx2 + Math.Abs(wmo_minx);
                int greeny2 = (int)drawy2 + Math.Abs(wmo_miny);

                /*
                 * //Check if minimaps wmo dir for this even exists
                 *
                 * string wmogroupfilename = Path.GetFileNameWithoutExtension(wmoname) + "_" + groupid;
                 * string[] filePaths = Directory.GetFiles(Path.Combine(basedir, "World", "Minimaps", wmodirname + Path.DirectorySeparatorChar), wmogroupfilename + "*");
                 *
                 * //check if there are any minimap blps for this group
                 * if (filePaths.Count() == 0)
                 * {
                 *  Console.WriteLine("WMO has no blps in minimap directory. Skipping..");
                 *  continue;
                 * }
                 */
                Bitmap minimapbmp = CompileGroup(wmoname, groupid);

                if (minimapbmp.Width > 1)
                {
                    wmog.DrawImage(minimapbmp, greenx1, (wmoresy - (greeny1 + (greeny2 - greeny1)) + (greeny2 - greeny1)), new Rectangle(0, minimapbmp.Height, (greenx2 - greenx1), -(greeny2 - greeny1)), GraphicsUnit.Pixel);
                }
                numtiles++;
                minimapbmp.Dispose();
            }

            wmog.Dispose();

            if (numtiles > 0) //check if it even compiled anything
            {
                Directory.CreateDirectory("done" + Path.DirectorySeparatorChar + "WMO" + Path.DirectorySeparatorChar + Path.GetDirectoryName(wmoname));
                wmobmp.Save("done" + Path.DirectorySeparatorChar + "WMO" + Path.DirectorySeparatorChar + Path.Combine(wmoname) + ".png");
            }
            else
            {
                Console.WriteLine("WMO has no minimaps. Skipping..");
            }
        }
예제 #4
0
        public void Compile(uint fileDataID)
        {
            if (!Listfile.fdidToNameMap.TryGetValue(fileDataID, out var filename))
            {
                throw new Exception("FileDataID " + fileDataID + " is not named in listfile!");
            }

            var wmoreader = new WMOReader();
            var wmo       = wmoreader.LoadWMO(fileDataID);

            Console.WriteLine("Compiling minimaps for WMO " + fileDataID);

            if (wmo.group == null || wmo.group.Count() == 0)
            {
                Console.WriteLine("WMO " + fileDataID + " has no groups! Skipping..");
                return;
            }

            int wmo_minx = 999999999;
            int wmo_maxx = 0;
            int wmo_miny = 999999999;
            int wmo_maxy = 0;
            int numtiles = 0;

            //Determine min max offset
            for (int i = 0; i < wmo.group.Count(); i++)
            {
                string groupid = i.ToString().PadLeft(3, '0');

                double drawx1 = wmo.groupInfo[i].boundingBox1.X * 2;
                double drawy1 = wmo.groupInfo[i].boundingBox1.Y * 2;

                double drawx2 = wmo.groupInfo[i].boundingBox2.X * 2;
                double drawy2 = wmo.groupInfo[i].boundingBox2.Y * 2;

                if (drawx1 < wmo_minx)
                {
                    wmo_minx = (int)drawx1;
                }
                if (drawx1 > wmo_maxx)
                {
                    wmo_maxx = (int)drawx1;
                }

                if (drawy1 < wmo_miny)
                {
                    wmo_miny = (int)drawy1;
                }
                if (drawy1 > wmo_maxy)
                {
                    wmo_maxy = (int)drawy1;
                }

                if (drawx2 < wmo_minx)
                {
                    wmo_minx = (int)drawx2;
                }
                if (drawx2 > wmo_maxx)
                {
                    wmo_maxx = (int)drawx2;
                }

                if (drawy2 < wmo_miny)
                {
                    wmo_minx = (int)drawy2;
                }
                if (drawy2 > wmo_maxy)
                {
                    wmo_maxx = (int)drawy2;
                }
            }

            int wmoresx = 0;
            int wmoresy = 0;

            //Determine image height
            for (int i = 0; i < wmo.group.Count(); i++)
            {
                string groupid = i.ToString().PadLeft(3, '0');

                double drawx1 = wmo.groupInfo[i].boundingBox1.X * 2;
                double drawy1 = wmo.groupInfo[i].boundingBox1.Y * 2;

                double drawx2 = wmo.groupInfo[i].boundingBox2.X * 2;
                double drawy2 = wmo.groupInfo[i].boundingBox2.Y * 2;

                int greenx1 = (int)drawx1 + Math.Abs(wmo_minx);
                int greeny1 = (int)drawy1 + Math.Abs(wmo_miny);

                int greenx2 = (int)drawx2 + Math.Abs(wmo_minx);
                int greeny2 = (int)drawy2 + Math.Abs(wmo_miny);

                if (greenx2 > wmoresx)
                {
                    wmoresx = greenx2;
                }
                if (greeny2 > wmoresy)
                {
                    wmoresy = greeny2;
                }
            }

            if (wmoresx == 0 || wmoresy == 0)
            {
                Console.WriteLine("WMO " + fileDataID + " has invalid calculated resolution (" + wmoresx + "x" + wmoresy + ")");
                return;
            }

            Bitmap   wmobmp = new Bitmap(wmoresx, wmoresy);
            Graphics wmog   = Graphics.FromImage(wmobmp);

            /*
             * string wmodirname = Path.GetDirectoryName(wmoname.Replace("World" + Path.DirectorySeparatorChar, String.Empty));
             *
             * if (!Directory.Exists(Path.Combine(basedir, "World", "Minimaps", wmodirname + Path.DirectorySeparatorChar)))
             * {
             *  Console.WriteLine("WMO has no minimaps directory (" + Path.Combine(basedir, "World", "Minimaps", wmodirname + Path.DirectorySeparatorChar) + "). Skipping..");
             *  return;
             * }
             */

            for (int i = 0; i < wmo.group.Count(); i++)
            {
                string groupid = i.ToString().PadLeft(3, '0');

                double drawx1 = wmo.groupInfo[i].boundingBox1.X * 2;
                double drawy1 = wmo.groupInfo[i].boundingBox1.Y * 2;

                double drawx2 = wmo.groupInfo[i].boundingBox2.X * 2;
                double drawy2 = wmo.groupInfo[i].boundingBox2.Y * 2;

                int greenx1 = (int)drawx1 + Math.Abs(wmo_minx);
                int greeny1 = (int)drawy1 + Math.Abs(wmo_miny);

                int greenx2 = (int)drawx2 + Math.Abs(wmo_minx);
                int greeny2 = (int)drawy2 + Math.Abs(wmo_miny);

                try
                {
                    var minimapbmp = CompileGroup(filename, groupid);

                    if (minimapbmp.Width > 1)
                    {
                        wmog.DrawImage(minimapbmp, greenx1,
                                       (wmoresy - (greeny1 + (greeny2 - greeny1)) + (greeny2 - greeny1)),
                                       new Rectangle(0, minimapbmp.Height, (greenx2 - greenx1), -(greeny2 - greeny1)),
                                       GraphicsUnit.Pixel);
                    }

                    numtiles++;
                    minimapbmp.Dispose();
                }
                catch (FileNotFoundException e)
                {
                    return;
                }
            }

            wmog.Dispose();

            if (numtiles > 0) //check if it even compiled anything
            {
                Directory.CreateDirectory("done" + Path.DirectorySeparatorChar + "WMO" + Path.DirectorySeparatorChar + Path.GetDirectoryName(fileDataID.ToString()));
                wmobmp.Save("done" + Path.DirectorySeparatorChar + "WMO" + Path.DirectorySeparatorChar + Path.Combine(fileDataID.ToString()) + ".png");
            }
            else
            {
                Console.WriteLine("WMO has no minimaps. Skipping..");
            }
        }
예제 #5
0
        public static void exportWMO(string file, BackgroundWorker exportworker = null)
        {
            if (exportworker == null)
            {
                exportworker = new BackgroundWorker();
            }

            Console.WriteLine("Loading WMO file..");

            exportworker.ReportProgress(5, "Reading WMO..");

            var       outdir = ConfigurationManager.AppSettings["outdir"];
            WMOReader reader = new WMOReader();

            reader.LoadWMO(file);

            // TODO: Support doodads!

            /*
             * for (int i = 0; i < reader.wmofile.doodadNames.Count(); i++)
             * {
             *  //Console.WriteLine(reader.wmofile.doodadNames[i].filename);
             *  //reader.wmofile.doodadDefinitions[i].
             *  //reader.wmofile.doodadDefinitions[i].
             * }
             */

            exportworker.ReportProgress(30, "Reading WMO..");

            uint totalVertices = 0;

            var groups = new Structs.WMOGroup[reader.wmofile.group.Count()];

            for (int g = 0; g < reader.wmofile.group.Count(); g++)
            {
                Console.WriteLine("Loading group #" + g);
                if (reader.wmofile.group[g].mogp.vertices == null)
                {
                    Console.WriteLine("Group has no vertices!");  continue;
                }
                for (int i = 0; i < reader.wmofile.groupNames.Count(); i++)
                {
                    if (reader.wmofile.group[g].mogp.nameOffset == reader.wmofile.groupNames[i].offset)
                    {
                        groups[g].name = reader.wmofile.groupNames[i].name.Replace(" ", "_");
                    }
                }

                if (groups[g].name == "antiportal")
                {
                    Console.WriteLine("Group is antiportal"); continue;
                }

                groups[g].verticeOffset = totalVertices;
                groups[g].vertices      = new Structs.Vertex[reader.wmofile.group[g].mogp.vertices.Count()];

                for (int i = 0; i < reader.wmofile.group[g].mogp.vertices.Count(); i++)
                {
                    groups[g].vertices[i].Position = new Vector3(reader.wmofile.group[g].mogp.vertices[i].vector.X * -1, reader.wmofile.group[g].mogp.vertices[i].vector.Z, reader.wmofile.group[g].mogp.vertices[i].vector.Y);
                    groups[g].vertices[i].Normal   = new Vector3(reader.wmofile.group[g].mogp.normals[i].normal.X, reader.wmofile.group[g].mogp.normals[i].normal.Z, reader.wmofile.group[g].mogp.normals[i].normal.Y);
                    groups[g].vertices[i].TexCoord = new Vector2(reader.wmofile.group[g].mogp.textureCoords[0][i].X, reader.wmofile.group[g].mogp.textureCoords[0][i].Y);
                    totalVertices++;
                }

                var indicelist = new List <uint>();

                for (int i = 0; i < reader.wmofile.group[g].mogp.indices.Count(); i++)
                {
                    indicelist.Add(reader.wmofile.group[g].mogp.indices[i].indice);
                }

                groups[g].indices = indicelist.ToArray();
            }

            exportworker.ReportProgress(55, "Exporting textures..");

            // Create output directory
            if (!Directory.Exists(Path.Combine(outdir, Path.GetDirectoryName(file))))
            {
                Directory.CreateDirectory(Path.Combine(outdir, Path.GetDirectoryName(file)));
            }

            var mtlsb     = new StringBuilder();
            var textureID = 0;

            if (reader.wmofile.materials == null)
            {
                Console.WriteLine("Materials empty"); return;
            }
            var materials = new Structs.Material[reader.wmofile.materials.Count()];

            for (int i = 0; i < reader.wmofile.materials.Count(); i++)
            {
                for (int ti = 0; ti < reader.wmofile.textures.Count(); ti++)
                {
                    if (reader.wmofile.textures[ti].startOffset == reader.wmofile.materials[i].texture1)
                    {
                        //materials[i].textureID = BLPLoader.LoadTexture(reader.wmofile.textures[ti].filename, cache);
                        materials[i].textureID = textureID + i;
                        materials[i].filename  = Path.GetFileNameWithoutExtension(reader.wmofile.textures[ti].filename);

                        if (reader.wmofile.materials[i].blendMode == 0)
                        {
                            materials[i].transparent = false;
                        }
                        else
                        {
                            materials[i].transparent = true;
                        }

                        if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file), materials[i].filename + ".png")))
                        {
                            var blpreader = new BLPReader();

                            blpreader.LoadBLP(reader.wmofile.textures[ti].filename);

                            try
                            {
                                blpreader.bmp.Save(Path.Combine(outdir, Path.GetDirectoryName(file), materials[i].filename + ".png"));
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e.Message);
                            }
                        }

                        textureID++;
                    }
                }
            }

            //No idea how MTL files really work yet. Needs more investigation.
            foreach (var material in materials)
            {
                mtlsb.Append("newmtl " + material.filename + "\n");
                mtlsb.Append("Ns 96.078431\n");
                mtlsb.Append("Ka 1.000000 1.000000 1.000000\n");
                mtlsb.Append("Kd 0.640000 0.640000 0.640000\n");
                mtlsb.Append("Ks 0.000000 0.000000 0.000000\n");
                mtlsb.Append("Ke 0.000000 0.000000 0.000000\n");
                mtlsb.Append("Ni 1.000000\n");
                mtlsb.Append("d 1.000000\n");
                mtlsb.Append("illum 2\n");
                mtlsb.Append("map_Kd " + material.filename + ".png\n");
                if (material.transparent)
                {
                    mtlsb.Append("map_d " + material.filename + ".png\n");
                }
            }

            File.WriteAllText(Path.Combine(outdir, file.Replace(".wmo", ".mtl")), mtlsb.ToString());

            exportworker.ReportProgress(75, "Exporting model..");

            int numRenderbatches = 0;

            //Get total amount of render batches
            for (int i = 0; i < reader.wmofile.group.Count(); i++)
            {
                if (reader.wmofile.group[i].mogp.renderBatches == null)
                {
                    continue;
                }
                numRenderbatches = numRenderbatches + reader.wmofile.group[i].mogp.renderBatches.Count();
            }


            int rb = 0;

            for (int g = 0; g < reader.wmofile.group.Count(); g++)
            {
                groups[g].renderBatches = new Structs.RenderBatch[numRenderbatches];

                var group = reader.wmofile.group[g];
                if (group.mogp.renderBatches == null)
                {
                    continue;
                }
                for (int i = 0; i < group.mogp.renderBatches.Count(); i++)
                {
                    var batch = group.mogp.renderBatches[i];

                    groups[g].renderBatches[rb].firstFace = batch.firstFace;
                    groups[g].renderBatches[rb].numFaces  = batch.numFaces;

                    if (batch.flags == 2)
                    {
                        groups[g].renderBatches[rb].materialID = (uint)batch.possibleBox2_3;
                    }
                    else
                    {
                        groups[g].renderBatches[rb].materialID = batch.materialID;
                    }
                    groups[g].renderBatches[rb].blendType = reader.wmofile.materials[batch.materialID].blendMode;
                    groups[g].renderBatches[rb].groupID   = (uint)g;
                    rb++;
                }
            }

            exportworker.ReportProgress(95, "Writing files..");

            var objsw = new StreamWriter(Path.Combine(outdir, file.Replace(".wmo", ".obj")));

            objsw.WriteLine("# Written by Marlamin's WoW OBJExporter. Original file: " + file);
            objsw.WriteLine("mtllib " + Path.GetFileNameWithoutExtension(file) + ".mtl");

            foreach (var group in groups)
            {
                if (group.vertices == null)
                {
                    continue;
                }
                Console.WriteLine("Writing " + group.name);
                objsw.WriteLine("g " + group.name);

                foreach (var vertex in group.vertices)
                {
                    objsw.WriteLine("v " + vertex.Position.X + " " + vertex.Position.Y + " " + vertex.Position.Z);
                    objsw.WriteLine("vt " + vertex.TexCoord.X + " " + -vertex.TexCoord.Y);
                    objsw.WriteLine("vn " + vertex.Normal.X + " " + vertex.Normal.Y + " " + vertex.Normal.Z);
                }

                var indices = group.indices;

                foreach (var renderbatch in group.renderBatches)
                {
                    var i = renderbatch.firstFace;
                    if (renderbatch.numFaces > 0)
                    {
                        objsw.WriteLine("usemtl " + materials[renderbatch.materialID].filename);
                        objsw.WriteLine("s 1");
                        while (i < (renderbatch.firstFace + renderbatch.numFaces))
                        {
                            objsw.WriteLine("f " + (indices[i] + group.verticeOffset + 1) + "/" + (indices[i] + group.verticeOffset + 1) + "/" + (indices[i] + group.verticeOffset + 1) + " " + (indices[i + 1] + group.verticeOffset + 1) + "/" + (indices[i + 1] + group.verticeOffset + 1) + "/" + (indices[i + 1] + group.verticeOffset + 1) + " " + (indices[i + 2] + group.verticeOffset + 1) + "/" + (indices[i + 2] + group.verticeOffset + 1) + "/" + (indices[i + 2] + group.verticeOffset + 1));
                            i = i + 3;
                        }
                    }
                }
            }
            objsw.Close();
            Console.WriteLine("Done loading WMO file!");
        }
예제 #6
0
        public static void exportWMO(string file, BackgroundWorker exportworker = null, string destinationOverride = null)
        {
            if (exportworker == null)
            {
                exportworker = new BackgroundWorker();
                exportworker.WorkerReportsProgress = true;
            }

            Logger.WriteLine("WMO glTF Exporter: Loading file {0}...", file);

            exportworker.ReportProgress(5, "Reading WMO..");

            var outdir = ConfigurationManager.AppSettings["outdir"];
            var reader = new WMOReader();

            reader.LoadWMO(file);

            System.Globalization.CultureInfo customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
            customCulture.NumberFormat.NumberDecimalSeparator    = ".";
            System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;

            if (destinationOverride == null)
            {
                if (!Directory.Exists(Path.Combine(outdir, Path.GetDirectoryName(file))))
                {
                    Directory.CreateDirectory(Path.Combine(outdir, Path.GetDirectoryName(file)));
                }
            }

            exportworker.ReportProgress(25, "Generating glTF..");

            var glTF = new glTF()
            {
                asset = new Asset()
                {
                    version    = "2.0",
                    generator  = "Marlamin's WoW Exporter " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(),
                    copyright  = "Contents are owned by Blizzard Entertainment",
                    minVersion = "2.0"
                }
            };

            var        groups = new Structs.WMOGroup[reader.wmofile.group.Count()];
            FileStream stream;

            if (destinationOverride == null)
            {
                stream = new FileStream(Path.Combine(outdir, file.Replace(".wmo", ".bin")), FileMode.OpenOrCreate);
            }
            else
            {
                stream = new FileStream(Path.Combine(destinationOverride, Path.GetFileNameWithoutExtension(file) + ".bin"), FileMode.OpenOrCreate);
            }

            var writer = new BinaryWriter(stream);

            var bufferViews  = new List <BufferView>();
            var accessorInfo = new List <Accessor>();
            var meshes       = new List <Mesh>();

            for (int g = 0; g < reader.wmofile.group.Count(); g++)
            {
                if (reader.wmofile.group[g].mogp.vertices == null)
                {
                    Console.WriteLine("Group has no vertices!");  continue;
                }
                for (int i = 0; i < reader.wmofile.groupNames.Count(); i++)
                {
                    if (reader.wmofile.group[g].mogp.nameOffset == reader.wmofile.groupNames[i].offset)
                    {
                        groups[g].name = reader.wmofile.groupNames[i].name.Replace(" ", "_");
                    }
                }

                if (groups[g].name == "antiportal")
                {
                    Console.WriteLine("Group is antiportal"); continue;
                }

                // Position bufferview
                var vPosBuffer = new BufferView()
                {
                    buffer     = 0,
                    byteOffset = (uint)writer.BaseStream.Position,
                    target     = 34962
                };

                var minPosX = float.MaxValue;
                var minPosY = float.MaxValue;
                var minPosZ = float.MaxValue;

                var maxPosX = float.MinValue;
                var maxPosY = float.MinValue;
                var maxPosZ = float.MinValue;

                for (int i = 0; i < reader.wmofile.group[g].mogp.vertices.Count(); i++)
                {
                    writer.Write(reader.wmofile.group[g].mogp.vertices[i].vector.X * -1);
                    writer.Write(reader.wmofile.group[g].mogp.vertices[i].vector.Z);
                    writer.Write(reader.wmofile.group[g].mogp.vertices[i].vector.Y);

                    if (reader.wmofile.group[g].mogp.vertices[i].vector.X * -1 < minPosX)
                    {
                        minPosX = reader.wmofile.group[g].mogp.vertices[i].vector.X * -1;
                    }
                    if (reader.wmofile.group[g].mogp.vertices[i].vector.Z < minPosY)
                    {
                        minPosY = reader.wmofile.group[g].mogp.vertices[i].vector.Z;
                    }
                    if (reader.wmofile.group[g].mogp.vertices[i].vector.Y < minPosZ)
                    {
                        minPosZ = reader.wmofile.group[g].mogp.vertices[i].vector.Y;
                    }

                    if (reader.wmofile.group[g].mogp.vertices[i].vector.X * -1 > maxPosX)
                    {
                        maxPosX = reader.wmofile.group[g].mogp.vertices[i].vector.X * -1;
                    }
                    if (reader.wmofile.group[g].mogp.vertices[i].vector.Z > maxPosY)
                    {
                        maxPosY = reader.wmofile.group[g].mogp.vertices[i].vector.Z;
                    }
                    if (reader.wmofile.group[g].mogp.vertices[i].vector.Y > maxPosZ)
                    {
                        maxPosZ = reader.wmofile.group[g].mogp.vertices[i].vector.Y;
                    }
                }

                vPosBuffer.byteLength = (uint)writer.BaseStream.Position - vPosBuffer.byteOffset;

                var posLoc = accessorInfo.Count();

                accessorInfo.Add(new Accessor()
                {
                    name          = "vPos",
                    bufferView    = bufferViews.Count(),
                    byteOffset    = 0,
                    componentType = 5126,
                    count         = (uint)reader.wmofile.group[g].mogp.vertices.Count(),
                    type          = "VEC3",
                    min           = new float[] { minPosX, minPosY, minPosZ },
                    max           = new float[] { maxPosX, maxPosY, maxPosZ }
                });

                bufferViews.Add(vPosBuffer);

                // Normal bufferview
                var normalBuffer = new BufferView()
                {
                    buffer     = 0,
                    byteOffset = (uint)writer.BaseStream.Position,
                    target     = 34962
                };

                for (int i = 0; i < reader.wmofile.group[g].mogp.vertices.Count(); i++)
                {
                    writer.Write(reader.wmofile.group[g].mogp.normals[i].normal.X);
                    writer.Write(reader.wmofile.group[g].mogp.normals[i].normal.Z);
                    writer.Write(reader.wmofile.group[g].mogp.normals[i].normal.Y);
                }

                normalBuffer.byteLength = (uint)writer.BaseStream.Position - normalBuffer.byteOffset;

                var normalLoc = accessorInfo.Count();

                accessorInfo.Add(new Accessor()
                {
                    name          = "vNormal",
                    bufferView    = bufferViews.Count(),
                    byteOffset    = 0,
                    componentType = 5126,
                    count         = (uint)reader.wmofile.group[g].mogp.vertices.Count(),
                    type          = "VEC3"
                });

                bufferViews.Add(normalBuffer);

                // TexCoord bufferview
                var texCoordBuffer = new BufferView()
                {
                    buffer     = 0,
                    byteOffset = (uint)writer.BaseStream.Position,
                    target     = 34962
                };

                for (int i = 0; i < reader.wmofile.group[g].mogp.vertices.Count(); i++)
                {
                    writer.Write(reader.wmofile.group[g].mogp.textureCoords[0][i].X);
                    writer.Write(reader.wmofile.group[g].mogp.textureCoords[0][i].Y);
                }

                texCoordBuffer.byteLength = (uint)writer.BaseStream.Position - texCoordBuffer.byteOffset;

                var texLoc = accessorInfo.Count();

                accessorInfo.Add(new Accessor()
                {
                    name          = "vTex",
                    bufferView    = bufferViews.Count(),
                    byteOffset    = 0,
                    componentType = 5126,
                    count         = (uint)reader.wmofile.group[g].mogp.vertices.Count(),
                    type          = "VEC2"
                });

                bufferViews.Add(texCoordBuffer);

                var indexBufferPos = bufferViews.Count();

                for (int i = 0; i < reader.wmofile.group[g].mogp.renderBatches.Count(); i++)
                {
                    var batch = reader.wmofile.group[g].mogp.renderBatches[i];

                    accessorInfo.Add(new Accessor()
                    {
                        name          = "indices",
                        bufferView    = indexBufferPos,
                        byteOffset    = batch.firstFace * 2,
                        componentType = 5123,
                        count         = batch.numFaces,
                        type          = "SCALAR"
                    });

                    var mesh = new Mesh();
                    mesh.name       = groups[g].name + "_" + i;
                    mesh.primitives = new Primitive[1];
                    mesh.primitives[0].attributes = new Dictionary <string, int>
                    {
                        { "POSITION", posLoc },
                        { "NORMAL", normalLoc },
                        { "TEXCOORD_0", texLoc }
                    };

                    mesh.primitives[0].indices = (uint)accessorInfo.Count() - 1;

                    if (batch.flags == 2)
                    {
                        mesh.primitives[0].material = (uint)batch.possibleBox2_3;
                    }
                    else
                    {
                        mesh.primitives[0].material = batch.materialID;
                    }

                    mesh.primitives[0].mode = 4;

                    meshes.Add(mesh);
                }

                var indiceBuffer = new BufferView()
                {
                    buffer     = 0,
                    byteOffset = (uint)writer.BaseStream.Position,
                    target     = 34963
                };

                for (int i = 0; i < reader.wmofile.group[g].mogp.indices.Count(); i++)
                {
                    writer.Write(reader.wmofile.group[g].mogp.indices[i].indice);
                }

                indiceBuffer.byteLength = (uint)writer.BaseStream.Position - indiceBuffer.byteOffset;

                bufferViews.Add(indiceBuffer);
            }

            glTF.bufferViews = bufferViews.ToArray();
            glTF.accessors   = accessorInfo.ToArray();

            glTF.buffers = new Buffer[1];
            glTF.buffers[0].byteLength = (uint)writer.BaseStream.Length;
            glTF.buffers[0].uri        = Path.GetFileNameWithoutExtension(file) + ".bin";

            writer.Close();
            writer.Dispose();

            exportworker.ReportProgress(65, "Exporting textures..");

            if (reader.wmofile.materials == null)
            {
                Logger.WriteLine("WMO glTF exporter: Materials empty"); return;
            }

            var materialCount = reader.wmofile.materials.Count();

            glTF.images    = new Image[materialCount];
            glTF.textures  = new Texture[materialCount];
            glTF.materials = new Material[materialCount];

            for (int i = 0; i < materialCount; i++)
            {
                for (int ti = 0; ti < reader.wmofile.textures.Count(); ti++)
                {
                    if (reader.wmofile.textures[ti].startOffset == reader.wmofile.materials[i].texture1)
                    {
                        var textureFilename = Path.GetFileNameWithoutExtension(reader.wmofile.textures[ti].filename).ToLower();

                        glTF.images[i].uri = textureFilename + ".png";

                        glTF.textures[i].sampler = 0;
                        glTF.textures[i].source  = i;

                        glTF.materials[i].name = textureFilename;
                        glTF.materials[i].pbrMetallicRoughness = new PBRMetallicRoughness();
                        glTF.materials[i].pbrMetallicRoughness.baseColorTexture       = new TextureIndex();
                        glTF.materials[i].pbrMetallicRoughness.baseColorTexture.index = i;
                        glTF.materials[i].pbrMetallicRoughness.metallicFactor         = 0.0f;

                        switch (reader.wmofile.materials[i].blendMode)
                        {
                        case 0:
                            glTF.materials[i].alphaMode   = "OPAQUE";
                            glTF.materials[i].alphaCutoff = 0.0f;
                            break;

                        case 1:
                            glTF.materials[i].alphaMode   = "MASK";
                            glTF.materials[i].alphaCutoff = 0.90393700787f;
                            break;

                        case 2:
                            glTF.materials[i].alphaMode   = "MASK";
                            glTF.materials[i].alphaCutoff = 0.5f;
                            break;

                        default:
                            glTF.materials[i].alphaMode   = "OPAQUE";
                            glTF.materials[i].alphaCutoff = 0.0f;
                            break;
                        }

                        var saveLocation = "";

                        if (destinationOverride == null)
                        {
                            saveLocation = Path.Combine(outdir, Path.GetDirectoryName(file), textureFilename + ".png");
                        }
                        else
                        {
                            saveLocation = Path.Combine(outdir, destinationOverride, textureFilename + ".png");
                        }

                        if (!File.Exists(saveLocation))
                        {
                            var blpreader = new BLPReader();

                            blpreader.LoadBLP(reader.wmofile.textures[ti].filename);

                            try
                            {
                                blpreader.bmp.Save(saveLocation);
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine("Error exporting texture " + reader.wmofile.textures[ti].filename + ": " + e.Message);
                            }
                        }
                    }
                }
            }

            glTF.samplers              = new Sampler[1];
            glTF.samplers[0].name      = "Default Sampler";
            glTF.samplers[0].minFilter = 9986;
            glTF.samplers[0].magFilter = 9729;
            glTF.samplers[0].wrapS     = 10497;
            glTF.samplers[0].wrapT     = 10497;

            glTF.scenes         = new Scene[1];
            glTF.scenes[0].name = Path.GetFileNameWithoutExtension(file);

            glTF.nodes = new Node[meshes.Count()];
            var meshIDs = new List <int>();

            for (var i = 0; i < meshes.Count(); i++)
            {
                glTF.nodes[i].name = meshes[i].name;
                glTF.nodes[i].mesh = i;
                meshIDs.Add(i);
            }

            glTF.scenes[0].nodes = meshIDs.ToArray();

            glTF.meshes = meshes.ToArray();

            glTF.scene = 0;

            string currentDoodadSetName = "";

            for (int i = 0; i < reader.wmofile.doodadDefinitions.Count(); i++)
            {
                var doodadDefinition = reader.wmofile.doodadDefinitions[i];

                foreach (var doodadSet in reader.wmofile.doodadSets)
                {
                    if (doodadSet.firstInstanceIndex == i)
                    {
                        Console.WriteLine("At set: " + doodadSet.setName);
                        currentDoodadSetName = doodadSet.setName.Replace("Set_", "").Replace("SET_", "").Replace("$DefaultGlobal", "Default");
                    }
                }

                foreach (var doodadNameEntry in reader.wmofile.doodadNames)
                {
                    if (doodadNameEntry.startOffset == doodadDefinition.offset)
                    {
                        if (!File.Exists(Path.GetFileNameWithoutExtension(doodadNameEntry.filename).ToLower() + ".gltf"))
                        {
                            if (destinationOverride == null)
                            {
                                M2Exporter.exportM2(doodadNameEntry.filename.Replace(".MDX", ".M2").Replace(".MDL", ".M2").ToLower(), null, Path.Combine(outdir, Path.GetDirectoryName(file)));
                            }
                            else
                            {
                                M2Exporter.exportM2(doodadNameEntry.filename.Replace(".MDX", ".M2").Replace(".MDL", ".M2").ToLower(), null, destinationOverride);
                            }
                        }
                    }
                }
            }

            exportworker.ReportProgress(95, "Writing to file..");

            if (destinationOverride == null)
            {
                File.WriteAllText(Path.Combine(outdir, file.Replace(".wmo", ".gltf")), JsonConvert.SerializeObject(glTF, Formatting.Indented, new JsonSerializerSettings
                {
                    NullValueHandling = NullValueHandling.Ignore
                }));
            }
            else
            {
                File.WriteAllText(Path.Combine(destinationOverride, Path.GetFileName(file.ToLower()).Replace(".wmo", ".gltf")), JsonConvert.SerializeObject(glTF, Formatting.Indented, new JsonSerializerSettings
                {
                    NullValueHandling = NullValueHandling.Ignore
                }));
            }

            Logger.WriteLine("Done exporting WMO file!");
        }
예제 #7
0
        private void LoadWMO(string modelpath)
        {
            Console.WriteLine("Loading WMO file..");
            WMOReader reader   = new WMOReader();
            string    filename = modelpath;

            //Load WMO
            reader.LoadWMO(filename);

            //Enable Vertex Arrays
            GL.EnableClientState(ArrayCap.VertexArray);
            //Enable Normal Arrays
            GL.EnableClientState(ArrayCap.NormalArray);
            //Enable TexCoord arrays
            GL.EnableClientState(ArrayCap.TextureCoordArray);

            //Set up buffer IDs
            VBOid = new uint[(reader.wmofile.group.Count() * 2) + 2];
            GL.GenBuffers((reader.wmofile.group.Count() * 2) + 2, VBOid);

            for (int i = 0; i < reader.wmofile.doodadNames.Count(); i++)
            {
                //Console.WriteLine(reader.wmofile.doodadNames[i].filename);
            }

            for (int g = 0; g < reader.wmofile.group.Count(); g++)
            {
                if (reader.wmofile.group[g].mogp.vertices == null)
                {
                    continue;
                }
                //Switch to Vertex buffer
                GL.BindBuffer(BufferTarget.ArrayBuffer, VBOid[g * 2]);

                Vertex[] vertices = new Vertex[reader.wmofile.group[g].mogp.vertices.Count()];

                for (int i = 0; i < reader.wmofile.group[g].mogp.vertices.Count(); i++)
                {
                    vertices[i].Position = new Vector3(reader.wmofile.group[g].mogp.vertices[i].vector.X, reader.wmofile.group[g].mogp.vertices[i].vector.Z, reader.wmofile.group[g].mogp.vertices[i].vector.Y);
                    vertices[i].Normal   = new Vector3(reader.wmofile.group[g].mogp.normals[i].normal.X, reader.wmofile.group[g].mogp.normals[i].normal.Z, reader.wmofile.group[g].mogp.normals[i].normal.Y);
                    vertices[i].TexCoord = new Vector2(reader.wmofile.group[g].mogp.textureCoords[0][i].X, reader.wmofile.group[g].mogp.textureCoords[0][i].Y);
                }


                //Push to buffer
                GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * 8 * sizeof(float)), vertices, BufferUsageHint.StaticDraw);

                //Switch to Index buffer
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, VBOid[(g * 2) + 1]);

                List <uint> indicelist = new List <uint>();
                for (int i = 0; i < reader.wmofile.group[g].mogp.indices.Count(); i++)
                {
                    indicelist.Add(reader.wmofile.group[g].mogp.indices[i].indice);
                }

                uint[] indices = indicelist.ToArray();

                //Push to buffer
                GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indices.Length * sizeof(uint)), indices, BufferUsageHint.StaticDraw);
            }

            GL.Enable(EnableCap.Texture2D);

            materials = new Material[reader.wmofile.materials.Count()];
            for (int i = 0; i < reader.wmofile.materials.Count(); i++)
            {
                for (int ti = 0; ti < reader.wmofile.textures.Count(); ti++)
                {
                    if (reader.wmofile.textures[ti].startOffset == reader.wmofile.materials[i].texture1)
                    {
                        materials[i].textureID = BLPLoader.LoadTexture(reader.wmofile.textures[ti].filename, cache);
                        materials[i].filename  = reader.wmofile.textures[ti].filename;
                    }
                }
            }

            int numRenderbatches = 0;

            //Get total amount of render batches
            for (int i = 0; i < reader.wmofile.group.Count(); i++)
            {
                if (reader.wmofile.group[i].mogp.renderBatches == null)
                {
                    continue;
                }
                numRenderbatches = numRenderbatches + reader.wmofile.group[i].mogp.renderBatches.Count();
            }

            renderbatches = new RenderBatch[numRenderbatches];

            int rb = 0;

            for (int g = 0; g < reader.wmofile.group.Count(); g++)
            {
                var group = reader.wmofile.group[g];
                if (group.mogp.renderBatches == null)
                {
                    continue;
                }
                for (int i = 0; i < group.mogp.renderBatches.Count(); i++)
                {
                    var batch = group.mogp.renderBatches[i];
                    renderbatches[rb].firstFace = batch.firstFace;
                    renderbatches[rb].numFaces  = batch.numFaces;
                    if (batch.flags == 2)
                    {
                        renderbatches[rb].materialID = (uint)group.mogp.renderBatches[i].possibleBox2_3;
                    }
                    else
                    {
                        renderbatches[rb].materialID = group.mogp.renderBatches[i].materialID;
                    }
                    renderbatches[rb].blendType = reader.wmofile.materials[group.mogp.renderBatches[i].materialID].blendMode;
                    renderbatches[rb].groupID   = (uint)g;
                    rb++;
                }
            }

            Console.WriteLine("  " + reader.wmofile.group.Count() + " skins");
            Console.WriteLine("  " + materials.Count() + " materials");
            Console.WriteLine("  " + renderbatches.Count() + " renderbatches");
            Console.WriteLine("  " + reader.wmofile.group[0].mogp.vertices.Count() + " vertices");
            Console.WriteLine("Done loading WMO file!");

            gLoaded = true;
            isWMO   = true;
        }
예제 #8
0
        public static Renderer.Structs.WorldModel LoadWMO(string filename, CacheStorage cache, int shaderProgram)
        {
            if (cache.worldModelBatches.ContainsKey(filename))
            {
                return(cache.worldModelBatches[filename]);
            }

            WoWFormatLib.Structs.WMO.WMO wmo = new WoWFormatLib.Structs.WMO.WMO();

            if (cache.worldModels.ContainsKey(filename))
            {
                wmo = cache.worldModels[filename];
            }
            else
            {
                //Load WMO from file
                if (WoWFormatLib.Utils.CASC.cascHandler.FileExists(filename))
                {
                    var wmoreader = new WMOReader();
                    wmoreader.LoadWMO(filename, false);
                    cache.worldModels.Add(filename, wmoreader.wmofile);
                    wmo = wmoreader.wmofile;
                }
                else
                {
                    throw new Exception("WMO " + filename + " does not exist!");
                }
            }

            if (wmo.group.Count() == 0)
            {
                throw new Exception("Broken WMO! Report to developer (mail [email protected]) with this filename: " + filename);
            }

            var wmobatch = new Renderer.Structs.WorldModel()
            {
                groupBatches = new Renderer.Structs.WorldModelGroupBatches[wmo.group.Count()]
            };

            string[] groupNames = new string[wmo.group.Count()];

            for (int g = 0; g < wmo.group.Count(); g++)
            {
                if (wmo.group[g].mogp.vertices == null)
                {
                    continue;
                }

                wmobatch.groupBatches[g].vao          = GL.GenVertexArray();
                wmobatch.groupBatches[g].vertexBuffer = GL.GenBuffer();
                wmobatch.groupBatches[g].indiceBuffer = GL.GenBuffer();

                GL.BindVertexArray(wmobatch.groupBatches[g].vao);

                GL.BindBuffer(BufferTarget.ArrayBuffer, wmobatch.groupBatches[g].vertexBuffer);

                Renderer.Structs.M2Vertex[] wmovertices = new Renderer.Structs.M2Vertex[wmo.group[g].mogp.vertices.Count()];

                for (int i = 0; i < wmo.groupNames.Count(); i++)
                {
                    if (wmo.group[g].mogp.nameOffset == wmo.groupNames[i].offset)
                    {
                        groupNames[g] = wmo.groupNames[i].name.Replace(" ", "_");
                    }
                }

                if (groupNames[g] == "antiportal")
                {
                    continue;
                }

                for (int i = 0; i < wmo.group[g].mogp.vertices.Count(); i++)
                {
                    wmovertices[i].Position = new Vector3(wmo.group[g].mogp.vertices[i].vector.X, wmo.group[g].mogp.vertices[i].vector.Y, wmo.group[g].mogp.vertices[i].vector.Z);
                    wmovertices[i].Normal   = new Vector3(wmo.group[g].mogp.normals[i].normal.X, wmo.group[g].mogp.normals[i].normal.Y, wmo.group[g].mogp.normals[i].normal.Z);
                    if (wmo.group[g].mogp.textureCoords[0] == null)
                    {
                        wmovertices[i].TexCoord = new Vector2(0.0f, 0.0f);
                    }
                    else
                    {
                        wmovertices[i].TexCoord = new Vector2(wmo.group[g].mogp.textureCoords[0][i].X, wmo.group[g].mogp.textureCoords[0][i].Y);
                    }
                }

                //Push to buffer
                GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(wmovertices.Length * 8 * sizeof(float)), wmovertices, BufferUsageHint.StaticDraw);

                //Set pointers in buffer
                //var normalAttrib = GL.GetAttribLocation(shaderProgram, "normal");
                //GL.EnableVertexAttribArray(normalAttrib);
                //GL.VertexAttribPointer(normalAttrib, 3, VertexAttribPointerType.Float, false, sizeof(float) * 8, sizeof(float) * 0);

                var texCoordAttrib = GL.GetAttribLocation(shaderProgram, "texCoord");
                GL.EnableVertexAttribArray(texCoordAttrib);
                GL.VertexAttribPointer(texCoordAttrib, 2, VertexAttribPointerType.Float, false, sizeof(float) * 8, sizeof(float) * 3);

                var posAttrib = GL.GetAttribLocation(shaderProgram, "position");
                GL.EnableVertexAttribArray(posAttrib);
                GL.VertexAttribPointer(posAttrib, 3, VertexAttribPointerType.Float, false, sizeof(float) * 8, sizeof(float) * 5);

                //Switch to Index buffer
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, wmobatch.groupBatches[g].indiceBuffer);

                List <uint> wmoindicelist = new List <uint>();
                for (int i = 0; i < wmo.group[g].mogp.indices.Count(); i++)
                {
                    wmoindicelist.Add(wmo.group[g].mogp.indices[i].indice);
                }

                wmobatch.groupBatches[g].indices = wmoindicelist.ToArray();

                GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(wmobatch.groupBatches[g].indices.Length * sizeof(uint)), wmobatch.groupBatches[g].indices, BufferUsageHint.StaticDraw);
            }

            GL.Enable(EnableCap.Texture2D);

            wmobatch.mats = new Renderer.Structs.Material[wmo.materials.Count()];
            for (int i = 0; i < wmo.materials.Count(); i++)
            {
                wmobatch.mats[i].texture1 = wmo.materials[i].texture1;
                wmobatch.mats[i].texture2 = wmo.materials[i].texture2;
                wmobatch.mats[i].texture3 = wmo.materials[i].texture3;

                for (int ti = 0; ti < wmo.textures.Count(); ti++)
                {
                    if (wmo.textures[ti].startOffset == wmo.materials[i].texture1)
                    {
                        wmobatch.mats[i].textureID1 = BLPLoader.LoadTexture(wmo.textures[ti].filename, cache);
                    }

                    if (wmo.textures[ti].startOffset == wmo.materials[i].texture2)
                    {
                        wmobatch.mats[i].textureID2 = BLPLoader.LoadTexture(wmo.textures[ti].filename, cache);
                    }

                    if (wmo.textures[ti].startOffset == wmo.materials[i].texture3)
                    {
                        wmobatch.mats[i].textureID3 = BLPLoader.LoadTexture(wmo.textures[ti].filename, cache);
                    }
                }
            }

            wmobatch.doodads = new Renderer.Structs.WMODoodad[wmo.doodadDefinitions.Count()];

            for (int i = 0; i < wmo.doodadDefinitions.Count(); i++)
            {
                for (int j = 0; j < wmo.doodadNames.Count(); j++)
                {
                    if (wmo.doodadDefinitions[i].offset == wmo.doodadNames[j].startOffset)
                    {
                        wmobatch.doodads[i].filename = wmo.doodadNames[j].filename;
                        //M2Loader.LoadM2(wmobatch.doodads[i].filename, cache);
                    }
                }
                wmobatch.doodads[i].flags    = wmo.doodadDefinitions[i].flags;
                wmobatch.doodads[i].position = new Vector3(wmo.doodadDefinitions[i].position.X, wmo.doodadDefinitions[i].position.Y, wmo.doodadDefinitions[i].position.Z);
                wmobatch.doodads[i].rotation = new Quaternion(wmo.doodadDefinitions[i].rotation.X, wmo.doodadDefinitions[i].rotation.Y, wmo.doodadDefinitions[i].rotation.Z, wmo.doodadDefinitions[i].rotation.W);
                wmobatch.doodads[i].scale    = wmo.doodadDefinitions[i].scale;
                wmobatch.doodads[i].color    = new Vector4(wmo.doodadDefinitions[i].color[0], wmo.doodadDefinitions[i].color[1], wmo.doodadDefinitions[i].color[2], wmo.doodadDefinitions[i].color[3]);
            }

            int numRenderbatches = 0;

            //Get total amount of render batches
            for (int i = 0; i < wmo.group.Count(); i++)
            {
                if (wmo.group[i].mogp.renderBatches == null)
                {
                    continue;
                }
                numRenderbatches = numRenderbatches + wmo.group[i].mogp.renderBatches.Count();
            }

            wmobatch.wmoRenderBatch = new Renderer.Structs.RenderBatch[numRenderbatches];

            int rb = 0;

            for (int g = 0; g < wmo.group.Count(); g++)
            {
                var group = wmo.group[g];
                if (group.mogp.renderBatches == null)
                {
                    continue;
                }
                for (int i = 0; i < group.mogp.renderBatches.Count(); i++)
                {
                    wmobatch.wmoRenderBatch[rb].firstFace = group.mogp.renderBatches[i].firstFace;
                    wmobatch.wmoRenderBatch[rb].numFaces  = group.mogp.renderBatches[i].numFaces;
                    uint matID = 0;

                    if (group.mogp.renderBatches[i].flags == 2)
                    {
                        matID = (uint)group.mogp.renderBatches[i].possibleBox2_3;
                    }
                    else
                    {
                        matID = group.mogp.renderBatches[i].materialID;
                    }

                    wmobatch.wmoRenderBatch[rb].materialID = new uint[3];
                    for (int ti = 0; ti < wmobatch.mats.Count(); ti++)
                    {
                        if (wmo.materials[matID].texture1 == wmobatch.mats[ti].texture1)
                        {
                            wmobatch.wmoRenderBatch[rb].materialID[0] = (uint)wmobatch.mats[ti].textureID1;
                        }

                        if (wmo.materials[matID].texture2 == wmobatch.mats[ti].texture2)
                        {
                            wmobatch.wmoRenderBatch[rb].materialID[1] = (uint)wmobatch.mats[ti].textureID2;
                        }

                        if (wmo.materials[matID].texture3 == wmobatch.mats[ti].texture3)
                        {
                            wmobatch.wmoRenderBatch[rb].materialID[2] = (uint)wmobatch.mats[ti].textureID3;
                        }
                    }

                    wmobatch.wmoRenderBatch[rb].blendType = wmo.materials[matID].blendMode;
                    wmobatch.wmoRenderBatch[rb].groupID   = (uint)g;
                    rb++;
                }
            }
            cache.worldModelBatches.Add(filename, wmobatch);

            return(wmobatch);
        }
예제 #9
0
        static void Main(string[] args)
        {
            if (args.Length < 2)
            {
                throw new Exception("Require buildconfig and cdnconfig (and yes for fullrun)");
            }

            var fullrun = false;

            if (args.Length == 3 && args[2] == "1")
            {
                Console.WriteLine("Doing full run!");
                fullrun = true;
            }

            // TODO: Use configuration stuff instead, but I don't want to figure that out right now. :)
            if (!File.Exists("connectionstring.txt"))
            {
                throw new Exception("connectionstring.txt not found!");
            }

            var dbConn = new MySqlConnection(File.ReadAllText("connectionstring.txt"));

            dbConn.Open();

            CASCLib.Logger.Init();

            CASC.InitCasc("wow.tools", args[0], args[1]);

            var insertCmd = new MySqlCommand("INSERT INTO wow_rootfiles_links VALUES (@parent, @child, @type)", dbConn);

            insertCmd.Parameters.AddWithValue("@parent", 0);
            insertCmd.Parameters.AddWithValue("@child", 0);
            insertCmd.Parameters.AddWithValue("@type", "");
            insertCmd.Prepare();

            var insertUVFNCmd = new MySqlCommand("INSERT INTO wow_communityfiles VALUES (@id, @filename)", dbConn);

            insertUVFNCmd.Parameters.AddWithValue("@id", 0);
            insertUVFNCmd.Parameters.AddWithValue("@filename", 0);
            insertCmd.Prepare();

            #region M2
            var m2ids = new List <uint>();

            using (var cmd = dbConn.CreateCommand())
            {
                if (fullrun)
                {
                    cmd.CommandText = "SELECT id from wow_rootfiles WHERE type = 'm2' ORDER BY id DESC";
                }
                else
                {
                    Console.WriteLine("[M2] Generating list of files to process..");
                    cmd.CommandText = "SELECT id from wow_rootfiles WHERE type = 'm2' AND id NOT IN (SELECT parent FROM wow_rootfiles_links) ORDER BY id DESC";
                }

                var reader = cmd.ExecuteReader();

                while (reader.Read())
                {
                    m2ids.Add(uint.Parse(reader["id"].ToString()));
                }

                reader.Close();
            }

            foreach (var m2 in m2ids)
            {
                if (CASC.FileExists(m2))
                {
                    Console.WriteLine("[M2] Loading " + m2);
                    try
                    {
                        var reader = new M2Reader();
                        reader.LoadM2(m2, false);

                        insertCmd.Parameters[0].Value = m2;

                        if (reader.model.textureFileDataIDs != null)
                        {
                            foreach (var textureID in reader.model.textureFileDataIDs)
                            {
                                insertEntry(insertCmd, textureID, "m2 texture");
                            }
                        }

                        if (reader.model.animFileDataIDs != null)
                        {
                            foreach (var animFileID in reader.model.animFileDataIDs)
                            {
                                insertEntry(insertCmd, animFileID.fileDataID, "m2 anim");
                            }
                        }

                        if (reader.model.skinFileDataIDs != null)
                        {
                            foreach (var skinFileID in reader.model.skinFileDataIDs)
                            {
                                insertEntry(insertCmd, skinFileID, "m2 skin");
                            }
                        }

                        if (reader.model.boneFileDataIDs != null)
                        {
                            foreach (var boneFileID in reader.model.boneFileDataIDs)
                            {
                                insertEntry(insertCmd, boneFileID, "m2 bone");
                            }
                        }

                        if (reader.model.recursiveParticleModelFileIDs != null)
                        {
                            foreach (var rpID in reader.model.recursiveParticleModelFileIDs)
                            {
                                insertEntry(insertCmd, rpID, "m2 recursive particle");
                            }
                        }

                        if (reader.model.geometryParticleModelFileIDs != null)
                        {
                            foreach (var gpID in reader.model.geometryParticleModelFileIDs)
                            {
                                insertEntry(insertCmd, gpID, "m2 geometry particle");
                            }
                        }

                        insertEntry(insertCmd, reader.model.skelFileID, "m2 skel");
                        insertEntry(insertCmd, reader.model.physFileID, "m2 phys");
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                    }
                }
            }
            #endregion

            #region WMO
            var wmoids = new List <uint>();

            var groupFixCMD = new MySqlCommand("UPDATE wow_rootfiles SET type = '_xxxwmo' WHERE id = @id LIMIT 1", dbConn);
            groupFixCMD.Parameters.AddWithValue("@id", 0);
            groupFixCMD.Prepare();

            using (var cmd = dbConn.CreateCommand())
            {
                if (fullrun)
                {
                    cmd.CommandText = "SELECT id from wow_rootfiles WHERE type = 'wmo' ORDER BY id DESC";
                }
                else
                {
                    Console.WriteLine("[WMO] Generating list of files to process..");
                    cmd.CommandText = "SELECT id from wow_rootfiles WHERE type = 'wmo' AND id NOT IN (SELECT parent FROM wow_rootfiles_links) ORDER BY id DESC";
                }
                var reader = cmd.ExecuteReader();

                while (reader.Read())
                {
                    wmoids.Add(uint.Parse(reader["id"].ToString()));
                }

                reader.Close();
            }

            foreach (var wmoid in wmoids)
            {
                if (CASC.FileExists(wmoid))
                {
                    Console.WriteLine("[WMO] Loading " + wmoid);
                    try
                    {
                        var reader = new WMOReader();
                        var wmo    = new WoWFormatLib.Structs.WMO.WMO();
                        try
                        {
                            wmo = reader.LoadWMO(wmoid);
                        }
                        catch (NotSupportedException e)
                        {
                            Console.WriteLine("[WMO] " + wmoid + " is a group WMO, fixing type and skipping..");
                            groupFixCMD.Parameters[0].Value = wmoid;
                            groupFixCMD.ExecuteNonQuery();
                            continue;
                        }

                        insertCmd.Parameters[0].Value = wmoid;

                        var inserted = new List <uint>();

                        if (wmo.groupFileDataIDs != null)
                        {
                            foreach (var groupFileDataID in wmo.groupFileDataIDs)
                            {
                                insertEntry(insertCmd, groupFileDataID, "wmo group");
                            }
                        }

                        if (wmo.doodadIds != null)
                        {
                            foreach (var doodadID in wmo.doodadIds)
                            {
                                if (inserted.Contains(doodadID))
                                {
                                    continue;
                                }

                                inserted.Add(doodadID);

                                insertEntry(insertCmd, doodadID, "wmo doodad");
                            }
                        }

                        if (wmo.textures == null && wmo.materials != null)
                        {
                            foreach (var material in wmo.materials)
                            {
                                if (material.texture1 == 0 || inserted.Contains(material.texture1))
                                {
                                    continue;
                                }

                                inserted.Add(material.texture1);
                                insertEntry(insertCmd, material.texture1, "wmo texture");

                                if (material.texture2 == 0 || inserted.Contains(material.texture2))
                                {
                                    continue;
                                }

                                inserted.Add(material.texture2);
                                insertEntry(insertCmd, material.texture2, "wmo texture");
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                    }
                }
            }
            #endregion

            #region WDT
            var wdtids         = new List <uint>();
            var wdtfullnamemap = new Dictionary <string, uint>();
            using (var cmd = dbConn.CreateCommand())
            {
                Console.WriteLine("[WDT] Generating list of WDT files..");
                cmd.CommandText = "SELECT id, filename from wow_rootfiles WHERE type = 'wdt' AND filename IS NOT NULL ORDER BY id DESC";
                var reader = cmd.ExecuteReader();

                while (reader.Read())
                {
                    var filename = (string)reader["filename"];
                    var wdtid    = uint.Parse(reader["id"].ToString());
                    if (filename.Contains("_mpv") || filename.Contains("_lgt") || filename.Contains("_occ") || filename.Contains("_fogs"))
                    {
                        continue;
                    }
                    wdtfullnamemap.Add(filename, wdtid);
                }
            }

            using (var cmd = dbConn.CreateCommand())
            {
                if (fullrun)
                {
                    cmd.CommandText = "SELECT id, filename from wow_rootfiles WHERE type = 'wdt' ORDER BY id DESC";
                }
                else
                {
                    Console.WriteLine("[WDT] Generating list of files to process..");
                    cmd.CommandText = "SELECT id, filename from wow_rootfiles WHERE type = 'wdt' AND id NOT IN (SELECT parent FROM wow_rootfiles_links) ORDER BY id DESC";
                }
                var reader = cmd.ExecuteReader();

                while (reader.Read())
                {
                    //var filename = (string)reader["filename"];
                    var wdtid = uint.Parse(reader["id"].ToString());
                    //if (filename.Contains("_mpv") || filename.Contains("_lgt") || filename.Contains("_occ") || filename.Contains("_fogs"))
                    //   continue;
                    wdtids.Add(wdtid);
                }

                reader.Close();

                foreach (var wdtid in wdtids)
                {
                    Console.WriteLine("[WDT] Loading " + wdtid);

                    insertCmd.Parameters[0].Value = wdtid;
                    try
                    {
                        var wdtreader = new WDTReader();
                        wdtreader.LoadWDT(wdtid);

                        if (wdtreader.wdtfile.modf.id != 0)
                        {
                            Console.WriteLine("WDT has WMO ID: " + wdtreader.wdtfile.modf.id);
                            insertEntry(insertCmd, wdtreader.wdtfile.modf.id, "wdt wmo");
                        }

                        foreach (var records in wdtreader.stringTileFiles)
                        {
                            insertEntry(insertCmd, records.Value.rootADT, "root adt");
                            insertEntry(insertCmd, records.Value.tex0ADT, "tex0 adt");
                            insertEntry(insertCmd, records.Value.lodADT, "lod adt");
                            insertEntry(insertCmd, records.Value.obj0ADT, "obj0 adt");
                            insertEntry(insertCmd, records.Value.obj1ADT, "obj1 adt");
                            insertEntry(insertCmd, records.Value.mapTexture, "map texture");
                            insertEntry(insertCmd, records.Value.mapTextureN, "mapn texture");
                            insertEntry(insertCmd, records.Value.minimapTexture, "minimap texture");
                        }
                    }catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                    }
                }
            }
            #endregion

            #region ADT
            var adtids     = new Dictionary <uint, Dictionary <(byte, byte), uint> >();
            var wdtmapping = new Dictionary <string, uint>();

            using (var cmd = dbConn.CreateCommand())
            {
                if (fullrun)
                {
                    cmd.CommandText = " SELECT id, filename from wow_rootfiles WHERE filename LIKE '%adt' AND filename NOT LIKE '%_obj0.adt' AND filename NOT LIKE '%_obj1.adt' AND filename NOT LIKE '%_lod.adt' AND filename NOT LIKE '%tex0.adt' AND filename NOT LIKE '%tex1.adt' ORDER BY id DESC ";
                }
                else
                {
                    Console.WriteLine("[ADT] Generating list of files to process..");
                    cmd.CommandText = " SELECT id, filename from wow_rootfiles WHERE filename LIKE '%adt' AND filename NOT LIKE '%_obj0.adt' AND filename NOT LIKE '%_obj1.adt' AND filename NOT LIKE '%_lod.adt' AND filename NOT LIKE '%tex0.adt' AND filename NOT LIKE '%tex1.adt' AND id NOT IN (SELECT parent FROM wow_rootfiles_links) ORDER BY id DESC";
                }
                var reader = cmd.ExecuteReader();

                while (reader.Read())
                {
                    var filename = (string)reader["filename"];
                    var mapname  = filename.Replace("world/maps/", "").Substring(0, filename.Replace("world/maps/", "").IndexOf("/"));
                    var exploded = Path.GetFileNameWithoutExtension(filename).Split('_');

                    for (var i = 0; i < exploded.Length; i++)
                    {
                        //Console.WriteLine(i + ": " + exploded[i]);
                    }

                    byte tileX = 0;
                    byte tileY = 0;

                    if (!byte.TryParse(exploded[exploded.Length - 2], out tileX) || !byte.TryParse(exploded[exploded.Length - 1], out tileY))
                    {
                        throw new FormatException("An error occured converting coordinates from " + filename + " to bytes");
                    }

                    if (!wdtmapping.ContainsKey(mapname))
                    {
                        var wdtname = "world/maps/" + mapname + "/" + mapname + ".wdt";
                        if (!wdtfullnamemap.ContainsKey(wdtname))
                        {
                            Console.WriteLine("Unable to get filedataid for " + mapname + ", skipping...");
                            wdtmapping.Remove(mapname);
                            continue;
                        }
                        wdtmapping.Add(mapname, wdtfullnamemap[wdtname]);
                        if (wdtmapping[mapname] == 0)
                        {
                            // TODO: Support WDTs removed in current build
                            Console.WriteLine("Unable to get filedataid for " + mapname + ", skipping...");
                            wdtmapping.Remove(mapname);
                            continue;

                            /*
                             * var wdtconn = new MySqlConnection(File.ReadAllText("connectionstring.txt"));
                             * wdtconn.Open();
                             * using (var wdtcmd = wdtconn.CreateCommand())
                             * {
                             *  wdtcmd.CommandText = "SELECT id from wow_rootfiles WHERE filename = '" + wdtname + "'";
                             *  var wdtread = wdtcmd.ExecuteReader();
                             *  while (wdtread.Read())
                             *  {
                             *      wdtmapping[mapname] = uint.Parse(wdtread["id"].ToString());
                             *  }
                             * }
                             * wdtconn.Close();*/
                        }

                        adtids.Add(wdtmapping[mapname], new Dictionary <(byte, byte), uint>());
                    }

                    var id = uint.Parse(reader["id"].ToString());

                    if (id == 0)
                    {
                        Console.WriteLine("Root ADT " + tileX + ", " + tileY + " with ID 0 on WDT " + wdtmapping[mapname]);
                        continue;
                    }

                    if (wdtmapping.ContainsKey(mapname))
                    {
                        adtids[wdtmapping[mapname]].Add((tileX, tileY), id);
                    }
                }

                reader.Close();

                foreach (var wdtid in adtids)
                {
                    foreach (var adtid in wdtid.Value)
                    {
                        var inserted = new List <uint>();
                        Console.WriteLine("[ADT] Loading " + adtid.Key.Item1 + ", " + adtid.Key.Item2 + "(" + adtid.Value + ")");

                        insertCmd.Parameters[0].Value = adtid.Value;

                        var adtreader = new ADTReader();
                        try
                        {
                            adtreader.LoadADT(wdtid.Key, adtid.Key.Item1, adtid.Key.Item2);
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                            continue;
                        }

                        if (adtreader.adtfile.objects.m2Names.filenames != null)
                        {
                            Console.WriteLine(adtid + " is still using old filenames, skipping!");
                        }
                        else
                        {
                            foreach (var worldmodel in adtreader.adtfile.objects.worldModels.entries)
                            {
                                if (inserted.Contains(worldmodel.mwidEntry))
                                {
                                    continue;
                                }

                                inserted.Add(worldmodel.mwidEntry);
                                insertEntry(insertCmd, worldmodel.mwidEntry, "adt worldmodel");
                            }

                            foreach (var doodad in adtreader.adtfile.objects.models.entries)
                            {
                                if (inserted.Contains(doodad.mmidEntry))
                                {
                                    continue;
                                }

                                insertEntry(insertCmd, doodad.mmidEntry, "adt doodad");
                                inserted.Add(doodad.mmidEntry);
                            }
                        }
                    }
                }
            }
            #endregion
        }
예제 #10
0
        public static TerrainWindow.WorldModel LoadWMO(string filename, CacheStorage cache)
        {
            if (cache.worldModelBatches.ContainsKey(filename))
            {
                return(cache.worldModelBatches[filename]);
            }

            WoWFormatLib.Structs.WMO.WMO wmo = new WoWFormatLib.Structs.WMO.WMO();

            if (cache.worldModels.ContainsKey(filename))
            {
                wmo = cache.worldModels[filename];
            }
            else
            {
                //Load WMO from file
                if (WoWFormatLib.Utils.CASC.FileExists(filename))
                {
                    var wmoreader = new WMOReader();
                    wmoreader.LoadWMO(filename);
                    cache.worldModels.Add(filename, wmoreader.wmofile);
                    wmo = wmoreader.wmofile;
                }
                else
                {
                    throw new Exception("WMO " + filename + " does not exist!");
                }
            }

            var wmobatch = new TerrainWindow.WorldModel();

            wmobatch.groupBatches = new TerrainWindow.WorldModelGroupBatches[wmo.group.Count()];

            string[] groupNames = new string[wmo.group.Count()];

            for (int g = 0; g < wmo.group.Count(); g++)
            {
                if (wmo.group[g].mogp.vertices == null)
                {
                    continue;
                }

                wmobatch.groupBatches[g].vertexBuffer = GL.GenBuffer();
                wmobatch.groupBatches[g].indiceBuffer = GL.GenBuffer();

                GL.BindBuffer(BufferTarget.ArrayBuffer, wmobatch.groupBatches[g].vertexBuffer);

                TerrainWindow.M2Vertex[] wmovertices = new TerrainWindow.M2Vertex[wmo.group[g].mogp.vertices.Count()];

                for (int i = 0; i < wmo.groupNames.Count(); i++)
                {
                    if (wmo.group[g].mogp.nameOffset == wmo.groupNames[i].offset)
                    {
                        groupNames[g] = wmo.groupNames[i].name.Replace(" ", "_");
                    }
                }

                if (groupNames[g] == "antiportal")
                {
                    continue;
                }

                for (int i = 0; i < wmo.group[g].mogp.vertices.Count(); i++)
                {
                    wmovertices[i].Position = new Vector3(wmo.group[g].mogp.vertices[i].vector.X, wmo.group[g].mogp.vertices[i].vector.Y, wmo.group[g].mogp.vertices[i].vector.Z);
                    wmovertices[i].Normal   = new Vector3(wmo.group[g].mogp.normals[i].normal.X, wmo.group[g].mogp.normals[i].normal.Y, wmo.group[g].mogp.normals[i].normal.Z);
                    if (wmo.group[g].mogp.textureCoords[0] == null)
                    {
                        wmovertices[i].TexCoord = new Vector2(0.0f, 0.0f);
                    }
                    else
                    {
                        wmovertices[i].TexCoord = new Vector2(wmo.group[g].mogp.textureCoords[0][i].X, wmo.group[g].mogp.textureCoords[0][i].Y);
                    }
                }

                //Push to buffer
                GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(wmovertices.Length * 8 * sizeof(float)), wmovertices, BufferUsageHint.StaticDraw);

                //Switch to Index buffer
                GL.BindBuffer(BufferTarget.ElementArrayBuffer, wmobatch.groupBatches[g].indiceBuffer);

                List <uint> wmoindicelist = new List <uint>();
                for (int i = 0; i < wmo.group[g].mogp.indices.Count(); i++)
                {
                    wmoindicelist.Add(wmo.group[g].mogp.indices[i].indice);
                }

                wmobatch.groupBatches[g].indices = wmoindicelist.ToArray();

                GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(wmobatch.groupBatches[g].indices.Length * sizeof(uint)), wmobatch.groupBatches[g].indices, BufferUsageHint.StaticDraw);
            }

            GL.Enable(EnableCap.Texture2D);

            wmobatch.mats = new TerrainWindow.Material[wmo.materials.Count()];
            for (int i = 0; i < wmo.materials.Count(); i++)
            {
                for (int ti = 0; ti < wmo.textures.Count(); ti++)
                {
                    if (wmo.textures[ti].startOffset == wmo.materials[i].texture1)
                    {
                        wmobatch.mats[i].texture1  = wmo.materials[i].texture1;
                        wmobatch.mats[i].textureID = BLPLoader.LoadTexture(wmo.textures[ti].filename, cache);
                        wmobatch.mats[i].filename  = wmo.textures[ti].filename;
                    }
                }
            }

            wmobatch.doodads = new TerrainWindow.WMODoodad[wmo.doodadDefinitions.Count()];

            for (int i = 0; i < wmo.doodadDefinitions.Count(); i++)
            {
                for (int j = 0; j < wmo.doodadNames.Count(); j++)
                {
                    if (wmo.doodadDefinitions[i].offset == wmo.doodadNames[j].startOffset)
                    {
                        wmobatch.doodads[i].filename = wmo.doodadNames[j].filename;
                        M2Loader.LoadM2(wmobatch.doodads[i].filename, cache);
                    }
                }
                wmobatch.doodads[i].flags    = wmo.doodadDefinitions[i].flags;
                wmobatch.doodads[i].position = new Vector3(wmo.doodadDefinitions[i].position.X, wmo.doodadDefinitions[i].position.Y, wmo.doodadDefinitions[i].position.Z);
                wmobatch.doodads[i].rotation = new Quaternion(wmo.doodadDefinitions[i].rotation.X, wmo.doodadDefinitions[i].rotation.Y, wmo.doodadDefinitions[i].rotation.Z, wmo.doodadDefinitions[i].rotation.W);
                wmobatch.doodads[i].scale    = wmo.doodadDefinitions[i].scale;
                wmobatch.doodads[i].color    = new Vector4(wmo.doodadDefinitions[i].color[0], wmo.doodadDefinitions[i].color[1], wmo.doodadDefinitions[i].color[2], wmo.doodadDefinitions[i].color[3]);
            }

            int numRenderbatches = 0;

            //Get total amount of render batches
            for (int i = 0; i < wmo.group.Count(); i++)
            {
                if (wmo.group[i].mogp.renderBatches == null)
                {
                    continue;
                }
                numRenderbatches = numRenderbatches + wmo.group[i].mogp.renderBatches.Count();
            }

            wmobatch.wmoRenderBatch = new TerrainWindow.RenderBatch[numRenderbatches];

            int rb = 0;

            for (int g = 0; g < wmo.group.Count(); g++)
            {
                var group = wmo.group[g];
                if (group.mogp.renderBatches == null)
                {
                    continue;
                }
                for (int i = 0; i < group.mogp.renderBatches.Count(); i++)
                {
                    wmobatch.wmoRenderBatch[rb].firstFace = group.mogp.renderBatches[i].firstFace;
                    wmobatch.wmoRenderBatch[rb].numFaces  = group.mogp.renderBatches[i].numFaces;
                    uint matID = 0;

                    if (group.mogp.renderBatches[i].flags == 2)
                    {
                        matID = (uint)group.mogp.renderBatches[i].possibleBox2_3;
                    }
                    else
                    {
                        matID = group.mogp.renderBatches[i].materialID;
                    }

                    for (int ti = 0; ti < wmobatch.mats.Count(); ti++)
                    {
                        if (wmo.materials[matID].texture1 == wmobatch.mats[ti].texture1)
                        {
                            wmobatch.wmoRenderBatch[rb].materialID = new uint[] { (uint)wmobatch.mats[ti].textureID };
                        }
                    }

                    wmobatch.wmoRenderBatch[rb].blendType = wmo.materials[group.mogp.renderBatches[i].materialID].blendMode;
                    wmobatch.wmoRenderBatch[rb].groupID   = (uint)g;
                    rb++;
                }
            }
            cache.worldModelBatches.Add(filename, wmobatch);

            return(wmobatch);
        }
예제 #11
0
        public static void ExportWMO(string filename, string outdir, BackgroundWorker exportworker = null, string destinationOverride = null, ushort doodadSetExportID = ushort.MaxValue)
        {
            filename = filename.ToLower();


            if (exportworker == null)
            {
                exportworker = new BackgroundWorker();
                exportworker.WorkerReportsProgress = true;
            }

            exportworker.ReportProgress(5, "Reading WMO..");

            var wmo = new WMOReader();

            wmo.LoadWMO(filename);


            var customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();

            customCulture.NumberFormat.NumberDecimalSeparator    = ".";
            System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;

            exportworker.ReportProgress(30, "Reading WMO..");

            uint totalVertices = 0;

            var groups = new Structs.WMOGroup[wmo.wmofile.group.Count()];

            for (var g = 0; g < wmo.wmofile.group.Count(); g++)
            {
                if (wmo.wmofile.group[g].mogp.vertices == null)
                {
                    continue;
                }
                for (var i = 0; i < wmo.wmofile.groupNames.Count(); i++)
                {
                    if (wmo.wmofile.group[g].mogp.nameOffset == wmo.wmofile.groupNames[i].offset)
                    {
                        groups[g].name = wmo.wmofile.groupNames[i].name.Replace(" ", "_");
                    }
                }

                if (groups[g].name == "antiportal")
                {
                    //Console.WriteLine("Group is antiportal");
                    continue;
                }

                groups[g].verticeOffset = totalVertices;
                groups[g].vertices      = new Structs.Vertex[wmo.wmofile.group[g].mogp.vertices.Count()];

                for (var i = 0; i < wmo.wmofile.group[g].mogp.vertices.Count(); i++)
                {
                    groups[g].vertices[i].Position = new Structs.Vector3D()
                    {
                        X = wmo.wmofile.group[g].mogp.vertices[i].vector.X * -1,
                        Y = wmo.wmofile.group[g].mogp.vertices[i].vector.Z,
                        Z = wmo.wmofile.group[g].mogp.vertices[i].vector.Y
                    };

                    groups[g].vertices[i].Normal = new Structs.Vector3D()
                    {
                        X = wmo.wmofile.group[g].mogp.normals[i].normal.X,
                        Y = wmo.wmofile.group[g].mogp.normals[i].normal.Z,
                        Z = wmo.wmofile.group[g].mogp.normals[i].normal.Y
                    };

                    groups[g].vertices[i].TexCoord = new Structs.Vector2D()
                    {
                        X = wmo.wmofile.group[g].mogp.textureCoords[0][i].X,
                        Y = wmo.wmofile.group[g].mogp.textureCoords[0][i].Y
                    };

                    totalVertices++;
                }

                var indicelist = new List <uint>();

                for (var i = 0; i < wmo.wmofile.group[g].mogp.indices.Count(); i++)
                {
                    indicelist.Add(wmo.wmofile.group[g].mogp.indices[i].indice);
                }

                groups[g].indices = indicelist.ToArray();
            }

            if (destinationOverride == null)
            {
                // Create output directory
                if (!string.IsNullOrEmpty(filename))
                {
                    if (!Directory.Exists(Path.Combine(outdir, Path.GetDirectoryName(filename))))
                    {
                        Directory.CreateDirectory(Path.Combine(outdir, Path.GetDirectoryName(filename)));
                    }
                }
                else
                {
                    if (!Directory.Exists(outdir))
                    {
                        Directory.CreateDirectory(outdir);
                    }
                }
            }
            #region M2Export
            bool exportM2 = Managers.ConfigurationManager.WMOExportM2;
            if (exportM2)
            {
                StreamWriter doodadSW;

                if (destinationOverride == null)
                {
                    if (!string.IsNullOrEmpty(filename))
                    {
                        doodadSW = new StreamWriter(Path.Combine(outdir, Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename.Replace(" ", "")) + "_ModelPlacementInformation.csv"));
                    }
                    else
                    {
                        doodadSW = new StreamWriter(Path.Combine(outdir, Path.GetDirectoryName(filename), filename + "_ModelPlacementInformation.csv"));
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(filename))
                    {
                        doodadSW = new StreamWriter(Path.Combine(outdir, destinationOverride, Path.GetFileNameWithoutExtension(filename).Replace(" ", "") + "_ModelPlacementInformation.csv"));
                    }
                    else
                    {
                        doodadSW = new StreamWriter(Path.Combine(outdir, destinationOverride, filename + "_ModelPlacementInformation.csv"));
                    }
                }

                exportworker.ReportProgress(55, "Exporting doodads..");

                doodadSW.WriteLine("ModelFile;PositionX;PositionY;PositionZ;RotationW;RotationX;RotationY;RotationZ;ScaleFactor;DoodadSet");

                for (var i = 0; i < wmo.wmofile.doodadSets.Count(); i++)
                {
                    var doodadSet = wmo.wmofile.doodadSets[i];

                    var currentDoodadSetName = doodadSet.setName.Replace("Set_", "").Replace("SET_", "").Replace("$DefaultGlobal", "Default");

                    if (doodadSetExportID != ushort.MaxValue)
                    {
                        if (i != 0 && i != doodadSetExportID)
                        {
                            //Console.WriteLine("Skipping doodadset with ID " + i + " (" + currentDoodadSetName + ") because export filter is set to " + doodadSetExportID);
                            continue;
                        }
                    }

                    //Console.WriteLine("At doodadset " + i + " (" + currentDoodadSetName + ")");

                    for (var j = doodadSet.firstInstanceIndex; j < (doodadSet.firstInstanceIndex + doodadSet.numDoodads); j++)
                    {
                        foreach (var doodadNameEntry in wmo.wmofile.doodadNames)
                        {
                            var doodadDefinition = wmo.wmofile.doodadDefinitions[j];

                            if (doodadNameEntry.startOffset == doodadDefinition.offset)
                            {
                                var doodadFileName = doodadNameEntry.filename.Replace(".MDX", ".M2").Replace(".MDL", ".M2");

                                if (destinationOverride == null)
                                {
                                    if (Managers.ConfigurationManager.WMODoodadsGlobalPath)
                                    {
                                        if (!File.Exists(Path.Combine(outdir, Path.GetFileName(doodadFileName.ToLower()).Replace(".m2", ".obj"))))
                                        {
                                            M2Exporter.ExportM2(doodadFileName, outdir, exportworker);
                                        }
                                    }
                                    else
                                    {
                                        if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(filename), Path.GetFileName(doodadFileName.ToLower()).Replace(".m2", ".obj"))))
                                        {
                                            M2Exporter.ExportM2(doodadFileName, Path.Combine(outdir, Path.GetDirectoryName(filename)), exportworker);
                                        }
                                    }
                                }
                                else
                                {
                                    if (!File.Exists(Path.Combine(destinationOverride, Path.GetFileName(doodadFileName.ToLower()).Replace(".m2", ".obj"))))
                                    {
                                        M2Exporter.ExportM2(doodadNameEntry.filename.Replace(".MDX", ".M2").Replace(".MDL", ".M2"), destinationOverride, exportworker);
                                    }
                                }

                                if (Managers.ConfigurationManager.WMODoodadsPlacementGlobalPath)
                                {
                                    doodadSW.WriteLine(doodadNameEntry.filename.ToLower().Replace(".mdx", ".m2").Replace(".mdl", ".m2").Replace(".m2", ".obj;") + doodadDefinition.position.X.ToString("F09") + ";" + doodadDefinition.position.Y.ToString("F09") + ";" + doodadDefinition.position.Z.ToString("F09") + ";" + doodadDefinition.rotation.W.ToString("F15") + ";" + doodadDefinition.rotation.X.ToString("F15") + ";" + doodadDefinition.rotation.Y.ToString("F15") + ";" + doodadDefinition.rotation.Z.ToString("F15") + ";" + doodadDefinition.scale + ";" + currentDoodadSetName);
                                }
                                else
                                {
                                    doodadSW.WriteLine(Path.GetFileNameWithoutExtension(doodadNameEntry.filename).ToLower() + ".obj;" + doodadDefinition.position.X.ToString("F09") + ";" + doodadDefinition.position.Y.ToString("F09") + ";" + doodadDefinition.position.Z.ToString("F09") + ";" + doodadDefinition.rotation.W.ToString("F15") + ";" + doodadDefinition.rotation.X.ToString("F15") + ";" + doodadDefinition.rotation.Y.ToString("F15") + ";" + doodadDefinition.rotation.Z.ToString("F15") + ";" + doodadDefinition.scale + ";" + currentDoodadSetName);
                                }

                                break;
                            }
                        }
                    }
                }
                doodadSW.Close();
            }
            #endregion
            var mtlsb     = new StringBuilder();
            var textureID = 0;

            if (wmo.wmofile.materials == null)
            {
                return;
            }

            var materials = new Structs.Material[wmo.wmofile.materials.Count()];

            for (var i = 0; i < wmo.wmofile.materials.Count(); i++)
            {
                for (var ti = 0; ti < wmo.wmofile.textures.Count(); ti++)
                {
                    if (wmo.wmofile.textures[ti].startOffset == wmo.wmofile.materials[i].texture1)
                    {
                        materials[i].textureID = textureID + i;
                        materials[i].filename  = Path.GetFileNameWithoutExtension(wmo.wmofile.textures[ti].filename);

                        if (wmo.wmofile.materials[i].blendMode == 0)
                        {
                            materials[i].transparent = false;
                        }
                        else
                        {
                            materials[i].transparent = true;
                        }

                        if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(filename), materials[i].filename + ".png")))
                        {
                            var blpreader = new BLPReader();
                            blpreader.LoadBLP(Managers.ArchiveManager.ReadThisFile(wmo.wmofile.textures[ti].filename));

                            try
                            {
                                if (destinationOverride == null)
                                {
                                    blpreader.bmp.Save(Path.Combine(outdir, Path.GetDirectoryName(filename), materials[i].filename + ".png"));
                                }
                                else
                                {
                                    blpreader.bmp.Save(Path.Combine(outdir, destinationOverride, materials[i].filename.ToLower() + ".png"));
                                }
                            }
                            catch
                            {
                                //Error on file save
                            }
                        }

                        textureID++;
                    }
                }
            }

            //No idea how MTL files really work yet. Needs more investigation.
            foreach (var material in materials)
            {
                mtlsb.Append("newmtl " + material.filename + "\n");
                mtlsb.Append("Ns 96.078431\n");
                mtlsb.Append("Ka 1.000000 1.000000 1.000000\n");
                mtlsb.Append("Kd 0.640000 0.640000 0.640000\n");
                mtlsb.Append("Ks 0.000000 0.000000 0.000000\n");
                mtlsb.Append("Ke 0.000000 0.000000 0.000000\n");
                mtlsb.Append("Ni 1.000000\n");
                mtlsb.Append("d 1.000000\n");
                mtlsb.Append("illum 1\n");
                mtlsb.Append("map_Kd " + material.filename + ".png\n");
                if (material.transparent)
                {
                    mtlsb.Append("map_d " + material.filename + ".png\n");
                }

                /* //temporary removed
                 * if (ConfigurationManager.AppSettings["textureMetadata"] == "True")
                 * {
                 *  mtlsb.Append("blend " + material.blendMode + "\n");
                 *  mtlsb.Append("shader " + material.shaderID + "\n");
                 *  mtlsb.Append("terrain " + material.terrainType + "\n");
                 * }
                 */
            }

            if (!string.IsNullOrEmpty(filename))
            {
                if (destinationOverride == null)
                {
                    File.WriteAllText(Path.Combine(outdir, filename.Replace(".wmo", ".mtl")), mtlsb.ToString());
                }
                else
                {
                    File.WriteAllText(Path.Combine(outdir, destinationOverride, Path.GetFileName(filename.ToLower()).Replace(".wmo", ".mtl")), mtlsb.ToString());
                }
            }
            else
            {
                if (destinationOverride == null)
                {
                    File.WriteAllText(Path.Combine(outdir, filename + ".mtl"), mtlsb.ToString());
                }
                else
                {
                    File.WriteAllText(Path.Combine(outdir, destinationOverride, filename + ".mtl"), mtlsb.ToString());
                }
            }

            exportworker.ReportProgress(75, "Exporting model..");

            var numRenderbatches = 0;
            //Get total amount of render batches
            for (var i = 0; i < wmo.wmofile.group.Count(); i++)
            {
                if (wmo.wmofile.group[i].mogp.renderBatches == null)
                {
                    continue;
                }
                numRenderbatches = numRenderbatches + wmo.wmofile.group[i].mogp.renderBatches.Count();
            }


            var rb = 0;
            for (var g = 0; g < wmo.wmofile.group.Count(); g++)
            {
                groups[g].renderBatches = new Structs.RenderBatch[numRenderbatches];

                var group = wmo.wmofile.group[g];
                if (group.mogp.renderBatches == null)
                {
                    continue;
                }

                for (var i = 0; i < group.mogp.renderBatches.Count(); i++)
                {
                    var batch = group.mogp.renderBatches[i];

                    groups[g].renderBatches[rb].firstFace = batch.firstFace;
                    groups[g].renderBatches[rb].numFaces  = batch.numFaces;

                    if (batch.flags == 2)
                    {
                        groups[g].renderBatches[rb].materialID = (uint)batch.possibleBox2_3;
                    }
                    else
                    {
                        groups[g].renderBatches[rb].materialID = batch.materialID;
                    }
                    groups[g].renderBatches[rb].blendType = wmo.wmofile.materials[batch.materialID].blendMode;
                    groups[g].renderBatches[rb].groupID   = (uint)g;
                    rb++;
                }
            }

            exportworker.ReportProgress(95, "Writing files..");

            StreamWriter objsw;
            if (!string.IsNullOrEmpty(filename))
            {
                if (destinationOverride == null)
                {
                    objsw = new StreamWriter(Path.Combine(outdir, filename.Replace(".wmo", ".obj")));
                }
                else
                {
                    objsw = new StreamWriter(Path.Combine(outdir, destinationOverride, Path.GetFileName(filename.ToLower()).Replace(".wmo", ".obj")));
                }

                objsw.WriteLine("# Written by Marlamin's WoW Export Tools. Original file: " + filename);
                objsw.WriteLine("mtllib " + Path.GetFileNameWithoutExtension(filename) + ".mtl");
            }
            else
            {
                if (destinationOverride == null)
                {
                    objsw = new StreamWriter(Path.Combine(outdir, filename + ".obj"));
                }
                else
                {
                    objsw = new StreamWriter(Path.Combine(outdir, destinationOverride, filename + ".obj"));
                }
                objsw.WriteLine("# Written by Marlamin's WoW Export Tools. Original file id: " + filename);
                objsw.WriteLine("mtllib " + filename + ".mtl");
            }

            foreach (var group in groups)
            {
                if (group.vertices == null)
                {
                    continue;
                }
                //Console.WriteLine("Writing " + group.name);
                objsw.WriteLine("o " + group.name);

                //Added thunderysteak's adjustment (original commit: ed067c7c6e8321c33ef0f3679d33c9c472dcefc3)
                foreach (var vertex in group.vertices)
                {
                    objsw.WriteLine("v " + vertex.Position.X + " " + vertex.Position.Y + " " + vertex.Position.Z);
                }

                foreach (var vertex in group.vertices)
                {
                    objsw.WriteLine("vt " + vertex.TexCoord.X + " " + (vertex.TexCoord.Y - 1) * -1);
                }
                foreach (var vertex in group.vertices)
                {
                    objsw.WriteLine("vn " + (-vertex.Normal.X).ToString("F12") + " " + vertex.Normal.Y.ToString("F12") + " " + vertex.Normal.Z.ToString("F12"));
                }

                var indices = group.indices;

                foreach (var renderbatch in group.renderBatches)
                {
                    var i = renderbatch.firstFace;
                    if (renderbatch.numFaces > 0)
                    {
                        //thunderysteak's adjustment
                        //objsw.WriteLine("o " + group.name); //?
                        objsw.WriteLine("g " + group.name);//3DS Max's OBJ importer fails with invalid normal index without groups being defined
                        //--------------------------
                        objsw.WriteLine("usemtl " + materials[renderbatch.materialID].filename);
                        objsw.WriteLine("s 1");
                        while (i < (renderbatch.firstFace + renderbatch.numFaces))
                        {
                            objsw.WriteLine("f " + (indices[i] + group.verticeOffset + 1) + "/" + (indices[i] + group.verticeOffset + 1) + "/" + (indices[i] + group.verticeOffset + 1) + " " + (indices[i + 1] + group.verticeOffset + 1) + "/" + (indices[i + 1] + group.verticeOffset + 1) + "/" + (indices[i + 1] + group.verticeOffset + 1) + " " + (indices[i + 2] + group.verticeOffset + 1) + "/" + (indices[i + 2] + group.verticeOffset + 1) + "/" + (indices[i + 2] + group.verticeOffset + 1));
                            i += 3;
                        }
                    }
                }
            }
            objsw.Close();
            //Console.WriteLine("Done loading WMO file!");
        }
예제 #12
0
        public static void exportWMO(string file, BackgroundWorker exportworker = null, string destinationOverride = null)
        {
            if (exportworker == null)
            {
                exportworker = new BackgroundWorker();
                exportworker.WorkerReportsProgress = true;
            }

            Console.WriteLine("Loading WMO file..");

            exportworker.ReportProgress(5, "Reading WMO..");

            var       outdir = ConfigurationManager.AppSettings["outdir"];
            WMOReader reader = new WMOReader();

            reader.LoadWMO(file);

            System.Globalization.CultureInfo customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
            customCulture.NumberFormat.NumberDecimalSeparator    = ".";
            System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;

            exportworker.ReportProgress(30, "Reading WMO..");

            uint totalVertices = 0;

            var groups = new Structs.WMOGroup[reader.wmofile.group.Count()];

            for (int g = 0; g < reader.wmofile.group.Count(); g++)
            {
                Console.WriteLine("Loading group #" + g);
                if (reader.wmofile.group[g].mogp.vertices == null)
                {
                    Console.WriteLine("Group has no vertices!");  continue;
                }
                for (int i = 0; i < reader.wmofile.groupNames.Count(); i++)
                {
                    if (reader.wmofile.group[g].mogp.nameOffset == reader.wmofile.groupNames[i].offset)
                    {
                        groups[g].name = reader.wmofile.groupNames[i].name.Replace(" ", "_");
                    }
                }

                if (groups[g].name == "antiportal")
                {
                    Console.WriteLine("Group is antiportal"); continue;
                }

                groups[g].verticeOffset = totalVertices;
                groups[g].vertices      = new Structs.Vertex[reader.wmofile.group[g].mogp.vertices.Count()];

                for (int i = 0; i < reader.wmofile.group[g].mogp.vertices.Count(); i++)
                {
                    groups[g].vertices[i].Position = new Vector3(reader.wmofile.group[g].mogp.vertices[i].vector.X * -1, reader.wmofile.group[g].mogp.vertices[i].vector.Z, reader.wmofile.group[g].mogp.vertices[i].vector.Y);
                    groups[g].vertices[i].Normal   = new Vector3(reader.wmofile.group[g].mogp.normals[i].normal.X, reader.wmofile.group[g].mogp.normals[i].normal.Z, reader.wmofile.group[g].mogp.normals[i].normal.Y);
                    groups[g].vertices[i].TexCoord = new Vector2(reader.wmofile.group[g].mogp.textureCoords[0][i].X, reader.wmofile.group[g].mogp.textureCoords[0][i].Y);
                    totalVertices++;
                }

                var indicelist = new List <uint>();

                for (int i = 0; i < reader.wmofile.group[g].mogp.indices.Count(); i++)
                {
                    indicelist.Add(reader.wmofile.group[g].mogp.indices[i].indice);
                }

                groups[g].indices = indicelist.ToArray();
            }

            if (destinationOverride == null)
            {
                // Create output directory
                if (!Directory.Exists(Path.Combine(outdir, Path.GetDirectoryName(file))))
                {
                    Directory.CreateDirectory(Path.Combine(outdir, Path.GetDirectoryName(file)));
                }
            }

            StreamWriter doodadSW;

            if (destinationOverride == null)
            {
                doodadSW = new StreamWriter(Path.Combine(outdir, Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(file).Replace(" ", "") + "_ModelPlacementInformation.csv"));
            }
            else
            {
                doodadSW = new StreamWriter(Path.Combine(outdir, destinationOverride, Path.GetFileNameWithoutExtension(file).Replace(" ", "") + "_ModelPlacementInformation.csv"));
            }

            exportworker.ReportProgress(55, "Exporting doodads..");

            doodadSW.WriteLine("ModelFile;PositionX;PositionY;PositionZ;RotationW;RotationX;RotationY;RotationZ;ScaleFactor;DoodadSet");

            string currentDoodadSetName = "";

            for (int i = 0; i < reader.wmofile.doodadDefinitions.Count(); i++)
            {
                var doodadDefinition = reader.wmofile.doodadDefinitions[i];

                foreach (var doodadSet in reader.wmofile.doodadSets)
                {
                    if (doodadSet.firstInstanceIndex == i)
                    {
                        Console.WriteLine("At set: " + doodadSet.setName);
                        currentDoodadSetName = doodadSet.setName.Replace("Set_", "").Replace("SET_", "").Replace("$DefaultGlobal", "Default");
                    }
                }

                foreach (var doodadNameEntry in reader.wmofile.doodadNames)
                {
                    if (doodadNameEntry.startOffset == doodadDefinition.offset)
                    {
                        if (!File.Exists(Path.GetFileNameWithoutExtension(doodadNameEntry.filename).ToLower() + ".obj"))
                        {
                            if (destinationOverride == null)
                            {
                                M2Exporter.exportM2(doodadNameEntry.filename.Replace(".MDX", ".M2").Replace(".MDL", ".M2"), null, Path.Combine(outdir, Path.GetDirectoryName(file)));
                            }
                            else
                            {
                                M2Exporter.exportM2(doodadNameEntry.filename.Replace(".MDX", ".M2").Replace(".MDL", ".M2"), null, destinationOverride);
                            }
                        }
                        doodadSW.WriteLine(Path.GetFileNameWithoutExtension(doodadNameEntry.filename).ToLower() + ".obj;" + doodadDefinition.position.X.ToString("F09") + ";" + doodadDefinition.position.Y.ToString("F09") + ";" + doodadDefinition.position.Z.ToString("F09") + ";" + doodadDefinition.rotation.W.ToString("F15") + ";" + doodadDefinition.rotation.X.ToString("F15") + ";" + doodadDefinition.rotation.Y.ToString("F15") + ";" + doodadDefinition.rotation.Z.ToString("F15") + ";" + doodadDefinition.scale + ";" + currentDoodadSetName);
                    }
                }
            }

            doodadSW.Close();

            exportworker.ReportProgress(65, "Exporting textures..");

            var mtlsb     = new StringBuilder();
            var textureID = 0;

            if (reader.wmofile.materials == null)
            {
                Console.WriteLine("Materials empty"); return;
            }
            var materials = new Structs.Material[reader.wmofile.materials.Count()];

            for (int i = 0; i < reader.wmofile.materials.Count(); i++)
            {
                for (int ti = 0; ti < reader.wmofile.textures.Count(); ti++)
                {
                    if (reader.wmofile.textures[ti].startOffset == reader.wmofile.materials[i].texture1)
                    {
                        //materials[i].textureID = BLPLoader.LoadTexture(reader.wmofile.textures[ti].filename, cache);
                        materials[i].textureID = textureID + i;
                        materials[i].filename  = Path.GetFileNameWithoutExtension(reader.wmofile.textures[ti].filename);

                        if (reader.wmofile.materials[i].blendMode == 0)
                        {
                            materials[i].transparent = false;
                        }
                        else
                        {
                            materials[i].transparent = true;
                        }

                        if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file), materials[i].filename + ".png")))
                        {
                            var blpreader = new BLPReader();

                            blpreader.LoadBLP(reader.wmofile.textures[ti].filename);

                            try
                            {
                                if (destinationOverride == null)
                                {
                                    blpreader.bmp.Save(Path.Combine(outdir, Path.GetDirectoryName(file), materials[i].filename + ".png"));
                                }
                                else
                                {
                                    blpreader.bmp.Save(Path.Combine(outdir, destinationOverride, materials[i].filename.ToLower() + ".png"));
                                }
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e.Message);
                            }
                        }

                        textureID++;
                    }
                }
            }

            //No idea how MTL files really work yet. Needs more investigation.
            foreach (var material in materials)
            {
                mtlsb.Append("newmtl " + material.filename + "\n");
                mtlsb.Append("Ns 96.078431\n");
                mtlsb.Append("Ka 1.000000 1.000000 1.000000\n");
                mtlsb.Append("Kd 0.640000 0.640000 0.640000\n");
                mtlsb.Append("Ks 0.000000 0.000000 0.000000\n");
                mtlsb.Append("Ke 0.000000 0.000000 0.000000\n");
                mtlsb.Append("Ni 1.000000\n");
                mtlsb.Append("d 1.000000\n");
                mtlsb.Append("illum 2\n");
                mtlsb.Append("map_Kd " + material.filename + ".png\n");
                if (material.transparent)
                {
                    mtlsb.Append("map_d " + material.filename + ".png\n");
                }
            }

            if (destinationOverride == null)
            {
                File.WriteAllText(Path.Combine(outdir, file.Replace(".wmo", ".mtl")), mtlsb.ToString());
            }
            else
            {
                File.WriteAllText(Path.Combine(outdir, destinationOverride, Path.GetFileName(file.ToLower()).Replace(".wmo", ".mtl")), mtlsb.ToString());
            }

            exportworker.ReportProgress(75, "Exporting model..");

            int numRenderbatches = 0;

            //Get total amount of render batches
            for (int i = 0; i < reader.wmofile.group.Count(); i++)
            {
                if (reader.wmofile.group[i].mogp.renderBatches == null)
                {
                    continue;
                }
                numRenderbatches = numRenderbatches + reader.wmofile.group[i].mogp.renderBatches.Count();
            }


            int rb = 0;

            for (int g = 0; g < reader.wmofile.group.Count(); g++)
            {
                groups[g].renderBatches = new Structs.RenderBatch[numRenderbatches];

                var group = reader.wmofile.group[g];
                if (group.mogp.renderBatches == null)
                {
                    continue;
                }
                for (int i = 0; i < group.mogp.renderBatches.Count(); i++)
                {
                    var batch = group.mogp.renderBatches[i];

                    groups[g].renderBatches[rb].firstFace = batch.firstFace;
                    groups[g].renderBatches[rb].numFaces  = batch.numFaces;

                    if (batch.flags == 2)
                    {
                        groups[g].renderBatches[rb].materialID = (uint)batch.possibleBox2_3;
                    }
                    else
                    {
                        groups[g].renderBatches[rb].materialID = batch.materialID;
                    }
                    groups[g].renderBatches[rb].blendType = reader.wmofile.materials[batch.materialID].blendMode;
                    groups[g].renderBatches[rb].groupID   = (uint)g;
                    rb++;
                }
            }

            exportworker.ReportProgress(95, "Writing files..");

            StreamWriter objsw;

            if (destinationOverride == null)
            {
                objsw = new StreamWriter(Path.Combine(outdir, file.Replace(".wmo", ".obj")));
            }
            else
            {
                objsw = new StreamWriter(Path.Combine(outdir, destinationOverride, Path.GetFileName(file.ToLower()).Replace(".wmo", ".obj")));
            }

            objsw.WriteLine("# Written by Marlamin's WoW OBJExporter. Original file: " + file);
            objsw.WriteLine("mtllib " + Path.GetFileNameWithoutExtension(file) + ".mtl");

            foreach (var group in groups)
            {
                if (group.vertices == null)
                {
                    continue;
                }
                Console.WriteLine("Writing " + group.name);
                objsw.WriteLine("g " + group.name);

                foreach (var vertex in group.vertices)
                {
                    objsw.WriteLine("v " + vertex.Position.X + " " + vertex.Position.Y + " " + vertex.Position.Z);
                    objsw.WriteLine("vt " + vertex.TexCoord.X + " " + -vertex.TexCoord.Y);
                    objsw.WriteLine("vn " + vertex.Normal.X.ToString("F12") + " " + vertex.Normal.Y.ToString("F12") + " " + vertex.Normal.Z.ToString("F12"));
                }

                var indices = group.indices;

                foreach (var renderbatch in group.renderBatches)
                {
                    var i = renderbatch.firstFace;
                    if (renderbatch.numFaces > 0)
                    {
                        objsw.WriteLine("usemtl " + materials[renderbatch.materialID].filename);
                        objsw.WriteLine("s 1");
                        while (i < (renderbatch.firstFace + renderbatch.numFaces))
                        {
                            objsw.WriteLine("f " + (indices[i] + group.verticeOffset + 1) + "/" + (indices[i] + group.verticeOffset + 1) + "/" + (indices[i] + group.verticeOffset + 1) + " " + (indices[i + 1] + group.verticeOffset + 1) + "/" + (indices[i + 1] + group.verticeOffset + 1) + "/" + (indices[i + 1] + group.verticeOffset + 1) + " " + (indices[i + 2] + group.verticeOffset + 1) + "/" + (indices[i + 2] + group.verticeOffset + 1) + "/" + (indices[i + 2] + group.verticeOffset + 1));
                            i = i + 3;
                        }
                    }
                }
            }
            objsw.Close();
            Console.WriteLine("Done loading WMO file!");
        }