Esempio n. 1
0
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();
}
Esempio n. 2
0
/* 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);
	}
}
Esempio n. 3
0
/* 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;
}
Esempio n. 4
0
/* 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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
/* 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;
}
Esempio n. 7
0
/* 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();
}
Esempio n. 8
0
/* 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;
}
Esempio n. 9
0
// -----------------------------------------------------------------------------
// 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();
}
Esempio n. 10
0
/* 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);
			}
		}
	}

}
Esempio n. 11
0
/* 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;
}