Esempio n. 1
0
        public static void exportADT(string file, string outdir, string bakeQuality, BackgroundWorker exportworker = null)
        {
            if (exportworker == null)
            {
                exportworker = new BackgroundWorker
                {
                    WorkerReportsProgress = true
                };
            }

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

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

            var MaxSize      = 51200 / 3.0;
            var TileSize     = MaxSize / 32.0;
            var ChunkSize    = TileSize / 16.0;
            var UnitSize     = ChunkSize / 8.0;
            var UnitSizeHalf = UnitSize / 2.0;

            string mapname = file;

            mapname = mapname.Substring(mapname.LastIndexOf("\\", mapname.Length - 2) + 1);
            mapname = mapname.Substring(0, mapname.Length - 4);

            var reader = new ADTReader();

            var ADTfile = file;

            exportworker.ReportProgress(0, "Loading ADT " + file);

            if (Managers.ConfigurationManager.Profile <= 3) //WoTLK and below
            {
                reader.Load335ADT(ADTfile);
            }
            else
            {
                reader.LoadADT(ADTfile);
            }

            if (reader.adtfile.chunks == null)
            {
                throw new Exception("ADT OBJ Exporter: File has no chunks, skipping export!");
            }

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

            var renderBatches = new List <Structs.RenderBatch>();
            var verticelist   = new List <Structs.Vertex>();
            var indicelist    = new List <int>();
            var materials     = new Dictionary <int, string>();

            // Calculate ADT offset in world coordinates
            var adtStartX = reader.adtfile.chunks[0].header.position.X;
            var adtStartY = reader.adtfile.chunks[0].header.position.Y;

            // Calculate first chunk offset in world coordinates
            var initialChunkX = adtStartX + (reader.adtfile.chunks[0].header.indexX * ChunkSize) * -1;
            var initialChunkY = adtStartY + (reader.adtfile.chunks[0].header.indexY * ChunkSize) * -1;

            uint ci = 0;

            for (var x = 0; x < 16; x++)
            {
                for (var y = 0; y < 16; y++)
                {
                    var genx = (initialChunkX + (ChunkSize * x) * -1);
                    var geny = (initialChunkY + (ChunkSize * y) * -1);

                    var chunk = reader.adtfile.chunks[ci];

                    var off = verticelist.Count();

                    var batch = new Structs.RenderBatch();

                    for (int row = 0, idx = 0; row < 17; row++)
                    {
                        bool isSmallRow = (row % 2) != 0;
                        int  rowLength  = isSmallRow ? 8 : 9;

                        for (var col = 0; col < rowLength; col++)
                        {
                            var v = new Structs.Vertex();

                            v.Normal = new Structs.Vector3D
                            {
                                X = (double)chunk.normals.normal_0[idx] / 127,
                                Y = (double)chunk.normals.normal_2[idx] / 127,
                                Z = (double)chunk.normals.normal_1[idx] / 127
                            };

                            var px = geny - (col * UnitSize);
                            var py = chunk.vertices.vertices[idx++] + chunk.header.position.Z;
                            var pz = genx - (row * UnitSizeHalf);

                            v.Position = new Structs.Vector3D
                            {
                                X = px,
                                Y = py,
                                Z = pz
                            };

                            if ((row % 2) != 0)
                            {
                                v.Position.X = (px - UnitSizeHalf);
                            }

                            double ofs = col;
                            if (isSmallRow)
                            {
                                ofs += 0.5;
                            }

                            if (bakeQuality == "high")
                            {
                                double tx = ofs / 8d;
                                double ty = 1 - (row / 16d);
                                v.TexCoord = new Structs.Vector2D {
                                    X = tx, Y = ty
                                };
                            }
                            else
                            {
                                double tx = -(v.Position.X - initialChunkY) / TileSize;
                                double ty = (v.Position.Z - initialChunkX) / TileSize;

                                v.TexCoord = new Structs.Vector2D {
                                    X = tx, Y = ty
                                };
                            }
                            verticelist.Add(v);
                        }
                    }

                    batch.firstFace = (uint)indicelist.Count();

                    // Stupid C# and its structs
                    var holesHighRes = new byte[8];
                    holesHighRes[0] = chunk.header.holesHighRes_0;
                    holesHighRes[1] = chunk.header.holesHighRes_1;
                    holesHighRes[2] = chunk.header.holesHighRes_2;
                    holesHighRes[3] = chunk.header.holesHighRes_3;
                    holesHighRes[4] = chunk.header.holesHighRes_4;
                    holesHighRes[5] = chunk.header.holesHighRes_5;
                    holesHighRes[6] = chunk.header.holesHighRes_6;
                    holesHighRes[7] = chunk.header.holesHighRes_7;

                    for (int j = 9, xx = 0, yy = 0; j < 145; j++, xx++)
                    {
                        if (xx >= 8)
                        {
                            xx = 0; ++yy;
                        }
                        var isHole = true;

                        // Check if chunk is using low-res holes
                        if ((chunk.header.flags & 0x10000) == 0)
                        {
                            // Calculate current hole number
                            var currentHole = (int)Math.Pow(2,
                                                            Math.Floor(xx / 2f) * 1f +
                                                            Math.Floor(yy / 2f) * 4f);

                            // Check if current hole number should be a hole
                            if ((chunk.header.holesLowRes & currentHole) == 0)
                            {
                                isHole = false;
                            }
                        }

                        //Sloppy ignore holes:
                        if (Managers.ConfigurationManager.ADTIgnoreHoles)
                        {
                            isHole = false;
                        }
                        else
                        {
                            // Check if current section is a hole
                            if (((holesHighRes[yy] >> xx) & 1) == 0)
                            {
                                isHole = false;
                            }
                        }

                        if (!isHole)
                        {
                            indicelist.AddRange(new int[] { off + j + 8, off + j - 9, off + j });
                            indicelist.AddRange(new int[] { off + j - 9, off + j - 8, off + j });
                            indicelist.AddRange(new int[] { off + j - 8, off + j + 9, off + j });
                            indicelist.AddRange(new int[] { off + j + 9, off + j + 8, off + j });

                            // Generates quads instead of 4x triangles
                            //indicelist.AddRange(new int[] { off + j + 8, off + j - 9, off + j - 8 });
                            //indicelist.AddRange(new int[] { off + j - 8, off + j + 9, off + j + 8 });
                        }
                        if ((j + 1) % (9 + 8) == 0)
                        {
                            j += 9;
                        }
                    }

                    if (bakeQuality == "high")
                    {
                        materials.Add((int)ci + 1, Path.GetFileNameWithoutExtension(file) + "_" + ci);
                        batch.materialID = ci + 1;
                    }
                    else
                    {
                        if (!materials.ContainsKey(1))
                        {
                            materials.Add(1, Path.GetFileNameWithoutExtension(file));
                        }
                        batch.materialID = (uint)materials.Count();
                    }
                    batch.numFaces = (uint)(indicelist.Count()) - batch.firstFace;

                    renderBatches.Add(batch);
                    ci++;
                }
            }

            bool exportWMO       = Managers.ConfigurationManager.ADTExportWMO;
            bool exportM2        = Managers.ConfigurationManager.ADTExportM2;
            bool exportTextures  = Managers.ConfigurationManager.ADTexportTextures;
            bool exportAlphaMaps = Managers.ConfigurationManager.ADTexportAlphaMaps;
            bool exportHeightmap = Managers.ConfigurationManager.ADTExportHeightmap;
            bool exportFoliage   = Managers.ConfigurationManager.ADTExportFoliage;

            //FOLIAGE
            if (exportFoliage && Managers.ArchiveManager.usingCasc) //ONLY EXPROT IF CASC; PRE CASC NEEDS TO BE IMPLEMEMNTED
            {
                exportworker.ReportProgress(65, "Exporting foliage");

                try
                {
                    var build = Managers.ArchiveManager.cascHandler.Config.VersionName; //TODO: IMPLEMENT PRE CASC BUILDS
                    var dbcd  = new DBCD.DBCD(new WoWExport.DBC.ArchiveDBCProvider(), new WoWExport.DBC.LocalDBCDProvider());
                    var groundEffectTextureDB = dbcd.Load("GroundEffectTexture", build);
                    var groundEffectDoodadDB  = dbcd.Load("GroundEffectDoodad", build);

                    for (var c = 0; c < reader.adtfile.texChunks.Length; c++)
                    {
                        for (var l = 0; l < reader.adtfile.texChunks[c].layers.Length; l++)
                        {
                            var effectID = reader.adtfile.texChunks[c].layers[l].effectId;
                            if (effectID == 0)
                            {
                                continue;
                            }

                            if (!groundEffectTextureDB.ContainsKey(effectID))
                            {
                                continue;
                            }

                            dynamic textureEntry = groundEffectTextureDB[effectID];
                            foreach (int doodad in textureEntry.DoodadID)
                            {
                                if (!groundEffectDoodadDB.ContainsKey(doodad))
                                {
                                    continue;
                                }

                                dynamic doodadEntry = groundEffectDoodadDB[doodad];

                                var filedataid = (uint)doodadEntry.ModelFileID;

                                if (!WoWExport.Listfile.TryGetFilename(filedataid, out var filename))
                                {
                                    Console.WriteLine("Could not find filename for " + filedataid + ", setting filename to filedataid..");
                                    filename = filedataid.ToString();
                                }

                                if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file), "foliage")))
                                {
                                    Directory.CreateDirectory(Path.Combine(outdir, Path.GetDirectoryName(file), "foliage"));
                                }

                                if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file), "foliage", Path.GetFileNameWithoutExtension(filename).ToLower() + ".obj")))
                                {
                                    M2Exporter.ExportM2(filename, Path.Combine(outdir, Path.GetDirectoryName(file), "foliage"));
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error exporting GroundEffects: " + e.Message);
                }
            }

            if (exportWMO || exportM2)
            {
                var doodadSW = new StreamWriter(Path.Combine(outdir, Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(file).Replace(" ", "") + "_ModelPlacementInformation.csv"));
                doodadSW.WriteLine("ModelFile;PositionX;PositionY;PositionZ;RotationX;RotationY;RotationZ;ScaleFactor;ModelId;Type");

                if (exportWMO)
                {
                    exportworker.ReportProgress(25, "Exporting WMOs");

                    for (var mi = 0; mi < reader.adtfile.objects.worldModels.entries.Count(); mi++)
                    {
                        var wmo = reader.adtfile.objects.worldModels.entries[mi];

                        float wmoScale;
                        if (wmo.scale != 0)
                        {
                            wmoScale = wmo.scale / 1024f;
                        }
                        else
                        {
                            wmoScale = 1;
                        }

                        var filename = reader.adtfile.objects.wmoNames.filenames[wmo.mwidEntry];

                        if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(filename).ToLower() + ".obj")))
                        {
                            WMOExporter.ExportWMO(filename, Path.Combine(outdir, Path.GetDirectoryName(file)), exportworker, null, wmo.doodadSet);
                        }

                        if (Managers.ConfigurationManager.ADTModelsPlacementGlobalPath)
                        {
                            doodadSW.WriteLine(Path.Combine(Path.GetDirectoryName(filename).ToLower(), Path.GetFileNameWithoutExtension(filename).ToLower() + ".obj") + ";" + wmo.position.X + ";" + wmo.position.Y + ";" + wmo.position.Z + ";" + wmo.rotation.X + ";" + wmo.rotation.Y + ";" + wmo.rotation.Z + ";" + wmoScale + ";" + wmo.uniqueId + ";wmo");
                        }
                        else
                        {
                            doodadSW.WriteLine(Path.GetFileNameWithoutExtension(filename).ToLower() + ".obj;" + wmo.position.X + ";" + wmo.position.Y + ";" + wmo.position.Z + ";" + wmo.rotation.X + ";" + wmo.rotation.Y + ";" + wmo.rotation.Z + ";" + wmoScale + ";" + wmo.uniqueId + ";wmo");
                        }
                    }
                }

                if (exportM2)
                {
                    exportworker.ReportProgress(50, "Exporting M2s");

                    for (var mi = 0; mi < reader.adtfile.objects.models.entries.Count(); mi++)
                    {
                        var doodad = reader.adtfile.objects.models.entries[mi];

                        string filename;
                        filename = reader.adtfile.objects.m2Names.filenames[doodad.mmidEntry];
                        if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(filename).ToLower() + ".obj")))
                        {
                            M2Exporter.ExportM2(filename, Path.Combine(outdir, Path.GetDirectoryName(file)), exportworker);
                        }
                        if (Managers.ConfigurationManager.ADTModelsPlacementGlobalPath)
                        {
                            doodadSW.WriteLine(Path.Combine(Path.GetDirectoryName(filename).ToLower(), Path.GetFileNameWithoutExtension(filename).ToLower() + ".obj") + ";" + doodad.position.X + ";" + doodad.position.Y + ";" + doodad.position.Z + ";" + doodad.rotation.X + ";" + doodad.rotation.Y + ";" + doodad.rotation.Z + ";" + doodad.scale / 1024f + ";" + doodad.uniqueId + ";m2");
                        }
                        else
                        {
                            doodadSW.WriteLine(Path.GetFileNameWithoutExtension(filename).ToLower() + ".obj;" + doodad.position.X + ";" + doodad.position.Y + ";" + doodad.position.Z + ";" + doodad.rotation.X + ";" + doodad.rotation.Y + ";" + doodad.rotation.Z + ";" + doodad.scale / 1024f + ";" + doodad.uniqueId + ";m2");
                        }
                    }
                }
                doodadSW.Close();
            }
            #region Alpha&Tex
            //----------------------------------------------------------------------------------------------------------
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
            ///TEXTURE & ALPHA & HEIGHTMAP RELATED START
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //----------------------------------------------------------------------------------------------------------
            if (exportTextures) //Export ground textures
            {
                {
                    if (!Directory.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures")))
                    {
                        Directory.CreateDirectory(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures"));
                    }
                }

                List <String> GroundTextures = reader.adtfile.textures.filenames.ToList();

                var blpreader = new BLPReader();
                foreach (string texture in GroundTextures)
                {
                    if (Managers.ConfigurationManager.ADTPreserveTextureStruct)
                    {
                        if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures", Path.GetDirectoryName(texture) + Path.GetFileNameWithoutExtension(texture) + ".png")))
                        {
                            if (!Directory.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures", Path.GetDirectoryName(texture))))
                            {
                                Directory.CreateDirectory(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures", Path.GetDirectoryName(texture)));
                            }

                            if (Managers.ArchiveManager.FileExists(texture))
                            {
                                try
                                {
                                    blpreader.LoadBLP(Managers.ArchiveManager.ReadThisFile(texture));
                                    blpreader.bmp.Save(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures", Path.GetDirectoryName(texture), Path.GetFileNameWithoutExtension(texture) + ".png"));
                                    if (Managers.ConfigurationManager.ADTExportSpecularTextures)
                                    {
                                        if (Managers.ArchiveManager.FileExists(Path.Combine(Path.GetDirectoryName(texture), Path.GetFileNameWithoutExtension(texture) + "_s.blp")))
                                        {
                                            if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures", Path.GetDirectoryName(texture), Path.GetFileNameWithoutExtension(texture) + "_s.png")))
                                            {
                                                blpreader.LoadBLP(Managers.ArchiveManager.ReadThisFile(Path.Combine(Path.GetDirectoryName(texture), Path.GetFileNameWithoutExtension(texture) + "_s.blp")));
                                                blpreader.bmp.Save(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures", Path.GetDirectoryName(texture), Path.GetFileNameWithoutExtension(texture) + "_s.png"));
                                            }
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    //Error on file save
                                    throw new Exception(e.Message);
                                }
                            }
                            else
                            {
                                //Missing file
                            }
                        }
                    }
                    else
                    {
                        if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures\\", Path.GetFileNameWithoutExtension(texture) + ".png")))
                        {
                            if (Managers.ArchiveManager.FileExists(texture))
                            {
                                try
                                {
                                    blpreader.LoadBLP(Managers.ArchiveManager.ReadThisFile(texture));
                                    blpreader.bmp.Save(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures\\", Path.GetFileNameWithoutExtension(texture) + ".png"));
                                    if (Managers.ConfigurationManager.ADTExportSpecularTextures)
                                    {
                                        if (Managers.ArchiveManager.FileExists(Path.Combine(Path.GetDirectoryName(texture), Path.GetFileNameWithoutExtension(texture) + "_s.blp")))
                                        {
                                            if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures\\", Path.GetFileNameWithoutExtension(texture) + "_s.png")))
                                            {
                                                blpreader.LoadBLP(Managers.ArchiveManager.ReadThisFile(Path.Combine(Path.GetDirectoryName(texture), Path.GetFileNameWithoutExtension(texture) + "_s.blp")));
                                                blpreader.bmp.Save(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\GroundTextures\\", Path.GetFileNameWithoutExtension(texture) + "_s.png"));
                                            }
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    //Error on file save
                                    throw new Exception(e.Message);
                                }
                            }
                            else
                            {
                                //Missing file
                            }
                        }
                    }
                }
            }

            if (exportAlphaMaps)
            {
                Generators.ADT_Alpha.ADT_Alpha AlphaMapsGenerator = new Generators.ADT_Alpha.ADT_Alpha();
                AlphaMapsGenerator.GenerateAlphaMaps(reader.adtfile, Managers.ConfigurationManager.ADTAlphaMode);

                List <System.Drawing.Bitmap> AlphaLayers = new List <System.Drawing.Bitmap>();
                AlphaLayers = AlphaMapsGenerator.AlphaLayers;

                if (!Directory.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\AlphaMaps")))
                {
                    Directory.CreateDirectory(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\AlphaMaps"));
                }

                if (AlphaLayers != null)
                {
                    if (Managers.ConfigurationManager.ADTAlphaMode == 0 || Managers.ConfigurationManager.ADTAlphaMode == 1)
                    {
                        for (int m = 0; m < AlphaLayers.ToArray().Length; m++)
                        {
                            if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\AlphaMaps\\", mapname + "_" + m + ".png")))
                            {
                                try
                                {
                                    AlphaLayers[m].Save(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\AlphaMaps\\", mapname + "_" + m + ".png"));
                                }
                                catch
                                {
                                    //Error on file save
                                }
                            }
                        }
                    }
                    if (Managers.ConfigurationManager.ADTAlphaMode == 2 || Managers.ConfigurationManager.ADTAlphaMode == 3)
                    {
                        List <String> AlphaLayersNames = new List <String>(AlphaMapsGenerator.AlphaLayersNames);
                        for (int m = 0; m < AlphaLayers.ToArray().Length; m++)
                        {
                            if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\AlphaMaps\\", mapname + "_" + AlphaLayersNames[m].Replace(";", "_") + ".png")))
                            {
                                try
                                {
                                    AlphaLayers[m].Save(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\AlphaMaps\\", mapname + "_" + AlphaLayersNames[m].Replace(";", "_") + ".png"));
                                }
                                catch
                                {
                                    //Error on file save
                                }
                            }
                        }
                    }
                    if (Managers.ConfigurationManager.ADTAlphaMode == 4) //Splatmaps
                    {
                        //Save the splatmaps
                        for (int m = 0; m < AlphaLayers.ToArray().Length; m++)
                        {
                            if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\AlphaMaps\\", mapname + "_splatmap_" + m + ".png")))
                            {
                                try
                                {
                                    AlphaLayers[m].Save(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\AlphaMaps\\", mapname + "_splatmap_" + m + ".png"));
                                }
                                catch
                                {
                                    //Error on file save
                                }
                            }
                        }
                        //Save the material info JSON
                        if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\AlphaMaps\\", mapname + "_MaterialData.json")))
                        {
                            try
                            {
                                File.WriteAllText(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\AlphaMaps\\", mapname + "_MaterialData.json"), AlphaMapsGenerator.SplatmapJSON);
                            }
                            catch
                            {
                                //Error on file save
                            }
                        }
                    }
                }

                //Check if the CSV already exists, if not, create it
                if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\" + mapname + "_" + "layers.csv")))
                {
                    //Generate layer information CSV
                    StreamWriter layerCsvSR = new StreamWriter(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\" + mapname + "_" + "layers.csv"));
                    //Insert CSV scheme
                    layerCsvSR.WriteLine("chunk;tex0;tex1;tex2;tex3");
                    for (uint c = 0; c < reader.adtfile.chunks.Count(); c++)
                    {
                        string csvLine = c.ToString();
                        for (int li = 0; li < reader.adtfile.texChunks[c].layers.Count(); li++)
                        {
                            var AlphaLayerName = reader.adtfile.textures.filenames[reader.adtfile.texChunks[c].layers[li].textureId].ToLower();
                            if (Managers.ConfigurationManager.ADTPreserveTextureStruct)
                            {
                                csvLine = csvLine + ";" + Path.Combine(Path.GetDirectoryName(AlphaLayerName), Path.GetFileNameWithoutExtension(AlphaLayerName));
                            }
                            else
                            {
                                csvLine = csvLine + ";" + Path.GetFileNameWithoutExtension(AlphaLayerName);
                            }
                        }
                        layerCsvSR.WriteLine(csvLine);
                    }
                    layerCsvSR.Close();
                }
            }

            if (exportHeightmap)
            {
                Generators.ADT_Height.ADT_Height heightmapGenerator = new Generators.ADT_Height.ADT_Height();
                heightmapGenerator.GenerateHeightmap(reader.adtfile);

                if (!Directory.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\HeightMaps")))
                {
                    Directory.CreateDirectory(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\HeightMaps"));
                }

                try
                {
                    File.WriteAllText(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\HeightMaps\\", mapname + "_HeightData.json"), Newtonsoft.Json.JsonConvert.SerializeObject(heightmapGenerator.heightArray2d));
                    heightmapGenerator.heightMap.Save(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\HeightMaps\\", mapname + "_heightmap.png"));
                }
                catch
                {
                    //Error on save
                }
            }
            //----------------------------------------------------------------------------------------------------------
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
            ///TEXTURE & ALPHA & HEIGHTMAP RELATED END
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //----------------------------------------------------------------------------------------------------------
            #endregion

            //VERTEX COLORS -- not implemented

            /*
             * //Vertex color data
             * if (!File.Exists(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\" + mapname + "_" + "vertex_colors.csv")))
             * {
             *  StreamWriter vertesColorCSV = new StreamWriter(Path.Combine(outdir, Path.GetDirectoryName(file) + "\\" + mapname + "_" + "vertex_colors.csv"));
             *  vertesColorCSV.WriteLine("chunk;vert;a;r;g;b"); //header
             *  for (uint c = 0; c < reader.adtfile.chunks.Count(); c++)
             *  {
             *      if (reader.adtfile.chunks[c].vertexShading.red != null)
             *      {
             *          for (int i = 0; i < 145; i++)
             *          {
             *              //Console.WriteLine(c + "_" + i + "-" + reader.adtfile.chunks[c].vertexShading.alpha[i] + " " + reader.adtfile.chunks[c].vertexShading.red[i] + " " + reader.adtfile.chunks[c].vertexShading.green[i] + " " + reader.adtfile.chunks[c].vertexShading.blue[i]);
             *              vertesColorCSV.WriteLine(c + ";" + i + ";" + reader.adtfile.chunks[c].vertexShading.alpha[i] + ";" + reader.adtfile.chunks[c].vertexShading.red[i] + ";" + reader.adtfile.chunks[c].vertexShading.green[i] + ";" + reader.adtfile.chunks[c].vertexShading.blue[i]);
             *          }
             *      }
             *      else
             *      {
             *          //Console.WriteLine(c + "- null");
             *          vertesColorCSV.WriteLine(c + ";0;0;0;0;0");
             *      }
             *  }
             *  vertesColorCSV.Close();
             * }
             */

            exportworker.ReportProgress(75, "Exporting terrain textures..");

            if (bakeQuality != "none")
            {
                var mtlsw = new StreamWriter(Path.Combine(outdir, Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(file).Replace(" ", "") + ".mtl"));

                //No idea how MTL files really work yet. Needs more investigation.
                foreach (var material in materials)
                {
                    mtlsw.WriteLine("newmtl " + material.Value.Replace(" ", ""));
                    mtlsw.WriteLine("Ka 1.000000 1.000000 1.000000");
                    mtlsw.WriteLine("Kd 0.640000 0.640000 0.640000");
                    mtlsw.WriteLine("map_Ka " + material.Value.Replace(" ", "") + ".png");
                    mtlsw.WriteLine("map_Kd " + material.Value.Replace(" ", "") + ".png");
                }

                mtlsw.Close();
            }

            exportworker.ReportProgress(85, "Exporting terrain geometry..");

            var indices = indicelist.ToArray();

            var adtname = Path.GetFileNameWithoutExtension(file);

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

            objsw.WriteLine("# Written by Marlamin's WoW OBJExporter. Original file: " + file);
            if (bakeQuality != "none")
            {
                objsw.WriteLine("mtllib " + Path.GetFileNameWithoutExtension(file).Replace(" ", "") + ".mtl");
            }

            objsw.WriteLine("g " + adtname.Replace(" ", ""));
            var verticeCounter = 1;
            var chunkCounter   = 1;
            foreach (var vertex in verticelist)
            {
                objsw.WriteLine("# C" + chunkCounter + ".V" + verticeCounter);
                objsw.WriteLine("v " + vertex.Position.X.ToString("R") + " " + vertex.Position.Y.ToString("R") + " " + vertex.Position.Z.ToString("R"));
                objsw.WriteLine("vt " + vertex.TexCoord.X + " " + vertex.TexCoord.Y);
                objsw.WriteLine("vn " + vertex.Normal.X.ToString("R") + " " + vertex.Normal.Y.ToString("R") + " " + vertex.Normal.Z.ToString("R"));
                verticeCounter++;
                if (verticeCounter == 146)
                {
                    chunkCounter++;
                    verticeCounter = 1;
                }
            }

            if (bakeQuality != "high")
            {
                objsw.WriteLine("usemtl " + materials[1]);
                objsw.WriteLine("s 1");
            }
            int currentChunk = 0;
            foreach (var renderBatch in renderBatches)
            {
                var i = renderBatch.firstFace;
                if (bakeQuality == "high" && materials.ContainsKey((int)renderBatch.materialID))
                {
                    if (Managers.ConfigurationManager.ADTSplitChunks)
                    {
                        objsw.WriteLine("g " + materials[(int)renderBatch.materialID]);
                        objsw.WriteLine("usemtl " + materials[(int)renderBatch.materialID]);
                        objsw.WriteLine("s 1");
                    }
                    else
                    {
                        objsw.WriteLine("usemtl " + materials[(int)renderBatch.materialID]);
                    }
                }
                while (i < (renderBatch.firstFace + renderBatch.numFaces))
                {
                    objsw.WriteLine("f " +
                                    (indices[i + 2] + 1) + "/" + (indices[i + 2] + 1) + "/" + (indices[i + 2] + 1) + " " +
                                    (indices[i + 1] + 1) + "/" + (indices[i + 1] + 1) + "/" + (indices[i + 1] + 1) + " " +
                                    (indices[i] + 1) + "/" + (indices[i] + 1) + "/" + (indices[i] + 1));
                    i += 3;
                }
                currentChunk++;
            }

            objsw.Close();
        }
Esempio n. 2
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!");
        }