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; }
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); } }
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.."); } }
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.."); } }
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!"); }
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!"); }
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; }
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); }
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 }
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); }
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!"); }
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!"); }