/* CTexture::parseDefine * Parses a HIRESTEX define block *******************************************************************/ bool CTexture::parseDefine(Tokenizer& tz) { this->type = "Define"; this->extended = true; this->defined = true; name = tz.getToken().Upper(); def_width = tz.getInteger(); def_height = tz.getInteger(); width = def_width; height = def_height; ArchiveEntry* entry = theResourceManager->getPatchEntry(name); if (entry) { SImage image; if (image.open(entry->getMCData())) { width = image.getWidth(); height = image.getHeight(); scale_x = (double)width / (double)def_width; scale_y = (double)height / (double)def_height; } } CTPatchEx* patch = new CTPatchEx(name); patches.push_back(patch); return true; }
/* Translation::parse * Parses a text definition [def] (in zdoom format, detailed here: * http://zdoom.org/wiki/Translation) *******************************************************************/ void Translation::parse(string def) { // Open definition string for processing w/tokenizer Tokenizer tz; tz.setSpecialCharacters("[]:%,="); tz.openString(def); //wxLogMessage("Parse translation \"%s\"", CHR(def)); // Read original range uint8_t o_start, o_end; o_start = tz.getInteger(); if (tz.peekToken() == "=") o_end = o_start; else if (!tz.checkToken(":")) return; else o_end = tz.getInteger(); if (!tz.checkToken("=")) return; // Check for reverse origin range bool reverse = (o_start > o_end); // Type of translation depends on next token if (tz.peekToken() == "[") { // Colour translation rgba_t start, end; tz.getToken(); // Skip [ // Read start colour start.r = tz.getInteger(); if (!tz.checkToken(",")) return; start.g = tz.getInteger(); if (!tz.checkToken(",")) return; start.b = tz.getInteger(); if (!tz.checkToken("]")) return; if (!tz.checkToken(":")) return; if (!tz.checkToken("[")) return; // Read end colour end.r = tz.getInteger(); if (!tz.checkToken(",")) return; end.g = tz.getInteger(); if (!tz.checkToken(",")) return; end.b = tz.getInteger(); if (!tz.checkToken("]")) return; // Add translation TransRangeColour* tr = new TransRangeColour(); if (reverse) { tr->o_start = o_end; tr->o_end = o_start; tr->d_start.set(end); tr->d_end.set(start); } else { tr->o_start = o_start; tr->o_end = o_end; tr->d_start.set(start); tr->d_end.set(end); } translations.push_back(tr); //wxLogMessage("Added colour translation"); } else if (tz.peekToken() == "%") { // Desat colour translation float sr, sg, sb, er, eg, eb; tz.getToken(); // Skip % if (!tz.checkToken("[")) return; // Read start colour sr = tz.getFloat(); if (!tz.checkToken(",")) return; sg = tz.getFloat(); if (!tz.checkToken(",")) return; sb = tz.getFloat(); if (!tz.checkToken("]")) return; if (!tz.checkToken(":")) return; if (!tz.checkToken("[")) return; // Read end colour er = tz.getFloat(); if (!tz.checkToken(",")) return; eg = tz.getFloat(); if (!tz.checkToken(",")) return; eb = tz.getFloat(); if (!tz.checkToken("]")) return; // Add translation TransRangeDesat* tr = new TransRangeDesat(); if (reverse) { tr->o_start = o_end; tr->o_end = o_start; tr->d_sr = er; tr->d_sg = eg; tr->d_sb = eb; tr->d_er = sr; tr->d_eg = sg; tr->d_eb = sb; } else { tr->o_start = o_start; tr->o_end = o_end; tr->d_sr = sr; tr->d_sg = sg; tr->d_sb = sb; tr->d_er = er; tr->d_eg = eg; tr->d_eb = eb; } translations.push_back(tr); //wxLogMessage("Added desat translation"); } else { // Palette range translation uint8_t d_start, d_end; // Read range values d_start = tz.getInteger(); if (!tz.checkToken(":")) d_end = d_start; else d_end = tz.getInteger(); // Add translation TransRangePalette* tr = new TransRangePalette(); if (reverse) { tr->o_start = o_end; tr->o_end = o_start; tr->d_start = d_end; tr->d_end = d_start; } else { tr->o_start = o_start; tr->o_end = o_end; tr->d_start = d_start; tr->d_end = d_end; } translations.push_back(tr); //wxLogMessage("Added range translation"); } }
/* MainWindow::createStartPage * Builds the HTML start page and loads it into the html viewer * (start page tab) *******************************************************************/ void MainWindow::createStartPage() { // Get relevant resource entries Archive* res_archive = theArchiveManager->programResourceArchive(); if (!res_archive) return; ArchiveEntry* entry_html = res_archive->entryAtPath("html/startpage.htm"); ArchiveEntry* entry_logo = res_archive->entryAtPath("logo.png"); ArchiveEntry* entry_tips = res_archive->entryAtPath("tips.txt"); // Can't do anything without html entry if (!entry_html) { html_startpage->SetPage("<html><head><title>SLADE</title></head><body><center><h1>Something is wrong with slade.pk3 :(</h1><center></body></html>"); return; } // Get html as string string html = wxString::FromAscii((const char*)(entry_html->getData()), entry_html->getSize()); // Generate tip of the day string string tip = "It seems tips.txt is missing from your slade.pk3"; if (entry_tips) { Tokenizer tz; tz.openMem((const char*)entry_tips->getData(), entry_tips->getSize(), entry_tips->getName()); srand(wxGetLocalTime()); int numtips = tz.getInteger(); if (numtips < 2) // Needs at least two choices or it's kinda pointless. tip = "Did you know? Something is wrong with the tips.txt file in your slade.pk3."; else { int tipindex = 0; // Don't show same tip twice in a row do { tipindex = 1 + (rand() % numtips); } while (tipindex == lasttipindex); lasttipindex = tipindex; for (int a = 0; a < tipindex; a++) tip = tz.getToken(); } } // Generate recent files string string recent; for (unsigned a = 0; a < 4; a++) { if (a >= theArchiveManager->numRecentFiles()) break; // No more recent files // Add line break if needed if (a > 0) recent += "<br/>\n"; // Add recent file link recent += S_FMT("<a href=\"recent://%d\">%s</a>", a, theArchiveManager->recentFile(a)); } // Insert tip and recent files into html html.Replace("#recent#", recent); html.Replace("#totd#", tip); // Write html and images to temp folder if (entry_logo) entry_logo->exportFile(appPath("logo.png", DIR_TEMP)); string html_file = appPath("startpage.htm", DIR_TEMP); wxFile outfile(html_file, wxFile::write); outfile.Write(html); outfile.Close(); // Load page html_startpage->LoadPage(html_file); // Clean up wxRemoveFile(html_file); wxRemoveFile(appPath("logo.png", DIR_TEMP)); }
/* MainWindow::createStartPage * Builds the HTML start page and loads it into the html viewer * (start page tab) *******************************************************************/ void MainWindow::createStartPage(bool newtip) { // Get relevant resource entries Archive* res_archive = theArchiveManager->programResourceArchive(); if (!res_archive) return; // Get entries to export vector<ArchiveEntry*> export_entries; ArchiveEntry* entry_html = res_archive->entryAtPath("html/startpage.htm"); ArchiveEntry* entry_tips = res_archive->entryAtPath("tips.txt"); export_entries.push_back(res_archive->entryAtPath("logo.png")); export_entries.push_back(res_archive->entryAtPath("html/box-title-back.png")); //export_entries.push_back(res_archive->entryAtPath("icons/e_archive.png")); //export_entries.push_back(res_archive->entryAtPath("icons/e_wad.png")); //export_entries.push_back(res_archive->entryAtPath("icons/e_zip.png")); //export_entries.push_back(res_archive->entryAtPath("icons/e_folder.png")); // Can't do anything without html entry if (!entry_html) { LOG_MESSAGE(1, "No start page resource found"); html_startpage->SetPage("<html><head><title>SLADE</title></head><body><center><h1>Something is wrong with slade.pk3 :(</h1><center></body></html>", wxEmptyString); return; } // Get html as string string html = wxString::FromAscii((const char*)(entry_html->getData()), entry_html->getSize()); // Generate tip of the day string string tip = "It seems tips.txt is missing from your slade.pk3"; if (entry_tips) { Tokenizer tz; tz.openMem((const char*)entry_tips->getData(), entry_tips->getSize(), entry_tips->getName()); srand(wxGetLocalTime()); int numtips = tz.getInteger(); if (numtips < 2) // Needs at least two choices or it's kinda pointless. tip = "Did you know? Something is wrong with the tips.txt file in your slade.pk3."; else { int tipindex = 0; if (newtip || lasttipindex == 0) { // Don't show same tip twice in a row do { tipindex = 1 + (rand() % numtips); } while (tipindex == lasttipindex); } else tipindex = lasttipindex; lasttipindex = tipindex; for (int a = 0; a < tipindex; a++) tip = tz.getToken(); } } // Generate recent files string string recent; recent += "<table class=\"box\">"; if (theArchiveManager->numRecentFiles() > 0) { for (unsigned a = 0; a < 12; a++) { if (a >= theArchiveManager->numRecentFiles()) break; // No more recent files recent += "<tr><td valign=\"middle\" class=\"box\">"; // Determine icon string fn = theArchiveManager->recentFile(a); string icon = "archive"; if (fn.EndsWith(".wad")) icon = "wad"; else if (fn.EndsWith(".zip") || fn.EndsWith(".pk3") || fn.EndsWith(".pke")) icon = "zip"; else if (wxDirExists(fn)) icon = "folder"; // Add recent file link recent += S_FMT("<img src=\"%s.png\"></td><td valign=\"top\" class=\"box\">", icon); recent += S_FMT("<a href=\"recent://%d\">%s</a></td></tr>", a, fn); } } else recent += "<tr><td valign=\"top\" class=\"box\">No recently opened files</td></tr>"; recent += "</table>"; // Insert tip and recent files into html html.Replace("#recent#", recent); html.Replace("#totd#", tip); // Write html and images to temp folder for (unsigned a = 0; a < export_entries.size(); a++) export_entries[a]->exportFile(appPath(export_entries[a]->getName(), DIR_TEMP)); Icons::exportIconPNG(Icons::ENTRY, "archive", appPath("archive.png", DIR_TEMP)); Icons::exportIconPNG(Icons::ENTRY, "wad", appPath("wad.png", DIR_TEMP)); Icons::exportIconPNG(Icons::ENTRY, "zip", appPath("zip.png", DIR_TEMP)); Icons::exportIconPNG(Icons::ENTRY, "folder", appPath("folder.png", DIR_TEMP)); string html_file = appPath("startpage.htm", DIR_TEMP); wxFile outfile(html_file, wxFile::write); outfile.Write(html); outfile.Close(); #ifdef __WXGTK__ html_file = "file://" + html_file; #endif // Load page html_startpage->ClearHistory(); html_startpage->LoadURL(html_file); #ifdef __WXMSW__ html_startpage->Reload(); #endif // Clean up //wxRemoveFile(html_file); //wxRemoveFile(appPath("logo.png", DIR_TEMP)); }
/* 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; }
/* CTexture::parse * Parses a TEXTURES format texture definition *******************************************************************/ bool CTexture::parse(Tokenizer& tz, string type) { // Check if optional if (S_CMPNOCASE(tz.peekToken(), "optional")) { tz.getToken(); // Skip it optional = true; } // Read basic info this->type = type; this->extended = true; this->defined = false; name = tz.getToken().Upper(); tz.getToken(); // Skip , width = tz.getInteger(); tz.getToken(); // Skip , height = tz.getInteger(); // Check for extended info if (tz.peekToken() == "{") { tz.getToken(); // Skip { // Read properties string property = tz.getToken(); while (property != "}") { // Check if end of text is reached (error) if (property.IsEmpty()) { wxLogMessage("Error parsing texture %s: End of text found, missing } perhaps?", name); return false; } // XScale if (S_CMPNOCASE(property, "XScale")) scale_x = tz.getFloat(); // YScale if (S_CMPNOCASE(property, "YScale")) scale_y = tz.getFloat(); // Offset if (S_CMPNOCASE(property, "Offset")) { offset_x = tz.getInteger(); tz.getToken(); // Skip , offset_y = tz.getInteger(); } // WorldPanning if (S_CMPNOCASE(property, "WorldPanning")) world_panning = true; // NoDecals if (S_CMPNOCASE(property, "NoDecals")) no_decals = true; // NullTexture if (S_CMPNOCASE(property, "NullTexture")) null_texture = true; // Patch if (S_CMPNOCASE(property, "Patch")) { CTPatchEx* patch = new CTPatchEx(); patch->parse(tz); patches.push_back(patch); } // Graphic if (S_CMPNOCASE(property, "Graphic")) { CTPatchEx* patch = new CTPatchEx(); patch->parse(tz, PTYPE_GRAPHIC); patches.push_back(patch); } // Read next property property = tz.getToken(); } } return true; }
/* CTPatchEx::parse * Parses a ZDoom TEXTURES format patch definition *******************************************************************/ bool CTPatchEx::parse(Tokenizer& tz, uint8_t type) { // Read basic info this->type = type; name = tz.getToken().Upper(); tz.getToken(); // Skip , offset_x = tz.getInteger(); tz.getToken(); // Skip , offset_y = tz.getInteger(); // Check if there is any extended info if (tz.peekToken() == "{") { // Skip { tz.getToken(); // Parse extended info string property = tz.getToken(); while (property != "}") { // FlipX if (S_CMPNOCASE(property, "FlipX")) flip_x = true; // FlipY if (S_CMPNOCASE(property, "FlipY")) flip_y = true; // UseOffsets if (S_CMPNOCASE(property, "UseOffsets")) use_offsets = true; // Rotate if (S_CMPNOCASE(property, "Rotate")) rotation = tz.getInteger(); // Translation if (S_CMPNOCASE(property, "Translation")) { // Add first translation string translation.parse(tz.getToken()); // Add any subsequent translations (separated by commas) while (tz.peekToken() == ",") { tz.getToken(); // Skip , translation.parse(tz.getToken()); } blendtype = 1; } // Blend if (S_CMPNOCASE(property, "Blend")) { double val; wxColour col; blendtype = 2; // Read first value string first = tz.getToken(); // If no second value, it's just a colour string if (tz.peekToken() != ",") { col.Set(first); colour.set(col.Red(), col.Green(), col.Blue()); } else { // Second value could be alpha or green tz.getToken(); // Skip , double second = tz.getDouble(); // If no third value, it's an alpha value if (tz.peekToken() != ",") { col.Set(first); colour.set(col.Red(), col.Green(), col.Blue(), second*255); blendtype = 3; } else { // Third value exists, must be R,G,B,A format tz.getToken(); // Skip , first.ToDouble(&val); colour.r = val*255; colour.g = second*255; colour.b = tz.getDouble()*255; if (tz.peekToken() != ",") { wxLogMessage("Invalid TEXTURES definition, expected ',', got '%s'", tz.getToken()); return false; } tz.getToken(); // Skip , colour.a = tz.getDouble()*255; blendtype = 3; } } } // Alpha if (S_CMPNOCASE(property, "Alpha")) alpha = tz.getFloat(); // Style if (S_CMPNOCASE(property, "Style")) style = tz.getToken(); // Read next property name property = tz.getToken(); } } 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; }