/* FontManager::initFonts * Loads all needed fonts for rendering. SFML 2.x implementation *******************************************************************/ int FontManager::initFonts() { // --- Load general fonts --- int ret = 0; // Normal ArchiveEntry* entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans.ttf"); if (entry) ++ret, font_normal.loadFromMemory((const char*)entry->getData(), entry->getSize()); // Condensed entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_c.ttf"); if (entry) ++ret, font_condensed.loadFromMemory((const char*)entry->getData(), entry->getSize()); // Bold entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_b.ttf"); if (entry) ++ret, font_bold.loadFromMemory((const char*)entry->getData(), entry->getSize()); // Condensed Bold entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_cb.ttf"); if (entry) ++ret, font_boldcondensed.loadFromMemory((const char*)entry->getData(), entry->getSize()); // Monospace entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_mono.ttf"); if (entry) ++ret, font_small.loadFromMemory((const char*)entry->getData(), entry->getSize()); return ret; }
/* HogArchive::write * Writes the hog archive to a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool HogArchive::write(MemChunk& mc, bool update) { // Determine individual lump offsets uint32_t offset = 3; ArchiveEntry* entry = NULL; for (uint32_t l = 0; l < numEntries(); l++) { offset += 17; entry = getEntry(l); setEntryOffset(entry, offset); if (update) { entry->setState(0); entry->exProp("Offset") = (int)offset; } offset += entry->getSize(); } // Clear/init MemChunk mc.clear(); mc.seek(0, SEEK_SET); mc.reSize(offset); // Write the header char header[3] = { 'D', 'H', 'F' }; mc.write(header, 3); // Write the lumps for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); mc.write(entry->getData(), entry->getSize()); } // Write the directory for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); char name[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; long size = wxINT32_SWAP_ON_BE(entry->getSize()); for (size_t c = 0; c < entry->getName().length() && c < 13; c++) name[c] = entry->getName()[c]; mc.write(name, 13); mc.write(&size, 4); mc.write(entry->getData(), entry->getSize()); } return true; }
/* MapPreviewCanvas::readThings * Reads non-UDMF thing data *******************************************************************/ bool MapPreviewCanvas::readThings(ArchiveEntry* map_head, ArchiveEntry* map_end, int map_format) { // Find THINGS entry ArchiveEntry* things = NULL; while (map_head) { // Check entry type if (map_head->getType() == EntryType::getType("map_things")) { things = map_head; break; } // Exit loop if we've reached the end of the map entries if (map_head == map_end) break; else map_head = map_head->nextEntry(); } // No things if (!things) return false; // Read things data if (map_format == MAP_DOOM) { doomthing_t* thng_data = (doomthing_t*)things->getData(true); unsigned nt = things->getSize() / sizeof(doomthing_t); for (size_t a = 0; a < nt; a++) addThing(thng_data[a].x, thng_data[a].y); } else if (map_format == MAP_DOOM64) { doom64thing_t* thng_data = (doom64thing_t*)things->getData(true); unsigned nt = things->getSize() / sizeof(doom64thing_t); for (size_t a = 0; a < nt; a++) addThing(thng_data[a].x, thng_data[a].y); } else if (map_format == MAP_HEXEN) { hexenthing_t* thng_data = (hexenthing_t*)things->getData(true); unsigned nt = things->getSize() / sizeof(hexenthing_t); for (size_t a = 0; a < nt; a++) addThing(thng_data[a].x, thng_data[a].y); } return true; }
/* ArchiveEntry::ArchiveEntry * ArchiveEntry class copy constructor *******************************************************************/ ArchiveEntry::ArchiveEntry(ArchiveEntry& copy) { // Initialise (copy) attributes this->parent = NULL; this->name = copy.name; this->size = copy.size; this->data_loaded = true; this->state = 2; this->type = copy.type; this->locked = false; this->state_locked = false; this->reliability = copy.reliability; this->next = NULL; this->prev = NULL; this->encrypted = copy.encrypted; // Copy data data.importMem(copy.getData(true), copy.getSize()); // Copy extra properties copy.exProps().copyTo(ex_props); // Clear properties that shouldn't be copied ex_props.removeProperty("ZipIndex"); ex_props.removeProperty("Offset"); // Set entry state state = 2; state_locked = false; }
/* Wad2Archive::write * Writes the wad archive to a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool Wad2Archive::write(MemChunk& mc, bool update) { // Determine directory offset & individual lump offsets uint32_t dir_offset = 12; ArchiveEntry* entry = NULL; for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); entry->exProp("Offset") = (int)dir_offset; dir_offset += entry->getSize(); } // Clear/init MemChunk mc.clear(); mc.seek(0, SEEK_SET); mc.reSize(dir_offset + numEntries() * 32); // Setup wad type char wad_type[4] = { 'W', 'A', 'D', '2' }; if (wad3) wad_type[3] = '3'; // Write the header uint32_t num_lumps = numEntries(); mc.write(wad_type, 4); mc.write(&num_lumps, 4); mc.write(&dir_offset, 4); // Write the lumps for (uint32_t l = 0; l < num_lumps; l++) { entry = getEntry(l); mc.write(entry->getData(), entry->getSize()); } // Write the directory for (uint32_t l = 0; l < num_lumps; l++) { entry = getEntry(l); // Setup directory entry wad2entry_t info; memset(info.name, 0, 16); memcpy(info.name, CHR(entry->getName()), entry->getName().Len()); info.cmprs = (bool)entry->exProp("W2Comp"); info.dsize = entry->getSize(); info.size = entry->getSize(); info.offset = (int)entry->exProp("Offset"); info.type = (int)entry->exProp("W2Type"); // Write it mc.write(&info, 32); if (update) entry->setState(0); } return true; }
/* GobArchive::write * Writes the gob archive to a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool GobArchive::write(MemChunk& mc, bool update) { // Determine directory offset & individual lump offsets uint32_t dir_offset = 8; ArchiveEntry* entry = NULL; for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); setEntryOffset(entry, dir_offset); dir_offset += entry->getSize(); } // Clear/init MemChunk mc.clear(); mc.seek(0, SEEK_SET); mc.reSize(dir_offset + 4 + numEntries() * 21); // Write the header uint32_t num_lumps = wxINT32_SWAP_ON_BE(numEntries()); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); char header[4] = { 'G', 'O', 'B', 0xA }; mc.write(header, 4); mc.write(&dir_offset, 4); // Write the lumps for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); mc.write(entry->getData(), entry->getSize()); } // Write the directory mc.write(&num_lumps, 4); for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); char name[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; long offset = wxINT32_SWAP_ON_BE(getEntryOffset(entry)); long size = wxINT32_SWAP_ON_BE(entry->getSize()); for (size_t c = 0; c < entry->getName().length() && c < 13; c++) name[c] = entry->getName()[c]; mc.write(&offset, 4); mc.write(&size, 4); mc.write(name, 13); if (update) { entry->setState(0); entry->exProp("Offset") = (int)offset; } } return true; }
/* DatArchive::write * Writes the dat archive to a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool DatArchive::write(MemChunk& mc, bool update) { // Only two bytes are used for storing entry amount, // so abort for excessively large files: if (numEntries() > 65535) return false; // Determine directory offset, name offsets & individual lump offsets uint32_t dir_offset = 10; uint16_t name_offset = numEntries() * 12; uint32_t name_size = 0; string previousname = ""; uint16_t* nameoffsets = new uint16_t[numEntries()]; ArchiveEntry* entry = NULL; for (uint16_t l = 0; l < numEntries(); l++) { entry = getEntry(l); setEntryOffset(entry, dir_offset); dir_offset += entry->getSize(); // Does the entry has a name? string name = entry->getName(); if (l > 0 && previousname.length() > 0 && name.length() > previousname.length() && !previousname.compare(0, previousname.length(), name, 0, previousname.length()) && name.at(previousname.length()) == '+') { // This is a fake name name = ""; nameoffsets[l] = 0; } else { // This is a true name previousname = name; nameoffsets[l] = uint16_t(name_offset + name_size); name_size += name.length() + 1; } } // Clear/init MemChunk mc.clear(); mc.seek(0, SEEK_SET); mc.reSize(dir_offset + name_size + numEntries() * 12); // Write the header uint16_t num_lumps = wxINT16_SWAP_ON_BE(numEntries()); dir_offset = wxINT32_SWAP_ON_BE(dir_offset); uint32_t unknown = 0; mc.write(&num_lumps, 2); mc.write(&dir_offset, 4); mc.write(&unknown, 4); // Write the lumps for (uint16_t l = 0; l < numEntries(); l++) { entry = getEntry(l); mc.write(entry->getData(), entry->getSize()); } // Write the directory for (uint16_t l = 0; l < num_lumps; l++) { entry = getEntry(l); uint32_t offset = wxINT32_SWAP_ON_BE(getEntryOffset(entry)); uint32_t size = wxINT32_SWAP_ON_BE(entry->getSize()); uint16_t nameofs = wxINT16_SWAP_ON_BE(nameoffsets[l]); uint16_t flags = wxINT16_SWAP_ON_BE((entry->isEncrypted() == ENC_SCRLE0) ? 1 : 0); mc.write(&offset, 4); // Offset mc.write(&size, 4); // Size mc.write(&nameofs, 2); // Name offset mc.write(&flags, 2); // Flags if (update) { entry->setState(0); entry->exProp("Offset") = (int)wxINT32_SWAP_ON_BE(offset); } } // Write the names for (uint16_t l = 0; l < num_lumps; l++) { uint8_t zero = 0; entry = getEntry(l); if (nameoffsets[l]) { mc.write(CHR(entry->getName()), entry->getName().length()); mc.write(&zero, 1); } } // Clean-up delete[] nameoffsets; // Finished! return true; }
/* WadArchive::write * Writes the wad archive to a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool WadArchive::write(MemChunk& mc, bool update) { // Don't write if iwad if (iwad && iwad_lock) { Global::error = "IWAD saving disabled"; return false; } // Determine directory offset & individual lump offsets uint32_t dir_offset = 12; ArchiveEntry* entry = NULL; for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); setEntryOffset(entry, dir_offset); dir_offset += entry->getSize(); } // Clear/init MemChunk mc.clear(); mc.seek(0, SEEK_SET); mc.reSize(dir_offset + numEntries() * 16); // Setup wad type char wad_type[4] = { 'P', 'W', 'A', 'D' }; if (iwad) wad_type[0] = 'I'; // Write the header uint32_t num_lumps = numEntries(); mc.write(wad_type, 4); mc.write(&num_lumps, 4); mc.write(&dir_offset, 4); // Write the lumps for (uint32_t l = 0; l < num_lumps; l++) { entry = getEntry(l); mc.write(entry->getData(), entry->getSize()); } // Write the directory for (uint32_t l = 0; l < num_lumps; l++) { entry = getEntry(l); char name[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; long offset = getEntryOffset(entry); long size = entry->getSize(); for (size_t c = 0; c < entry->getName().length() && c < 8; c++) name[c] = entry->getName()[c]; mc.write(&offset, 4); mc.write(&size, 4); mc.write(name, 8); if (update) { entry->setState(0); entry->exProp("Offset") = (int)offset; } } return true; }
GLTexture* MapTextureManager::getSprite(string name, string translation, string palette) { // Don't bother looking for nameless sprites if (name.IsEmpty()) return NULL; // Get sprite matching name string hashname = name.Upper(); if (!translation.IsEmpty()) hashname += translation.Lower(); if (!palette.IsEmpty()) hashname += palette.Upper(); map_tex_t& mtex = sprites[hashname]; // Get desired filter type int filter = 1; if (map_tex_filter == 0) filter = GLTexture::NEAREST_LINEAR_MIN; else if (map_tex_filter == 1) filter = GLTexture::LINEAR; else if (map_tex_filter == 2) filter = GLTexture::LINEAR; else if (map_tex_filter == 3) filter = GLTexture::NEAREST_MIPMAP; // If the texture is loaded if (mtex.texture) { // If the texture filter matches the desired one, return it if (mtex.texture->getFilter() == filter) return mtex.texture; else { // Otherwise, reload the texture delete mtex.texture; mtex.texture = NULL; } } // Sprite not found, look for it bool found = false; bool mirror = false; SImage image; Palette8bit* pal = getResourcePalette(); ArchiveEntry* entry = theResourceManager->getPatchEntry(name, "sprites", archive); if (!entry) entry = theResourceManager->getPatchEntry(name, "", archive); if (!entry && name.length() == 8) { string newname = name; newname[4] = name[6]; newname[5] = name[7]; newname[6] = name[4]; newname[7] = name[5]; entry = theResourceManager->getPatchEntry(newname, "sprites", archive); if (entry) mirror = true; } if (entry) { found = true; Misc::loadImageFromEntry(&image, entry); } else // Try composite textures then { CTexture* ctex = theResourceManager->getTexture(name, archive); if (ctex && ctex->toImage(image, archive, pal)) found = true; } // We have a valid image either from an entry or a composite texture. if (found) { // Apply translation if (!translation.IsEmpty()) image.applyTranslation(translation, pal); // Apply palette override if (!palette.IsEmpty()) { ArchiveEntry* newpal = theResourceManager->getPaletteEntry(palette, archive); if (newpal && newpal->getSize() == 768) { // Why is this needed? // Copying data in pal->loadMem shouldn't // change it in the original entry... // We shouldn't need to copy the data in a temporary place first. pal = image.getPalette(); MemChunk mc; mc.importMem(newpal->getData(), newpal->getSize()); pal->loadMem(mc); } } // Apply mirroring if (mirror) image.mirror(false); // Turn into GL texture mtex.texture = new GLTexture(false); mtex.texture->setFilter(filter); mtex.texture->setTiling(false); mtex.texture->loadImage(&image, pal); return mtex.texture; } else if (name.EndsWith("?")) { name.RemoveLast(1); GLTexture* sprite = getSprite(name + '0', translation, palette); if (!sprite) sprite = getSprite(name + '1', translation, palette); if (sprite) return sprite; if (!sprite && name.length() == 5) { for (char chr = 'A'; chr <= ']'; ++chr) { sprite = getSprite(name + '0' + chr + '0', translation, palette); if (sprite) return sprite; sprite = getSprite(name + '1' + chr + '1', translation, palette); if (sprite) return sprite; } } } return NULL; }
/* FontManager::initFonts * Loads all needed fonts for rendering. Non-SFML implementation *******************************************************************/ int FontManager::initFonts() { // --- Load general fonts --- int ret = 0; if (font_normal) { delete font_normal; font_normal = NULL; } if (font_condensed) { delete font_condensed; font_condensed = NULL; } if (font_bold) { delete font_bold; font_bold = NULL; } if (font_boldcondensed) { delete font_boldcondensed; font_boldcondensed = NULL; } if (font_mono) { delete font_mono; font_mono = NULL; } if (font_small) { delete font_small; font_small = NULL; } // Normal ArchiveEntry* entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans.ttf"); if (entry) { font_normal = new FTTextureFont(entry->getData(), entry->getSize()); font_normal->FaceSize(gl_font_size); // Check it loaded ok if (font_normal->Error()) { delete font_normal; font_normal = NULL; } else ++ ret; } // Condensed entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_c.ttf"); if (entry) { font_condensed = new FTTextureFont(entry->getData(), entry->getSize()); font_condensed->FaceSize(gl_font_size); // Check it loaded ok if (font_condensed->Error()) { delete font_condensed; font_condensed = NULL; } else ++ ret; } // Bold entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_b.ttf"); if (entry) { font_bold = new FTTextureFont(entry->getData(), entry->getSize()); font_bold->FaceSize(gl_font_size); // Check it loaded ok if (font_bold->Error()) { delete font_bold; font_bold = NULL; } else ++ ret; } // Condensed bold entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_cb.ttf"); if (entry) { font_boldcondensed = new FTTextureFont(entry->getData(), entry->getSize()); font_boldcondensed->FaceSize(gl_font_size); // Check it loaded ok if (font_boldcondensed->Error()) { delete font_boldcondensed; font_boldcondensed = NULL; } else ++ ret; } // Monospace entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_mono.ttf"); if (entry) { font_mono = new FTTextureFont(entry->getData(), entry->getSize()); font_mono->FaceSize(gl_font_size); // Check it loaded ok if (font_mono->Error()) { delete font_mono; font_mono = NULL; } else ++ ret; } // Small entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans.ttf"); if (entry) { font_small = new FTTextureFont(entry->getData(), entry->getSize()); font_small->FaceSize((gl_font_size * 0.6) + 1); // Check it loaded ok if (font_small->Error()) { delete font_small; font_small = NULL; } else ++ ret; } return ret; }
/* MapPreviewCanvas::openMap * Opens a map from a mapdesc_t *******************************************************************/ bool MapPreviewCanvas::openMap(Archive::mapdesc_t map) { // All errors = invalid map Global::error = "Invalid map"; // Check if this map is a pk3 map bool map_archive = false; if (map.archive) { map_archive = true; // Attempt to open entry as wad archive temp_archive = new WadArchive(); if (!temp_archive->open(map.head)) { delete temp_archive; return false; } // Detect maps vector<Archive::mapdesc_t> maps = temp_archive->detectMaps(); // Set map if there are any in the archive if (maps.size() > 0) map = maps[0]; else return false; } // Parse UDMF map if (map.format == MAP_UDMF) { ArchiveEntry* udmfdata = NULL; for (ArchiveEntry* mapentry = map.head; mapentry != map.end; mapentry = mapentry->nextEntry()) { // Check entry type if (mapentry->getType() == EntryType::getType("udmf_textmap")) { udmfdata = mapentry; break; } } if (udmfdata == NULL) return false; // Start parsing Tokenizer tz; tz.openMem(udmfdata->getData(), udmfdata->getSize(), map.head->getName()); // Get first token string token = tz.getToken(); size_t vertcounter = 0, linecounter = 0, thingcounter = 0; while (!token.IsEmpty()) { if (!token.CmpNoCase("namespace")) { // skip till we reach the ';' do { token = tz.getToken(); } while (token.Cmp(";")); } else if (!token.CmpNoCase("vertex")) { // Get X and Y properties bool gotx = false; bool goty = false; double x = 0.; double y = 0.; do { token = tz.getToken(); if (!token.CmpNoCase("x") || !token.CmpNoCase("y")) { bool isx = !token.CmpNoCase("x"); token = tz.getToken(); if (token.Cmp("=")) { wxLogMessage("Bad syntax for vertex %i in UDMF map data", vertcounter); return false; } if (isx) x = tz.getDouble(), gotx = true; else y = tz.getDouble(), goty = true; // skip to end of declaration after each key do { token = tz.getToken(); } while (token.Cmp(";")); } } while (token.Cmp("}")); if (gotx && goty) addVertex(x, y); else { wxLogMessage("Wrong vertex %i in UDMF map data", vertcounter); return false; } vertcounter++; } else if (!token.CmpNoCase("linedef")) { bool special = false; bool twosided = false; bool gotv1 = false, gotv2 = false; size_t v1 = 0, v2 = 0; do { token = tz.getToken(); if (!token.CmpNoCase("v1") || !token.CmpNoCase("v2")) { bool isv1 = !token.CmpNoCase("v1"); token = tz.getToken(); if (token.Cmp("=")) { wxLogMessage("Bad syntax for linedef %i in UDMF map data", linecounter); return false; } if (isv1) v1 = tz.getInteger(), gotv1 = true; else v2 = tz.getInteger(), gotv2 = true; // skip to end of declaration after each key do { token = tz.getToken(); } while (token.Cmp(";")); } else if (!token.CmpNoCase("special")) { special = true; // skip to end of declaration after each key do { token = tz.getToken(); } while (token.Cmp(";")); } else if (!token.CmpNoCase("sideback")) { twosided = true; // skip to end of declaration after each key do { token = tz.getToken(); } while (token.Cmp(";")); } } while (token.Cmp("}")); if (gotv1 && gotv2) addLine(v1, v2, twosided, special); else { wxLogMessage("Wrong line %i in UDMF map data", linecounter); return false; } linecounter++; } else if (S_CMPNOCASE(token, "thing")) { // Get X and Y properties bool gotx = false; bool goty = false; double x = 0.; double y = 0.; do { token = tz.getToken(); if (!token.CmpNoCase("x") || !token.CmpNoCase("y")) { bool isx = !token.CmpNoCase("x"); token = tz.getToken(); if (token.Cmp("=")) { wxLogMessage("Bad syntax for thing %i in UDMF map data", vertcounter); return false; } if (isx) x = tz.getDouble(), gotx = true; else y = tz.getDouble(), goty = true; // skip to end of declaration after each key do { token = tz.getToken(); } while (token.Cmp(";")); } } while (token.Cmp("}")); if (gotx && goty) addThing(x, y); else { wxLogMessage("Wrong thing %i in UDMF map data", vertcounter); return false; } vertcounter++; } else { // Check for side or sector definition (increase counts) if (S_CMPNOCASE(token, "sidedef")) n_sides++; else if (S_CMPNOCASE(token, "sector")) n_sectors++; // map preview ignores sidedefs, sectors, comments, // unknown fields, etc. so skip to end of block do { token = tz.getToken(); } while (token.Cmp("}")); } // Iterate to next token token = tz.getToken(); } } // Non-UDMF map if (map.format != MAP_UDMF) { // Read vertices (required) if (!readVertices(map.head, map.end, map.format)) return false; // Read linedefs (required) if (!readLines(map.head, map.end, map.format)) return false; // Read things if (map.format != MAP_UDMF) readThings(map.head, map.end, map.format); // Read sides & sectors (count only) ArchiveEntry* sidedefs = NULL; ArchiveEntry* sectors = NULL; while (map.head) { // Check entry type if (map.head->getType() == EntryType::getType("map_sidedefs")) sidedefs = map.head; if (map.head->getType() == EntryType::getType("map_sectors")) sectors = map.head; // Exit loop if we've reached the end of the map entries if (map.head == map.end) break; else map.head = map.head->nextEntry(); } if (sidedefs && sectors) { // Doom64 map if (map.format != MAP_DOOM64) { n_sides = sidedefs->getSize() / 30; n_sectors = sectors->getSize() / 26; } // Doom/Hexen map else { n_sides = sidedefs->getSize() / 12; n_sectors = sectors->getSize() / 16; } } } // Clean up if (map_archive) { temp_archive->close(); delete temp_archive; temp_archive = NULL; } // Refresh map Refresh(); return true; }
/* LfdArchive::write * Writes the lfd archive to a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool LfdArchive::write(MemChunk& mc, bool update) { // Determine total size uint32_t dir_size = (numEntries() + 1)<<4; uint32_t total_size = dir_size; ArchiveEntry* entry = NULL; for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); total_size += 16; setEntryOffset(entry, total_size); if (update) { entry->setState(0); entry->exProp("Offset") = (int)total_size; } total_size += entry->getSize(); } // Clear/init MemChunk mc.clear(); mc.seek(0, SEEK_SET); mc.reSize(total_size); // Variables char type[5] = "RMAP"; char name[9] = "resource"; size_t size = wxINT32_SWAP_ON_BE(numEntries()<<4); // Write the resource map first mc.write(type, 4); mc.write(name, 8); mc.write(&size,4); for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); for (int t = 0; t < 5; ++t) type[t] = 0; for (int n = 0; n < 9; ++n) name[n] = 0; size = wxINT32_SWAP_ON_BE(entry->getSize()); wxFileName fn(entry->getName()); for (size_t c = 0; c < fn.GetName().length() && c < 9; c++) name[c] = fn.GetName()[c]; for (size_t c = 0; c < fn.GetExt().length() && c < 5; c++) type[c] = fn.GetExt()[c]; mc.write(type, 4); mc.write(name, 8); mc.write(&size,4); } // Write the lumps for (uint32_t l = 0; l < numEntries(); l++) { entry = getEntry(l); for (int t = 0; t < 5; ++t) type[t] = 0; for (int n = 0; n < 9; ++n) name[n] = 0; size = wxINT32_SWAP_ON_BE(entry->getSize()); wxFileName fn(entry->getName()); for (size_t c = 0; c < fn.GetName().length() && c < 9; c++) name[c] = fn.GetName()[c]; for (size_t c = 0; c < fn.GetExt().length() && c < 5; c++) type[c] = fn.GetExt()[c]; mc.write(type, 4); mc.write(name, 8); mc.write(&size,4); mc.write(entry->getData(), entry->getSize()); } return true; }
/* MapPreviewCanvas::openMap * Opens a map from a mapdesc_t *******************************************************************/ bool MapPreviewCanvas::openMap(Archive::mapdesc_t map) { // All errors = invalid map Global::error = "Invalid map"; // Check if this map is a pk3 map bool map_archive = false; if (map.archive) { map_archive = true; // Attempt to open entry as wad archive temp_archive = new WadArchive(); if (!temp_archive->open(map.head)) { delete temp_archive; return false; } // Detect maps vector<Archive::mapdesc_t> maps = temp_archive->detectMaps(); // Set map if there are any in the archive if (maps.size() > 0) map = maps[0]; else return false; } // Parse UDMF map if (map.format == MAP_UDMF) { ArchiveEntry* udmfdata = NULL; for (ArchiveEntry* mapentry = map.head; mapentry != map.end; mapentry = mapentry->nextEntry()) { // Check entry type if (mapentry->getType() == EntryType::getType("udmf_textmap")) { udmfdata = mapentry; break; } } if (udmfdata == NULL) return false; // Start parsing Tokenizer tz; tz.openMem(udmfdata->getData(), udmfdata->getSize(), map.head->getName()); // Get first token string token = tz.getToken(); size_t vertcounter = 0, linecounter = 0; while (!token.IsEmpty()) { if (!token.CmpNoCase("namespace")) { // skip till we reach the ';' do { token = tz.getToken(); } while (token.Cmp(";")); } else if (!token.CmpNoCase("vertex")) { // Get X and Y properties bool gotx = false; bool goty = false; double x = 0.; double y = 0.; do { token = tz.getToken(); if (!token.CmpNoCase("x") || !token.CmpNoCase("y")) { bool isx = !token.CmpNoCase("x"); token = tz.getToken(); if (token.Cmp("=")) { wxLogMessage("Bad syntax for vertex %i in UDMF map data", vertcounter); return false; } if (isx) x = tz.getDouble(), gotx = true; else y = tz.getDouble(), goty = true; // skip to end of declaration after each key do { token = tz.getToken(); } while (token.Cmp(";")); } } while (token.Cmp("}")); if (gotx && goty) addVertex(x, y); else { wxLogMessage("Wrong vertex %i in UDMF map data", vertcounter); return false; } vertcounter++; } else if (!token.CmpNoCase("linedef")) { bool special = false; bool twosided = false; bool gotv1 = false, gotv2 = false; size_t v1 = 0, v2 = 0; do { token = tz.getToken(); if (!token.CmpNoCase("v1") || !token.CmpNoCase("v2")) { bool isv1 = !token.CmpNoCase("v1"); token = tz.getToken(); if (token.Cmp("=")) { wxLogMessage("Bad syntax for linedef %i in UDMF map data", linecounter); return false; } if (isv1) v1 = tz.getInteger(), gotv1 = true; else v2 = tz.getInteger(), gotv2 = true; // skip to end of declaration after each key do { token = tz.getToken(); } while (token.Cmp(";")); } else if (!token.CmpNoCase("special")) { special = true; // skip to end of declaration after each key do { token = tz.getToken(); } while (token.Cmp(";")); } else if (!token.CmpNoCase("sideback")) { twosided = true; // skip to end of declaration after each key do { token = tz.getToken(); } while (token.Cmp(";")); } } while (token.Cmp("}")); if (gotv1 && gotv2) addLine(v1, v2, twosided, special); else { wxLogMessage("Wrong line %i in UDMF map data", linecounter); return false; } linecounter++; } else { // map preview ignores things, sidedefs, sectors, comments, // unknown fields, etc. so skip to end of block do { token = tz.getToken(); } while (token.Cmp("}")); } // Iterate to next token token = tz.getToken(); } } // Read vertices if (map.format == MAP_DOOM || map.format == MAP_HEXEN || map.format == MAP_DOOM64) { // Find VERTEXES entry ArchiveEntry* mapentry = map.head; ArchiveEntry* vertexes = NULL; while (mapentry) { // Check entry type if (mapentry->getType() == EntryType::getType("map_vertexes")) { vertexes = mapentry; break; } // Exit loop if we've reached the end of the map entries if (mapentry == map.end) break; else mapentry = mapentry->nextEntry(); } // Can't open a map without vertices if (!vertexes) return false; // Read vertex data MemChunk& mc = vertexes->getMCData(); mc.seek(0, SEEK_SET); if (map.format == MAP_DOOM64) { doom64vertex_t v; while (1) { // Read vertex if (!mc.read(&v, 8)) break; // Add vertex addVertex((double)v.x/65536, (double)v.y/65536); } } else { doomvertex_t v; while (1) { // Read vertex if (!mc.read(&v, 4)) break; // Add vertex addVertex((double)v.x, (double)v.y); } } } // Read linedefs if (map.format == MAP_DOOM || map.format == MAP_HEXEN || map.format == MAP_DOOM64) { // Find LINEDEFS entry ArchiveEntry* mapentry = map.head; ArchiveEntry* linedefs = NULL; while (mapentry) { // Check entry type if (mapentry->getType() == EntryType::getType("map_linedefs")) { linedefs = mapentry; break; } // Exit loop if we've reached the end of the map entries if (mapentry == map.end) break; else mapentry = mapentry->nextEntry(); } // Can't open a map without linedefs if (!linedefs) return false; // Read line data MemChunk& mc = linedefs->getMCData(); mc.seek(0, SEEK_SET); if (map.format == MAP_DOOM) { while (1) { // Read line doomline_t l; if (!mc.read(&l, sizeof(doomline_t))) break; // Check properties bool special = false; bool twosided = false; if (l.side2 != 0xFFFF) twosided = true; if (l.type > 0) special = true; // Add line addLine(l.vertex1, l.vertex2, twosided, special); } } else if (map.format == MAP_DOOM64) { while (1) { // Read line doom64line_t l; if (!mc.read(&l, sizeof(doom64line_t))) break; // Check properties bool macro = false; bool special = false; bool twosided = false; if (l.side2 != 0xFFFF) twosided = true; if (l.type > 0) { if (l.type & 0x100) macro = true; else special = true; } // Add line addLine(l.vertex1, l.vertex2, twosided, special, macro); } } else if (map.format == MAP_HEXEN) { while (1) { // Read line hexenline_t l; if (!mc.read(&l, sizeof(hexenline_t))) break; // Check properties bool special = false; bool twosided = false; if (l.side2 != 0xFFFF) twosided = true; if (l.type > 0) special = true; // Add line addLine(l.vertex1, l.vertex2, twosided, special); } } } // Clean up if (map_archive) { temp_archive->close(); delete temp_archive; temp_archive = NULL; } // Refresh map Refresh(); return true; }