public WorldModel(string directory, string modelName) { var filePath = Path.Combine(directory, "vmaps", $"{modelName}.vmo"); using (var reader = new BinaryReader(File.OpenRead(filePath))) { reader.BaseStream.Position += 8; if (reader.ReadInt32() == 0x444F4D57) // WMOD { var chunkSize = reader.ReadInt32(); // 8 RootWmoID = reader.ReadInt32(); } if (reader.ReadInt32() == 0x444F4D47) // GMOD { GroupModels = new GroupModel[reader.ReadInt32()]; for (var i = 0; i < GroupModels.Length; ++i) { GroupModels[i] = new GroupModel(reader) { Program = ShaderProgramCache.Instance.Get("wmo"), VerticeAttribute = "vertexPosition_modelSpace", InstancePositionAttribute = "instance_position", }; } if (reader.ReadInt32() == 0x48494247) // GIH { GroupTree = new BIH(reader); } } } }
public VMapLoader(string directory, int mapID) { Directory = directory; using (var reader = new BinaryReader(File.OpenRead(Path.Combine(directory, "vmaps", $"{mapID:D3}.vmtree")))) { if (reader == null) { return; } MapID = mapID; reader.BaseStream.Position += 8; IsTiled = reader.ReadByte() == 1; if (reader.ReadInt32() == 0x45444F4E) // NODE { BIH = new BIH(reader); } if (!IsTiled && reader.ReadInt32() == 0x4A424F47) // GOBJ { GlobalModel = new ModelSpawn(directory, reader); } } }
public GroupModel(BinaryReader reader) { var bbox = reader.Read <float>(6); // var boundingBoxLo = reader.Read<Vector3>(); // var boundingBoxHi = reader.Read<Vector3>(); var mogpFlags = reader.ReadInt32(); var groupWmoID = reader.ReadInt32(); if (reader.ReadInt32() == 0x54524556) // VERT { var chunkSize = reader.ReadInt32(); var count = reader.ReadInt32(); if (count == 0) { return; } Vertices = reader.Read <Vector3>(count); } if (reader.ReadInt32() == 0x4D495254) // TRIM { var chunkSize = reader.ReadInt32(); var count = reader.ReadInt32(); Indices = reader.Read <uint>(count * 3); } if (reader.ReadInt32() == 0x4849424D) // MBIH { Tree = new BIH(reader); } if (reader.ReadInt32() == 0x5551494C) // LIQU { var chunkSize = reader.ReadInt32(); if (chunkSize == 0) { return; } var tileX = reader.ReadInt32(); var tileY = reader.ReadInt32(); reader.BaseStream.Position += SizeCache <Vector3> .Size; reader.BaseStream.Position += 4; reader.BaseStream.Position += 4 * (tileX + 1) * (tileY + 1); reader.BaseStream.Position += tileX * tileY; } }
public GroupModel(BinaryReader reader) { reader.BaseStream.Position += 2 * SizeCache <Vector3> .Size; // BBox var mogpFlags = reader.ReadInt32(); var groupWmoID = reader.ReadInt32(); if (reader.ReadInt32() == 0x54524556) // VERT { var chunkSize = reader.ReadInt32(); var count = reader.ReadInt32(); if (count == 0) { return; } _modelVertices = reader.Read <Vector3>(count); } if (reader.ReadInt32() == 0x4D495254) // TRIM { var chunkSize = reader.ReadInt32(); var count = reader.ReadInt32(); _modelIndices = reader.Read <uint>(count * 3); } if (reader.ReadInt32() == 0x4849424D) // MBIH { BIH.Skip(reader); } if (reader.ReadInt32() == 0x5551494C) // LIQU { var chunkSize = reader.ReadInt32(); if (chunkSize == 0) { return; } var tileX = reader.ReadInt32(); var tileY = reader.ReadInt32(); reader.BaseStream.Position += SizeCache <Vector3> .Size; reader.BaseStream.Position += 4; reader.BaseStream.Position += 4 * (tileX + 1) * (tileY + 1); reader.BaseStream.Position += tileX * tileY; } }
public BuildingsLoader(string directory, int mapID) { _directory = directory; _mapId = mapID; using (var reader = new BinaryReader(File.OpenRead(Path.Combine(directory, "vmaps", $"{mapID:D3}.vmtree")))) { reader.BaseStream.Position += 8; // Skip signature _isTiled = reader.ReadByte() == 1; if (reader.ReadInt32() == 0x45444F4E) // NODE { BIH.Skip(reader); } if (!_isTiled && reader.ReadInt32() == 0x4A424F47) // GOBJ { // load global model } } }
public bool convertWorld2() { bool success = readMapSpawns(); if (!success) { return(false); } float invTileSize = 1.0f / 533.33333f; // export Map data foreach (var mapPair in mapData) { var mapSpawn = mapPair.Value; // build global map tree List <ModelSpawn> mapSpawns = new List <ModelSpawn>(); Console.WriteLine($"Calculating model bounds for map {mapPair.Key}..."); foreach (var entry in mapSpawn.UniqueEntries.Values) { // M2 models don't have a bound set in WDT/ADT placement data, i still think they're not used for LoS at all on retail if (Convert.ToBoolean(entry.flags & ModelFlags.M2)) { if (!calculateTransformedBound(entry)) { continue; } } mapSpawns.Add(entry); spawnedModelFiles.Add(entry.name); var tileEntries = Convert.ToBoolean(entry.flags & ModelFlags.ParentSpawn) ? mapSpawn.ParentTileEntries : mapSpawn.TileEntries; AxisAlignedBox bounds = entry.iBound; Vector2 low = new Vector2(bounds.Lo.X * invTileSize, bounds.Lo.Y * invTileSize); Vector2 high = new Vector2(bounds.Hi.X * invTileSize, bounds.Hi.Y * invTileSize); for (uint x = (ushort)low.X; x <= (ushort)high.X; ++x) { for (uint y = (ushort)low.Y; y <= (ushort)high.Y; ++y) { tileEntries.Add(StaticMapTree.PackTileID(x, y), new TileSpawn(entry.ID, entry.flags)); } } } Console.WriteLine($"Creating map tree for map {mapPair.Key}..."); BIH pTree = new BIH(); pTree.build(mapSpawns, BoundsTrait.GetBounds); // ===> possibly move this code to StaticMapTree class // write map tree file string mapfilename = $"{iDestDir}/{mapPair.Key:D4}.vmtree"; using (BinaryWriter writer = new BinaryWriter(File.Open(mapfilename, FileMode.Create, FileAccess.Write))) { //general info writer.WriteString(SharedConst.VMAP_MAGIC); // Nodes writer.WriteString("NODE"); pTree.writeToFile(writer); // spawn id to index map writer.WriteString("SIDX"); writer.Write(mapSpawns.Count); for (int i = 0; i < mapSpawns.Count; ++i) { writer.Write(mapSpawns[i].ID); writer.Write(i); } } // write map tile files, similar to ADT files, only with extra BIH tree node info foreach (var key in mapSpawn.TileEntries.Keys) { var spawnList = mapSpawn.TileEntries[key]; uint x, y; StaticMapTree.UnpackTileID(key, out x, out y); string tilefilename = $"{iDestDir}/{mapPair.Key:D4}_{y:D2}_{x:D2}.vmtile"; using (BinaryWriter writer = new BinaryWriter(File.Open(tilefilename, FileMode.Create, FileAccess.Write))) { var parentTileEntries = mapPair.Value.ParentTileEntries[key]; int nSpawns = spawnList.Count + parentTileEntries.Count; // file header writer.WriteString(SharedConst.VMAP_MAGIC); // write number of tile spawns writer.Write(nSpawns); // write tile spawns foreach (var tileSpawn in spawnList) { ModelSpawn.WriteToFile(writer, mapPair.Value.UniqueEntries[tileSpawn.Id]); } foreach (var spawnItr in parentTileEntries) { ModelSpawn.WriteToFile(writer, mapPair.Value.UniqueEntries[spawnItr.Id]); } } } } // add an object models, listed in temp_gameobject_models file exportGameobjectModels(); // export objects Console.WriteLine("Converting Model Files"); foreach (var mfile in spawnedModelFiles) { Console.WriteLine($"Converting {mfile}"); convertRawFile(mfile); } return(success); }
public bool convertWorld2() { bool success = readMapSpawns(); if (!success) { return(false); } // export Map data foreach (var mapPair in mapData) { var mapSpawn = mapPair.Value; // build global map tree List <ModelSpawn> mapSpawns = new List <ModelSpawn>(); Console.WriteLine($"Calculating model bounds for map {mapPair.Key}..."); foreach (var entry in mapSpawn.UniqueEntries.Values) { // M2 models don't have a bound set in WDT/ADT placement data, i still think they're not used for LoS at all on retail if (Convert.ToBoolean(entry.flags & ModelFlags.M2)) { if (!calculateTransformedBound(entry)) { break; } } else if (Convert.ToBoolean(entry.flags & ModelFlags.WorldSpawn)) // WMO maps and terrain maps use different origin, so we need to adapt :/ { /// @todo remove extractor hack and uncomment below line: //entry.second.iPos += Vector3(533.33333f*32, 533.33333f*32, 0.f); entry.iBound = entry.iBound + new Vector3(533.33333f * 32, 533.33333f * 32, 0.0f); } mapSpawns.Add(entry); spawnedModelFiles.Add(entry.name); } Console.WriteLine($"Creating map tree for map {mapPair.Key}..."); BIH pTree = new BIH(); try { pTree.build(mapSpawns, BoundsTrait.getBounds); } catch (Exception e) { Console.Write($"Exception {e.Message} when calling pTree.build"); return(false); } // ===> possibly move this code to StaticMapTree class Dictionary <uint, uint> modelNodeIdx = new Dictionary <uint, uint>(); for (uint i = 0; i < mapSpawns.Count; ++i) { modelNodeIdx.Add(mapSpawns[(int)i].ID, i); } // write map tree file string mapfilename = $"{iDestDir}/{mapPair.Key:D4}.vmtree"; using (BinaryWriter writer = new BinaryWriter(File.Open(mapfilename, FileMode.Create, FileAccess.Write))) { //general info writer.WriteString(SharedConst.VMAP_MAGIC); uint globalTileID = StaticMapTree.packTileID(65, 65); var globalRange = mapSpawn.TileEntries.LookupByKey(globalTileID); bool isTiled = globalRange.Count == 0; // only maps without terrain (tiles) have global WMO writer.Write(isTiled); // Nodes writer.WriteString("NODE"); pTree.writeToFile(writer); // global map spawns (WDT), if any (most instances) writer.WriteString("GOBJ"); foreach (var glob in globalRange) { ModelSpawn.writeToFile(writer, mapSpawn.UniqueEntries[glob]); } } // write map tile files, similar to ADT files, only with extra BSP tree node info var tileEntries = mapSpawn.TileEntries; foreach (var key in tileEntries.Keys) { ModelSpawn spawn = mapSpawn.UniqueEntries[tileEntries[key].First()]; if (Convert.ToBoolean(spawn.flags & ModelFlags.WorldSpawn)) // WDT spawn, saved as tile 65/65 currently... { continue; } string tilefilename = $"{iDestDir}/{mapPair.Key:D4}_"; uint x, y; StaticMapTree.unpackTileID(key, out x, out y); tilefilename += $"{x:D2}_{y:D2}.vmtile"; using (BinaryWriter writer = new BinaryWriter(File.Open(tilefilename, FileMode.Create, FileAccess.Write))) { // file header writer.WriteString(SharedConst.VMAP_MAGIC); // write number of tile spawns writer.Write(tileEntries[key].Count); // write tile spawns foreach (var nSpawn in tileEntries[key]) { ModelSpawn spawn2 = mapSpawn.UniqueEntries[nSpawn]; ModelSpawn.writeToFile(writer, spawn2); // MapTree nodes to update when loading tile: var nIdx = modelNodeIdx[spawn2.ID]; writer.Write(nIdx); } } } // break; //test, extract only first map; TODO: remvoe this line } // add an object models, listed in temp_gameobject_models file exportGameobjectModels(); // export objects Console.WriteLine("Converting Model Files"); foreach (var mfile in spawnedModelFiles) { Console.WriteLine($"Converting {mfile}"); convertRawFile(mfile); } return(success); }