// Get all the wall textures from the wall texture resource public static List <WallTextureData> GetTextures(FileStream wadStream, WADInfo wadInfo, byte[] data) { var textures = new List <WallTextureData>(); var numTexs = BitConverter.ToInt32(data, 0); for (var i = 0; i < numTexs; i++) { var pointer = BitConverter.ToInt32(data, 4 + (i * 4)); var name = Encoding.UTF8.GetString(data, pointer, 8).ToUpper(); var w = BitConverter.ToInt16(data, pointer + 12); var h = BitConverter.ToInt16(data, pointer + 14); var numPatches = BitConverter.ToInt16(data, pointer + 20); var patches = new WallPatch[numPatches]; for (var p = 0; p < numPatches; p++) { var x = BitConverter.ToInt16(data, pointer + 22 + (p * 10)); var y = BitConverter.ToInt16(data, pointer + 22 + (p * 10) + 2); var pnum = BitConverter.ToInt16(data, pointer + 22 + (p * 10) + 4); var pname = wadInfo.PatchNames[pnum]; var patch = new WallPatch(x, y, pnum, pname); patches[p] = patch; } textures.Add(new WallTextureData(name, w, h, patches)); } return(textures); }
void LoadWad() { using (var wadStream = new FileStream(fileName, FileMode.Open)) { loadedWad = WADReader.GetInfo(wadStream); availableMaps = WADReader.GetMapList(wadStream, loadedWad); } }
// Returns actual map data when given a map entry (from GetMapList) public static MapData GetMapData(FileStream wadStream, WADInfo wadInfo, WADMapEntry mapEntry) { var mapData = new MapData(wadInfo, mapEntry.Name, GetResource(wadStream, mapEntry.Things), GetResource(wadStream, mapEntry.LineDefs), GetResource(wadStream, mapEntry.SideDefs), GetResource(wadStream, mapEntry.Sectors), GetResource(wadStream, mapEntry.SubSectors), GetResource(wadStream, mapEntry.Segs), GetResource(wadStream, mapEntry.Vertexes)); return(mapData); }
// Gets a list of maps in the WAD // At this level, we only care about metadata - so we get the name of the map and pointers to resources containing the map data public static List <WADMapEntry> GetMapList(FileStream wadStream, WADInfo wadInfo) { var maps = new List <WADMapEntry>(); // Map names are either in the format "ExMy" or "MAPxx" // They also have a zero resource length as they're just markers in the WAD directory foreach (var entry in wadInfo.Entries.Where(e => (e.Name.StartsWith("MAP") || (e.Name[0] == 'E' && e.Name[2] == 'M')) && e.ResourceLength == 0)) { var map = new WADMapEntry() { Name = entry.Name }; // The resource entries directly after the map marker are the actual map data // Let's find the ones we're interested in and hold pointers to them so we can get to them easily later var startIndex = wadInfo.Entries.IndexOf(entry); var index = startIndex + 1; while (index < startIndex + 10 || index >= wadInfo.Entries.Count - 1) { switch (wadInfo.Entries[index].Name) { case "THINGS": map.Things = wadInfo.Entries[index]; break; case "LINEDEFS": map.LineDefs = wadInfo.Entries[index]; break; case "SIDEDEFS": map.SideDefs = wadInfo.Entries[index]; break; case "VERTEXES": map.Vertexes = wadInfo.Entries[index]; break; case "SECTORS": map.Sectors = wadInfo.Entries[index]; break; case "SSECTORS": map.SubSectors = wadInfo.Entries[index]; break; case "SEGS": map.Segs = wadInfo.Entries[index]; break; } index++; } maps.Add(map); } return(maps); }
// Get a dictionary of wall patches based on the patch names listed in the wall texture data public static Dictionary <string, SpriteData> GetWallPatches(FileStream wadStream, WADInfo wadInfo, WallTextureData textureData) { var sprites = new Dictionary <string, SpriteData>(); foreach (var patch in textureData.Patches) { if (!sprites.ContainsKey(patch.PatchName)) { sprites.Add(patch.PatchName, GetPictureSprite(wadStream, wadInfo.EntryDictionary[patch.PatchName])); } } return(sprites); }
// Deals with reading data from the WAD file // See https://github.com/nukeop/TheUnofficialDoomSpecs public static WADInfo GetInfo(FileStream wadStream) { // Root WAD data var wi = new WADInfo() { Type = ReadString(wadStream, 0, 4), NumEntries = ReadInt(wadStream, 4, 4), DirectoryOffset = ReadInt(wadStream, 8, 4) }; // Get a list of the contents of the WAD for (var i = 0; i < wi.NumEntries; i++) { var entryOffset = wi.DirectoryOffset + (i * 16); var entry = new WADEntry() { ResourceOffset = ReadInt(wadStream, entryOffset, 4), ResourceLength = ReadInt(wadStream, entryOffset + 4, 4), Name = ReadString(wadStream, entryOffset + 8, 8) }; wi.Entries.Add(entry); if (!wi.EntryDictionary.ContainsKey(entry.Name.Replace("\0", ""))) { wi.EntryDictionary.Add(entry.Name.Replace("\0", ""), entry); //Debug.Log(entry.Name); } } // Wall patches // Get patchnames lookup var patchesEntry = wi.EntryDictionary["PNAMES"]; var patchesData = GetResource(wadStream, patchesEntry); var numPatches = BitConverter.ToInt32(patchesData, 0); wi.PatchNames = new string[numPatches]; var pos = 4; for (var i = 0; i < numPatches; i++) { wi.PatchNames[i] = Encoding.UTF8.GetString(patchesData, pos, 8).ToUpper().Replace("\0", ""); pos += 8; } // Wall textures: textures listed in the TEXTURE1 resource are for shareware (Episode 1) maps, all others are in TEXTURE2. var texEntry = wi.EntryDictionary["TEXTURE1"]; var texList = GetTextures(wadStream, wi, GetResource(wadStream, texEntry)); foreach (var t in texList) { wi.WallTextures.Add(t.Name, t); } if (wi.EntryDictionary.ContainsKey("TEXTURE2")) { texEntry = wi.EntryDictionary["TEXTURE2"]; texList = GetTextures(wadStream, wi, GetResource(wadStream, texEntry)); foreach (var t in texList) { wi.WallTextures.Add(t.Name, t); } } return(wi); }
public MapData(WADInfo wadInfo, string name, byte[] thingsData, byte[] lineDefData, byte[] sideDefData, byte[] sectorData, byte[] subSectorData, byte[] segData, byte[] vertexData) { Name = name; Things = new MapThing[thingsData.Length / 10]; LineDefs = new MapLineDef[lineDefData.Length / 14]; SideDefs = new MapSideDef[sideDefData.Length / 30]; Sectors = new MapSector[sectorData.Length / 26]; Vertexes = new MapVertex[vertexData.Length / 4]; SubSectors = new MapSubSector[subSectorData.Length / 4]; Segs = new MapSeg[segData.Length / 12]; var pos = 0; for (var i = 0; i < Things.Length; i++) { Things[i] = new MapThing(BitConverter.ToInt16(thingsData, pos), BitConverter.ToInt16(thingsData, pos + 2), BitConverter.ToInt16(thingsData, pos + 4), BitConverter.ToInt16(thingsData, pos + 6), BitConverter.ToInt16(thingsData, pos + 8)); pos += 10; } pos = 0; for (var i = 0; i < LineDefs.Length; i++) { LineDefs[i] = new MapLineDef(BitConverter.ToInt16(lineDefData, pos), BitConverter.ToInt16(lineDefData, pos + 2), BitConverter.ToInt16(lineDefData, pos + 4), BitConverter.ToInt16(lineDefData, pos + 6), BitConverter.ToInt16(lineDefData, pos + 8), BitConverter.ToInt16(lineDefData, pos + 10), BitConverter.ToInt16(lineDefData, pos + 12)); pos += 14; } pos = 0; for (var i = 0; i < SideDefs.Length; i++) { SideDefs[i] = new MapSideDef(BitConverter.ToInt16(sideDefData, pos), BitConverter.ToInt16(sideDefData, pos + 2), Encoding.UTF8.GetString(sideDefData, pos + 4, 8).ToUpper(), Encoding.UTF8.GetString(sideDefData, pos + 12, 8).ToUpper(), Encoding.UTF8.GetString(sideDefData, pos + 20, 8).ToUpper(), BitConverter.ToInt16(sideDefData, pos + 28)); if (SideDefs[i].FullTexture != "-" && wadInfo.WallTextures.ContainsKey(SideDefs[i].FullTexture) && !WallsUsed.Contains(wadInfo.WallTextures[SideDefs[i].FullTexture])) { WallsUsed.Add(wadInfo.WallTextures[SideDefs[i].FullTexture]); } if (SideDefs[i].UpperTexture != "-" && wadInfo.WallTextures.ContainsKey(SideDefs[i].UpperTexture) && !WallsUsed.Contains(wadInfo.WallTextures[SideDefs[i].UpperTexture])) { WallsUsed.Add(wadInfo.WallTextures[SideDefs[i].UpperTexture]); } if (SideDefs[i].LowerTexture != "-" && wadInfo.WallTextures.ContainsKey(SideDefs[i].LowerTexture) && !WallsUsed.Contains(wadInfo.WallTextures[SideDefs[i].LowerTexture])) { WallsUsed.Add(wadInfo.WallTextures[SideDefs[i].LowerTexture]); } pos += 30; } pos = 0; for (var i = 0; i < Sectors.Length; i++) { Sectors[i] = new MapSector(BitConverter.ToInt16(sectorData, pos), BitConverter.ToInt16(sectorData, pos + 2), Encoding.UTF8.GetString(sectorData, pos + 4, 8).ToUpper(), Encoding.UTF8.GetString(sectorData, pos + 12, 8).ToUpper(), BitConverter.ToInt16(sectorData, pos + 20), BitConverter.ToInt16(sectorData, pos + 22), BitConverter.ToInt16(sectorData, pos + 24)); var cname = Sectors[i].CeilingTexture.Replace("\0", ""); if (Sectors[i].CeilingTexture != "-" && wadInfo.EntryDictionary.ContainsKey(cname) && !FlatsUsed.Contains(wadInfo.EntryDictionary[cname])) { FlatsUsed.Add(wadInfo.EntryDictionary[cname]); } var fname = Sectors[i].FloorTexture.Replace("\0", ""); if (Sectors[i].FloorTexture != "-" && wadInfo.EntryDictionary.ContainsKey(fname) && !FlatsUsed.Contains(wadInfo.EntryDictionary[fname])) { FlatsUsed.Add(wadInfo.EntryDictionary[fname]); } pos += 26; } pos = 0; for (var i = 0; i < SubSectors.Length; i++) { SubSectors[i] = new MapSubSector(BitConverter.ToInt16(subSectorData, pos), BitConverter.ToInt16(subSectorData, pos + 2)); pos += 4; } pos = 0; for (var i = 0; i < Segs.Length; i++) { Segs[i] = new MapSeg(BitConverter.ToInt16(segData, pos), BitConverter.ToInt16(segData, pos + 2), BitConverter.ToInt16(segData, pos + 4), BitConverter.ToInt16(segData, pos + 6), BitConverter.ToInt16(segData, pos + 8), BitConverter.ToInt16(segData, pos + 10)); pos += 12; } pos = 0; for (var i = 0; i < Vertexes.Length; i++) { Vertexes[i] = new MapVertex(BitConverter.ToInt16(vertexData, pos), BitConverter.ToInt16(vertexData, pos + 2)); pos += 4; } }