// ----------------------------------------------------------------------------- // Reads non-UDMF vertex data // ----------------------------------------------------------------------------- bool MapPreviewCanvas::readVertices(ArchiveEntry* map_head, ArchiveEntry* map_end, MapFormat map_format) { // Find VERTEXES entry ArchiveEntry* vertexes = nullptr; while (map_head) { // Check entry type if (map_head->type() == EntryType::fromId("map_vertexes")) { vertexes = 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(); } // Can't open a map without vertices if (!vertexes) return false; // Read vertex data auto& mc = vertexes->data(); mc.seek(0, SEEK_SET); if (map_format == MapFormat::Doom64) { Doom64MapFormat::Vertex v; while (true) { // Read vertex if (!mc.read(&v, 8)) break; // Add vertex addVertex((double)v.x / 65536, (double)v.y / 65536); } } else { DoomMapFormat::Vertex v; while (true) { // Read vertex if (!mc.read(&v, 4)) break; // Add vertex addVertex((double)v.x, (double)v.y); } } return true; }
// ----------------------------------------------------------------------------- // Compare the archive's entries with those sharing the same name and namespace // in the base resource archive, deleting duplicates // ----------------------------------------------------------------------------- void ArchiveOperations::removeEntriesUnchangedFromIWAD(Archive* archive) { // Do nothing if there is no base resource archive, // or if the archive *is* the base resource archive. auto bra = App::archiveManager().baseResourceArchive(); if (bra == nullptr || bra == archive || archive == nullptr) return; // Get list of all entries in archive vector<ArchiveEntry*> entries; archive->putEntryTreeAsList(entries); // Init search options Archive::SearchOptions search; ArchiveEntry* other = nullptr; wxString dups = ""; size_t count = 0; // Go through list for (auto& entry : entries) { // Skip directory entries if (entry->type() == EntryType::folderType()) continue; // Skip markers if (entry->type() == EntryType::mapMarkerType() || entry->size() == 0) continue; // Now, let's look for a counterpart in the IWAD search.match_namespace = archive->detectNamespace(entry); search.match_name = entry->name(); other = bra->findLast(search); // If there is one, and it is identical, remove it if (other != nullptr && (other->data().crc() == entry->data().crc())) { ++count; dups += wxString::Format("%s\n", search.match_name); archive->removeEntry(entry); entry = nullptr; } } // If no duplicates exist, do nothing if (count == 0) { wxMessageBox("No duplicated entries exist"); return; } wxString message = wxString::Format( "The following %d entr%s duplicated from the base resource archive and deleted:", count, (count > 1) ? "ies were" : "y was"); // Display list of deleted duplicate entries ExtMessageDialog msg(theMainWindow, (count > 1) ? "Deleted Entries" : "Deleted Entry"); msg.setExt(dups); msg.setMessage(message); msg.ShowModal(); }
// ----------------------------------------------------------------------------- // Opens a map from a mapdesc_t // ----------------------------------------------------------------------------- bool MapPreviewCanvas::openMap(Archive::MapDesc 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 auto maps = temp_archive_->detectMaps(); // Set map if there are any in the archive if (!maps.empty()) map = maps[0]; else return false; } // Parse UDMF map if (map.format == MapFormat::UDMF) { ArchiveEntry* udmfdata = nullptr; for (auto mapentry = map.head; mapentry != map.end; mapentry = mapentry->nextEntry()) { // Check entry type if (mapentry->type() == EntryType::fromId("udmf_textmap")) { udmfdata = mapentry; break; } } if (udmfdata == nullptr) return false; // Start parsing Tokenizer tz; tz.openMem(udmfdata->data(), map.head->name()); // Get first token wxString 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("=")) { Log::error(wxString::Format("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 { Log::error(wxString::Format("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("=")) { Log::error(wxString::Format("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 { Log::error(wxString::Format("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("=")) { Log::error(wxString::Format("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 { Log::error(wxString::Format("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("}") && !token.empty()); } // Iterate to next token token = tz.getToken(); } } // Non-UDMF map if (map.format != MapFormat::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 != MapFormat::UDMF) readThings(map.head, map.end, map.format); // Read sides & sectors (count only) ArchiveEntry* sidedefs = nullptr; ArchiveEntry* sectors = nullptr; while (map.head) { // Check entry type if (map.head->type() == EntryType::fromId("map_sidedefs")) sidedefs = map.head; if (map.head->type() == EntryType::fromId("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 != MapFormat::Doom64) { n_sides_ = sidedefs->size() / 30; n_sectors_ = sectors->size() / 26; } // Doom/Hexen map else { n_sides_ = sidedefs->size() / 12; n_sectors_ = sectors->size() / 16; } } } // Clean up if (map_archive) { temp_archive_->close(); delete temp_archive_; temp_archive_ = nullptr; } // Refresh map Refresh(); return true; }
// ----------------------------------------------------------------------------- // Reads non-UDMF line data // ----------------------------------------------------------------------------- bool MapPreviewCanvas::readLines(ArchiveEntry* map_head, ArchiveEntry* map_end, MapFormat map_format) { // Find LINEDEFS entry ArchiveEntry* linedefs = nullptr; while (map_head) { // Check entry type if (map_head->type() == EntryType::fromId("map_linedefs")) { linedefs = 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(); } // Can't open a map without linedefs if (!linedefs) return false; // Read line data auto& mc = linedefs->data(); mc.seek(0, SEEK_SET); if (map_format == MapFormat::Doom) { while (true) { // Read line DoomMapFormat::LineDef l; if (!mc.read(&l, sizeof(DoomMapFormat::LineDef))) 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 == MapFormat::Doom64) { while (true) { // Read line Doom64MapFormat::LineDef l; if (!mc.read(&l, sizeof(Doom64MapFormat::LineDef))) 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 == MapFormat::Hexen) { while (true) { // Read line HexenMapFormat::LineDef l; if (!mc.read(&l, sizeof(HexenMapFormat::LineDef))) 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); } } return true; }