Palette8bit* MapTextureManager::getResourcePalette() { if (thePaletteChooser->globalSelected()) { ArchiveEntry* entry = theResourceManager->getPaletteEntry("PLAYPAL", archive); if (!entry) return thePaletteChooser->getSelectedPalette(); palette->loadMem(entry->getMCData()); return palette; } else return thePaletteChooser->getSelectedPalette(); }
/* Executables::init * Reads all executable definitions from the program resource * and user dir *******************************************************************/ void Executables::init() { // Load from pk3 Archive* res_archive = theArchiveManager->programResourceArchive(); ArchiveEntry* entry = res_archive->entryAtPath("config/executables.cfg"); if (!entry) return; // Parse base executables config Parser p; p.parseText(entry->getMCData(), "slade.pk3 - executables.cfg"); parse(&p, false); // Parse user executables config Parser p2; MemChunk mc; if (mc.importFile(App::path("executables.cfg", App::Dir::User))) { p2.parseText(mc, "user execuatbles.cfg"); parse(&p2, true); } }
/* GfxEntryPanel::extractAll * Extract all sub-images as individual PNGs *******************************************************************/ bool GfxEntryPanel::extractAll() { if (getImage()->getSize() < 2) return false; // Remember where we are int imgindex = getImage()->getIndex(); Archive* parent = entry->getParent(); if (parent == NULL) return false; int index = parent->entryIndex(entry, entry->getParentDir()); string name = wxFileName(entry->getName()).GetName(); // Loop through subimages and get things done int pos = 0; for (int i = 0; i < getImage()->getSize(); ++i) { string newname = S_FMT("%s_%i.png", name, i); Misc::loadImageFromEntry(getImage(), entry, i); // Only process images that actually contain some pixels if (getImage()->getWidth() && getImage()->getHeight()) { ArchiveEntry* newimg = parent->addNewEntry(newname, index+pos+1, entry->getParentDir()); if (newimg == NULL) return false; SIFormat::getFormat("png")->saveImage(*getImage(), newimg->getMCData(), gfx_canvas->getPalette()); EntryType::detectEntryType(newimg); pos++; } } // Reload image of where we were Misc::loadImageFromEntry(getImage(), entry, imgindex); return true; }
/* ResArchive::readDirectory * Reads a res directory from a MemChunk * Returns true if successful, false otherwise *******************************************************************/ bool ResArchive::readDirectory(MemChunk& mc, size_t dir_offset, size_t num_lumps, ArchiveTreeNode* parent) { if (!parent) { LOG_MESSAGE(1, "ReadDir: No parent node"); Global::error = "Archive is invalid and/or corrupt"; return false; } mc.seek(dir_offset, SEEK_SET); for (uint32_t d = 0; d < num_lumps; d++) { // Update splash window progress UI::setSplashProgress(((float)d / (float)num_lumps)); // Read lump info char magic[4] = ""; char name[15] = ""; uint32_t dumzero1, dumzero2; uint16_t dumff, dumze; uint8_t flags = 0; uint32_t offset = 0; uint32_t size = 0; mc.read(magic, 4); // ReS\0 mc.read(name, 14); // Name mc.read(&offset, 4); // Offset mc.read(&size, 4); // Size // Check the identifier if (magic[0] != 'R' || magic[1] != 'e' || magic[2] != 'S' || magic[3] != 0) { LOG_MESSAGE(1, "ResArchive::readDir: Entry %s (%i@0x%x) has invalid directory entry", name, size, offset); Global::error = "Archive is invalid and/or corrupt"; return false; } // Byteswap values for big endian if needed offset = wxINT32_SWAP_ON_BE(offset); size = wxINT32_SWAP_ON_BE(size); name[14] = '\0'; mc.read(&dumze, 2); if (dumze) LOG_MESSAGE(1, "Flag guard not null for entry %s", name); mc.read(&flags, 1); if (flags != 1 && flags != 17) LOG_MESSAGE(1, "Unknown flag value for entry %s", name); mc.read(&dumzero1, 4); if (dumzero1) LOG_MESSAGE(1, "Near-end values not set to zero for entry %s", name); mc.read(&dumff, 2); if (dumff != 0xFFFF) LOG_MESSAGE(1, "Dummy set to a non-FF value for entry %s", name); mc.read(&dumzero2, 4); if (dumzero2) LOG_MESSAGE(1, "Trailing values not set to zero for entry %s", name); // If the lump data goes past the end of the file, // the resfile is invalid if (offset + size > mc.getSize()) { LOG_MESSAGE(1, "ResArchive::readDirectory: Res archive is invalid or corrupt, offset overflow"); Global::error = "Archive is invalid and/or corrupt"; setMuted(false); return false; } // Create & setup lump ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(name), size); nlump->setLoaded(false); nlump->exProp("Offset") = (int)offset; nlump->setState(0); // Read entry data if it isn't zero-sized if (nlump->getSize() > 0) { // Read the entry data MemChunk edata; mc.exportMemChunk(edata, offset, size); nlump->importMemChunk(edata); } // What if the entry is a directory? size_t d_o, n_l; if (isResArchive(nlump->getMCData(), d_o, n_l)) { ArchiveTreeNode* ndir = createDir(name, parent); if (ndir) { UI::setSplashProgressMessage(S_FMT("Reading res archive data: %s directory", name)); // Save offset to restore it once the recursion is done size_t myoffset = mc.currentPos(); readDirectory(mc, d_o, n_l, ndir); ndir->getDirEntry()->setState(0); // Restore offset and clean out the entry mc.seek(myoffset, SEEK_SET); delete nlump; } else { delete nlump; return false; } // Not a directory, then add to entry list } else { parent->addEntry(nlump); // Detect entry type EntryType::detectEntryType(nlump); // Unload entry data if needed if (!archive_load_data) nlump->unloadData(); // Set entry to unchanged nlump->setState(0); } } return true; }
bool PaletteEntryPanel::generateColormaps() { if (!entry || !entry->getParent() || ! palettes[0]) return false; MemChunk mc; SImage img; MemChunk imc; mc.reSize(34*256); mc.seek(0, SEEK_SET); imc.reSize(34*256*4); imc.seek(0, SEEK_SET); uint8_t rgba[4]; rgba[3] = 255; rgba_t rgb; float grey; // Generate 34 maps: the first 32 for diminishing light levels, // the 33th for the inverted grey map used by invulnerability. // The 34th colormap remains empty and black. for (size_t l = 0; l < 34; ++l) { for (size_t c = 0; c < 256; ++c) { rgb = palettes[0]->colour(c); if (l < 32) { // Generate light maps DIMINISH(rgb.r, l); DIMINISH(rgb.g, l); DIMINISH(rgb.b, l); #if (0) } else if (l == GREENMAP) { // Point of mostly useless trivia: the green "light amp" colormap in the Press Release beta // have colors that, on average, correspond to a bit less than (R*75/256, G*225/256, B*115/256) #endif } else if (l == GRAYMAP) { // Generate inverse map grey = ((float)rgb.r/256.0 * col_greyscale_r) + ((float)rgb.g/256.0 * col_greyscale_g) + ((float)rgb.b/256.0 * col_greyscale_b); grey = 1.0 - grey; // Clamp value: with Id Software's values, the sum is greater than 1.0 (0.299+0.587+0.144=1.030) // This means the negation above can give a negative value (for example, with RGB values of 247 or more), // which will not be converted correctly to unsigned 8-bit int in the rgba_t struct. if (grey < 0.0) grey = 0; rgb.r = rgb.g = rgb.b = grey*255; } else { // Fill with 0 rgb = palettes[0]->colour(0); } rgba[0] = rgb.r; rgba[1] = rgb.g; rgba[2] = rgb.b; imc.write(&rgba, 4); mc[(256*l)+c] = palettes[0]->nearestColour(rgb); } } #if 0 // Create truecolor image uint8_t* imd = new uint8_t[256*34*4]; memcpy(imd, imc.getData(), 256*34*4); img.setImageData(imd, 256, 34, RGBA); // imd will be freed by img's destructor ArchiveEntry* tcolormap; string name = entry->getName(true) + "-tcm.png"; tcolormap = new ArchiveEntry(name); if (tcolormap) { entry->getParent()->addEntry(tcolormap); SIFormat::getFormat("png")->saveImage(img, tcolormap->getMCData()); EntryType::detectEntryType(tcolormap); } #endif // Now override or create new entry ArchiveEntry* colormap; colormap = entry->getParent()->getEntry("COLORMAP", true); bool preexisting = colormap != NULL; if (!colormap) { // We need to create this entry colormap = new ArchiveEntry("COLORMAP.lmp", 34*256); } if (!colormap) return false; colormap->importMemChunk(mc); if (!preexisting) { entry->getParent()->addEntry(colormap); } return true; }
/* StyleSet::loadResourceStyles * Loads all text styles from the slade resource archive (slade.pk3) *******************************************************************/ bool StyleSet::loadResourceStyles() { // Get 'config/text_styles' directory in slade.pk3 ArchiveTreeNode* dir = theArchiveManager->programResourceArchive()->getDir("config/text_styles"); // Check it exists if (!dir) { wxLogMessage("Warning: No 'config/text_styles' directory exists in slade.pk3"); return false; } // Read default style set first ArchiveEntry* default_style = dir->getEntry("default.sss"); if (default_style) { // Read entry data into tokenizer Tokenizer tz; tz.openMem(&default_style->getMCData(), default_style->getName()); // Parse it ParseTreeNode root; root.allowDup(true); root.parse(tz); // Read any styleset definitions vector<STreeNode*> nodes = root.getChildren("styleset"); for (unsigned b = 0; b < nodes.size(); b++) { StyleSet* newset = new StyleSet(); if (newset->parseSet((ParseTreeNode*)nodes[b])) style_sets.push_back(newset); else delete newset; } } // Go through all entries within it for (unsigned a = 0; a < dir->numEntries(); a++) { ArchiveEntry* entry = dir->getEntry(a); // Skip default if (entry->getName(true) == "default") continue; // Read entry data into tokenizer Tokenizer tz; tz.openMem(&entry->getMCData(), entry->getName()); // Parse it ParseTreeNode root; root.allowDup(true); root.parse(tz); // Read any styleset definitions vector<STreeNode*> nodes = root.getChildren("styleset"); for (unsigned b = 0; b < nodes.size(); b++) { StyleSet* newset = new StyleSet(); if (newset->parseSet((ParseTreeNode*)nodes[b])) style_sets.push_back(newset); else delete newset; } } return true; }
/* MapPreviewCanvas::draw * Draws the map *******************************************************************/ void MapPreviewCanvas::draw() { // Setup colours rgba_t col_view_background = ColourConfiguration::getColour("map_view_background"); rgba_t col_view_line_1s = ColourConfiguration::getColour("map_view_line_1s"); rgba_t col_view_line_2s = ColourConfiguration::getColour("map_view_line_2s"); rgba_t col_view_line_special = ColourConfiguration::getColour("map_view_line_special"); rgba_t col_view_line_macro = ColourConfiguration::getColour("map_view_line_macro"); rgba_t col_view_thing = ColourConfiguration::getColour("map_view_thing"); // Setup the viewport glViewport(0, 0, GetSize().x, GetSize().y); // Setup the screen projection glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, GetSize().x, 0, GetSize().y, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Clear glClearColor(((double)col_view_background.r)/255.f, ((double)col_view_background.g)/255.f, ((double)col_view_background.b)/255.f, ((double)col_view_background.a)/255.f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Translate to inside of pixel (otherwise inaccuracies can occur on certain gl implementations) if (OpenGL::accuracyTweak()) glTranslatef(0.375f, 0.375f, 0); // Zoom/offset to show full map showMap(); // Translate to middle of canvas glTranslated(GetSize().x * 0.5, GetSize().y * 0.5, 0); // Zoom glScaled(zoom, zoom, 1); // Translate to offset glTranslated(-offset_x, -offset_y, 0); // Setup drawing glDisable(GL_TEXTURE_2D); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glLineWidth(1.5f); glEnable(GL_LINE_SMOOTH); // Draw lines for (unsigned a = 0; a < lines.size(); a++) { mep_line_t line = lines[a]; // Check ends if (line.v1 >= verts.size() || line.v2 >= verts.size()) continue; // Get vertices mep_vertex_t v1 = verts[lines[a].v1]; mep_vertex_t v2 = verts[lines[a].v2]; // Set colour if (line.special) OpenGL::setColour(col_view_line_special); else if (line.macro) OpenGL::setColour(col_view_line_macro); else if (line.twosided) OpenGL::setColour(col_view_line_2s); else OpenGL::setColour(col_view_line_1s); // Draw line glBegin(GL_LINES); glVertex2d(v1.x, v1.y); glVertex2d(v2.x, v2.y); glEnd(); } // Load thing texture if needed if (!tex_loaded) { // Load thing texture SImage image; ArchiveEntry* entry = theArchiveManager->programResourceArchive()->entryAtPath("images/thing/normal_n.png"); if (entry) { image.open(entry->getMCData()); tex_thing = new GLTexture(false); tex_thing->setFilter(GLTexture::MIPMAP); tex_thing->loadImage(&image); } else tex_thing = NULL; tex_loaded = true; } // Draw things if (map_view_things) { OpenGL::setColour(col_view_thing); if (tex_thing) { double radius = 20; glEnable(GL_TEXTURE_2D); tex_thing->bind(); for (unsigned a = 0; a < things.size(); a++) { glPushMatrix(); glTranslated(things[a].x, things[a].y, 0); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex2d(-radius, -radius); glTexCoord2f(0.0f, 1.0f); glVertex2d(-radius, radius); glTexCoord2f(1.0f, 1.0f); glVertex2d(radius, radius); glTexCoord2f(1.0f, 0.0f); glVertex2d(radius, -radius); glEnd(); glPopMatrix(); } } else { glEnable(GL_POINT_SMOOTH); glPointSize(8.0f); glBegin(GL_POINTS); for (unsigned a = 0; a < things.size(); a++) glVertex2d(things[a].x, things[a].y); glEnd(); } } glLineWidth(1.0f); glDisable(GL_LINE_SMOOTH); // Swap buffers (ie show what was drawn) SwapBuffers(); }
/* MapPreviewCanvas::readLines * Reads non-UDMF line data *******************************************************************/ bool MapPreviewCanvas::readLines(ArchiveEntry* map_head, ArchiveEntry* map_end, int map_format) { // Find LINEDEFS entry ArchiveEntry* linedefs = NULL; while (map_head) { // Check entry type if (map_head->getType() == EntryType::getType("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 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); } } 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. Archive* bra = App::archiveManager().baseResourceArchive(); if (bra == nullptr || bra == archive || archive == nullptr) return; // Get list of all entries in archive vector<ArchiveEntry*> entries; archive->getEntryTreeAsList(entries); // Init search options Archive::SearchOptions search; ArchiveEntry* other = nullptr; string dups = ""; size_t count = 0; // Go through list for (unsigned a = 0; a < entries.size(); a++) { // Skip directory entries if (entries[a]->getType() == EntryType::folderType()) continue; // Skip markers if (entries[a]->getType() == EntryType::mapMarkerType() || entries[a]->getSize() == 0) continue; // Now, let's look for a counterpart in the IWAD search.match_namespace = archive->detectNamespace(entries[a]); search.match_name = entries[a]->getName(); other = bra->findLast(search); // If there is one, and it is identical, remove it if (other != nullptr && (other->getMCData().crc() == entries[a]->getMCData().crc())) { ++count; dups += S_FMT("%s\n", search.match_name); archive->removeEntry(entries[a]); entries[a] = nullptr; } } // If no duplicates exist, do nothing if (count == 0) { wxMessageBox("No duplicated entries exist"); return; } string message = S_FMT( "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(); }
/* BaseResourceArchivesPanel::autodetect * Automatically seek IWADs to populate the list *******************************************************************/ void BaseResourceArchivesPanel::autodetect() { // List of known IWADs and common aliases ArchiveEntry * iwadlist = theArchiveManager->programResourceArchive()->entryAtPath("config/iwads.cfg"); if (!iwadlist) return; Parser p; p.parseText(iwadlist->getMCData(), "slade.pk3:config/iwads.cfg"); // Find IWADs from DOOMWADDIR and DOOMWADPATH // See http://doomwiki.org/wiki/Environment_variables string doomwaddir, doomwadpath, envvar; envvar = "DOOMWADDIR"; wxGetEnv(envvar, &doomwaddir); envvar = "DOOMWADPATH"; wxGetEnv(envvar, &doomwadpath); if (doomwaddir.length() || doomwadpath.length()) { #ifdef WIN32 char separator = ';'; doomwadpath.Replace("\\", "/", true); doomwaddir.Replace("\\", "/", true); #else char separator = ':'; #endif wxArrayString paths = wxSplit(doomwadpath, separator); paths.Add(doomwaddir); wxArrayString iwadnames; ParseTreeNode* list = (ParseTreeNode*)p.parseTreeRoot()->getChild("iwads"); for (size_t i = 0; i < list->nChildren(); ++i) iwadnames.Add(list->getChild(i)->getName()); // Look for every known IWAD in every known IWAD directory for (size_t i = 0; i < paths.size(); ++i) { string folder = paths[i]; if (folder.Last() != '/') folder += '/'; for (size_t j = 0; j < iwadnames.size(); ++j) { string iwad = folder + iwadnames[j]; #ifndef WIN32 // Try a couple variants before throwing the towel about a name if (!wxFileExists(iwad)) iwad = folder + iwadnames[j].Capitalize(); if (!wxFileExists(iwad)) iwad = folder + iwadnames[j].Upper(); #endif // If a valid combo is found, add it to the list unless already present if (wxFileExists(iwad)) { // Verify existence before adding it to the list if (list_base_archive_paths->FindString(iwad) == wxNOT_FOUND) { theArchiveManager->addBaseResourcePath(iwad); list_base_archive_paths->Append(iwad); } } } } } // Let's take a look at the registry wxArrayString paths; string path; string gamepath; // Now query GOG.com paths -- Windows only for now #ifdef __WXMSW__ #ifdef _WIN64 string gogregistrypath = "Software\\Wow6432Node\\GOG.com"; #else // If a 32-bit ZDoom runs on a 64-bit Windows, this will be transparently and // automatically redirected to the Wow6432Node address instead, so this address // should be safe to use in all cases. string gogregistrypath = "Software\\GOG.com"; #endif if (QueryPathKey(wxRegKey::HKLM, gogregistrypath, "DefaultPackPath", path)) { ParseTreeNode* list = (ParseTreeNode*)p.parseTreeRoot()->getChild("gog"); for (size_t i = 0; i < list->nChildren(); ++i) { ParseTreeNode* child = (ParseTreeNode*)list->getChild(i); gamepath = gogregistrypath + ((ParseTreeNode*)child->getChild("id"))->getStringValue(); if (QueryPathKey(wxRegKey::HKLM, gamepath, "Path", path)) paths.Add(path + ((ParseTreeNode*)child->getChild("path"))->getStringValue()); } } #endif // Now query Steam paths -- Windows only for now as well #ifdef __WXMSW__ if (QueryPathKey(wxRegKey::HKCU, "Software\\Valve\\Steam", "SteamPath", gamepath) || QueryPathKey(wxRegKey::HKLM, "Software\\Valve\\Steam", "InstallPath", gamepath)) { gamepath += "/SteamApps/common/"; ParseTreeNode* list = (ParseTreeNode*)p.parseTreeRoot()->getChild("steam"); for (size_t i = 0; i < list->nChildren(); ++i) paths.Add(gamepath + ((ParseTreeNode*)list->getChild(i))->getStringValue()); } #else // TODO: Querying Steam registry on Linux and OSX. This involves parsing Steam's config.vdf file, which is found in // FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &folder) + "/Steam/config/config.vdf" on OSX // and in ~home/.local/share/Steam/config/config.vdf on Linux/BSD systems. There's also default install dirs in // appSupportPath + "/Steam/SteamApps/common" for OSX, ~home/.local/share/Steam/SteamApps/common for Linux/BSD. #endif // Add GOG & Steam paths for (size_t i = 0; i < paths.size(); ++i) { string iwad = paths[i]; iwad.Replace("\\", "/", true); if (wxFileExists(iwad)) { // Verify existence before adding it to the list if (list_base_archive_paths->FindString(iwad) == wxNOT_FOUND) { theArchiveManager->addBaseResourcePath(iwad); list_base_archive_paths->Append(iwad); } } } }
/* 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; }