Esempio n. 1
0
bool NetDemo::readMessageHeader(netdemo_message_t &type, uint32_t &len, uint32_t &tic) const
{
	len = tic = 0;

	message_header_t msgheader;
	
	size_t cnt = 0;
	cnt += sizeof(msgheader.type) *
		fread(&msgheader.type, sizeof(msgheader.type), 1, demofp);
	cnt += sizeof(msgheader.length) *
		fread(&msgheader.length, sizeof(msgheader.length), 1, demofp);
	cnt += sizeof(msgheader.gametic) *
		fread(&msgheader.gametic, sizeof(msgheader.gametic), 1, demofp);
	
	if (cnt < NetDemo::MESSAGE_HEADER_SIZE)
	{
		return false;
	}

	// convert the values to native byte order
	len = LELONG(msgheader.length);
	tic = LELONG(msgheader.gametic);
	type = static_cast<netdemo_message_t>(msgheader.type);

	return true;
}
Esempio n. 2
0
bool NetDemo::readMapIndex()
{
	fseek(demofp, header.map_index_offset, SEEK_SET);

	for (int i = 0; i < header.map_index_size; i++)
	{
		netdemo_index_entry_t entry;
		
		size_t cnt = 0;
		cnt += sizeof(entry.ticnum) *
			fread(&entry.ticnum, sizeof(entry.ticnum), 1, demofp);
		cnt += sizeof(entry.offset) *
			fread(&entry.offset, sizeof(entry.offset), 1, demofp);
		
		if (cnt < INDEX_ENTRY_SIZE)
			return false;

		// convert from little-endian to native
		entry.ticnum = LELONG(entry.ticnum);	
		entry.offset = LELONG(entry.offset);

		map_index.push_back(entry);
	}

	return true;
}
Esempio n. 3
0
bool NetDemo::writeSnapshotIndex()
{
	fseek(demofp, header.snapshot_index_offset, SEEK_SET);



	for (size_t i = 0; i < snapshot_index.size(); i++)
	{
		netdemo_index_entry_t entry;
		// convert to little-endian
		entry.ticnum = LELONG(snapshot_index[i].ticnum);
		entry.offset = LELONG(snapshot_index[i].offset);
		
		size_t cnt = 0;
		cnt += sizeof(entry.ticnum) *
			fwrite(&entry.ticnum, sizeof(entry.ticnum), 1, demofp);
		cnt += sizeof(entry.offset) *
			fwrite(&entry.offset, sizeof(entry.offset), 1, demofp);
		
		if (cnt < NetDemo::INDEX_ENTRY_SIZE)
			return false;
	}

	return true;
}
Esempio n. 4
0
//
// R_ConvertPatch
//
// Converts a patch that uses post_t posts into a patch that uses tallpost_t.
//
void R_ConvertPatch(patch_t *newpatch, patch_t *rawpatch)
{
	if (!rawpatch || !newpatch)
		return;

	memcpy(newpatch, rawpatch, 8);		// copy the patch header

	unsigned *rawpostofs = (unsigned*)((byte*)rawpatch + 8);
	unsigned *newpostofs = (unsigned*)((byte*)newpatch + 8);

	unsigned curofs = 8 + 4 * rawpatch->width();	// keep track of the column offset

	for (int i = 0; i < rawpatch->width(); i++)
	{
		int abs_offset = 0;
			
		newpostofs[i] = LELONG(curofs);		// write the new offset for this column
		post_t *rawpost = (post_t*)((byte*)rawpatch + LELONG(rawpostofs[i]));
		tallpost_t *newpost = (tallpost_t*)((byte*)newpatch + curofs);

		while (rawpost->topdelta != 0xFF)
		{
			// handle DeePsea tall patches where topdelta is treated as a relative
			// offset instead of an absolute offset
			if (rawpost->topdelta <= abs_offset)
				abs_offset += rawpost->topdelta;
			else
				abs_offset = rawpost->topdelta;
				
			// watch for column overruns
			int length = rawpost->length;
			if (abs_offset + length > rawpatch->height())
				length = rawpatch->height() - abs_offset;

			// copy the pixels in the post
			memcpy(newpost->data(), (byte*)(rawpost) + 3, length);
				
			newpost->topdelta = abs_offset;
			newpost->length = length;

			curofs += newpost->length + 4;
			rawpost = (post_t*)((byte*)rawpost + rawpost->length + 4);
			newpost = newpost->next();
		}

		newpost->writeend();
		curofs += 2;
	}
}
Esempio n. 5
0
bool NetDemo::writeHeader()
{
	strncpy(header.identifier, "ODAD", 4);
	header.version = NETDEMOVER;
	header.compression = 0;
	header.snapshot_spacing = NetDemo::SNAPSHOT_SPACING;

	netdemo_header_t tmpheader;
	memcpy(&tmpheader, &header, sizeof(header));

	// convert from native byte ordering to little-endian
	tmpheader.snapshot_index_size	= LESHORT(tmpheader.snapshot_index_size);
	tmpheader.snapshot_index_offset	= LELONG(tmpheader.snapshot_index_offset);
	tmpheader.map_index_size		= LESHORT(tmpheader.map_index_size);
	tmpheader.map_index_offset		= LELONG(tmpheader.map_index_offset);
	tmpheader.snapshot_spacing		= LESHORT(tmpheader.snapshot_spacing);
	tmpheader.starting_gametic		= LELONG(tmpheader.starting_gametic);
	tmpheader.ending_gametic		= LELONG(tmpheader.ending_gametic);
	
	fseek(demofp, 0, SEEK_SET);
	size_t cnt = 0;
	cnt += sizeof(tmpheader.identifier) *
		fwrite(&tmpheader.identifier, sizeof(tmpheader.identifier), 1, demofp);
	cnt += sizeof(tmpheader.version) *
		fwrite(&tmpheader.version, sizeof(tmpheader.version), 1, demofp);
	cnt += sizeof(tmpheader.compression) *
		fwrite(&tmpheader.compression, sizeof(tmpheader.compression), 1, demofp);
	cnt += sizeof(tmpheader.snapshot_index_size) *
		fwrite(&tmpheader.snapshot_index_size, sizeof(tmpheader.snapshot_index_size), 1, demofp);
	cnt += sizeof(tmpheader.snapshot_index_offset)*
		fwrite(&tmpheader.snapshot_index_offset, sizeof(tmpheader.snapshot_index_offset), 1, demofp);
	cnt += sizeof(tmpheader.map_index_size) *
		fwrite(&tmpheader.map_index_size, sizeof(tmpheader.map_index_size), 1, demofp);
	cnt += sizeof(tmpheader.map_index_offset)*
		fwrite(&tmpheader.map_index_offset, sizeof(tmpheader.map_index_offset), 1, demofp);
	cnt += sizeof(tmpheader.snapshot_spacing) *
		fwrite(&tmpheader.snapshot_spacing, sizeof(tmpheader.snapshot_spacing), 1, demofp);
	cnt += sizeof(tmpheader.starting_gametic) *
		fwrite(&tmpheader.starting_gametic, sizeof(tmpheader.starting_gametic), 1, demofp);
	cnt += sizeof(tmpheader.ending_gametic) *
		fwrite(&tmpheader.ending_gametic, sizeof(tmpheader.ending_gametic), 1, demofp);
	cnt += sizeof(tmpheader.reserved) *
		fwrite(&tmpheader.reserved, sizeof(tmpheader.reserved), 1, demofp);
	
	if (cnt < NetDemo::HEADER_SIZE)
		return false;

	return true;
}
Esempio n. 6
0
int FStringTable::LoadLanguage (DWORD code, bool exactMatch, BYTE *start, BYTE *end)
{
	const DWORD orMask = exactMatch ? 0 : MAKE_ID(0,0,0xff,0);
	int count = 0;

	code |= orMask;

	while (start < end)
	{
		const DWORD langLen = LELONG(*(DWORD *)&start[4]);

		if (((*(DWORD *)start) | orMask) == code)
		{
			start[3] = 1;

			const BYTE *probe = start + 8;

			while (probe < start + langLen)
			{
				int index = probe[0] | (probe[1]<<8);

				if (Strings[index] == NULL)
				{
					Strings[index] = copystring ((const char *)(probe + 2));
					++count;
				}
				probe += 3 + strlen ((const char *)(probe + 2));
			}
		}

		start += langLen + 8;
		start += (4 - (ptrdiff_t)start) & 3;
	}
	return count;
}
Esempio n. 7
0
//
// TextureManager::readPNamesDirectory
//
void TextureManager::readPNamesDirectory()
{
	int lumpnum = W_GetNumForName("PNAMES");
	size_t lumplen = W_LumpLength(lumpnum);

	byte* lumpdata = new byte[lumplen];
	W_ReadLump(lumpnum, lumpdata);

	int num_pname_mappings = LELONG(*((int*)(lumpdata + 0)));
	mPNameLookup = new int[num_pname_mappings];

	for (int i = 0; i < num_pname_mappings; i++)
	{
		const char* lumpname = (const char*)(lumpdata + 4 + 8 * i);
		mPNameLookup[i] = W_CheckNumForName(lumpname);

		// killough 4/17/98:
		// Some wads use sprites as wall patches, so repeat check and
		// look for sprites this time, but only if there were no wall
		// patches found. This is the same as allowing for both, except
		// that wall patches always win over sprites, even when they
		// appear first in a wad. This is a kludgy solution to the wad
		// lump namespace problem.

		if (mPNameLookup[i] == -1)
			mPNameLookup[i] = W_CheckNumForName(lumpname, ns_sprites);
	}

	delete [] lumpdata;
}
Esempio n. 8
0
void FStringTable::DoneLoading (BYTE *start, BYTE *end)
{
	while (start < end)
	{
		start[3] = 0;
		start += LELONG(*(DWORD *)&start[4]) + 8;
		start += (4 - (ptrdiff_t)start) & 3;
	}
}
Esempio n. 9
0
//
// TextureManager::readAnimatedLump
//
// Reads animation definitions from the ANIMATED lump.
//
// Load the table of animation definitions, checking for existence of
// the start and end of each frame. If the start doesn't exist the sequence
// is skipped, if the last doesn't exist, BOOM exits.
//
// Wall/Flat animation sequences, defined by name of first and last frame,
// The full animation sequence is given using all lumps between the start
// and end entry, in the order found in the WAD file.
//
// This routine modified to read its data from a predefined lump or
// PWAD lump called ANIMATED rather than a static table in this module to
// allow wad designers to insert or modify animation sequences.
//
// Lump format is an array of byte packed animdef_t structures, terminated
// by a structure with istexture == -1. The lump can be generated from a
// text source file using SWANTBLS.EXE, distributed with the BOOM utils.
// The standard list of switches and animations is contained in the example
// source text file DEFSWANI.DAT also in the BOOM util distribution.
//
// [RH] Rewritten to support BOOM ANIMATED lump but also make absolutely
// no assumptions about how the compiler packs the animdefs array.
//
void TextureManager::readAnimatedLump()
{
	int lumpnum = W_CheckNumForName("ANIMATED");
	if (lumpnum == -1)
		return;

	size_t lumplen = W_LumpLength(lumpnum);
	if (lumplen == 0)
		return;

	byte* lumpdata = new byte[lumplen];
	W_ReadLump(lumpnum, lumpdata);

	for (byte* ptr = lumpdata; *ptr != 255; ptr += 23)
	{
		anim_t anim;

		Texture::TextureSourceType texture_type = *(ptr + 0) == 1 ?
					Texture::TEX_WALLTEXTURE : Texture::TEX_FLAT;

		const char* startname = (const char*)(ptr + 10);
		const char* endname = (const char*)(ptr + 1);

		texhandle_t start_texhandle =
				texturemanager.getHandle(startname, texture_type);
		texhandle_t end_texhandle =
				texturemanager.getHandle(endname, texture_type);

		if (start_texhandle == TextureManager::NOT_FOUND_TEXTURE_HANDLE ||
			start_texhandle == TextureManager::NO_TEXTURE_HANDLE ||
			end_texhandle == TextureManager::NOT_FOUND_TEXTURE_HANDLE ||
			end_texhandle == TextureManager::NO_TEXTURE_HANDLE)
			continue;

		anim.basepic = start_texhandle;
		anim.numframes = end_texhandle - start_texhandle + 1;

		if (anim.numframes <= 0)
			continue;
		anim.curframe = 0;
			
		int speed = LELONG(*(int*)(ptr + 19));
		anim.countdown = speed - 1;

		for (int i = 0; i < anim.numframes; i++)
		{
			anim.framepic[i] = anim.basepic + i;
			anim.speedmin[i] = anim.speedmax[i] = speed;
		}

		mAnimDefs.push_back(anim);
	}

	delete [] lumpdata;
}
Esempio n. 10
0
bool NetDemo::readHeader()
{
	fseek(demofp, 0, SEEK_SET);
	
	size_t cnt = 0;
	cnt += sizeof(header.identifier) *
		fread(&header.identifier, sizeof(header.identifier), 1, demofp);
	cnt += sizeof(header.version) *
		fread(&header.version, sizeof(header.version), 1, demofp);
	cnt += sizeof(header.compression) *
		fread(&header.compression, sizeof(header.compression), 1, demofp);
	cnt += sizeof(header.snapshot_index_size) *
		fread(&header.snapshot_index_size, sizeof(header.snapshot_index_size), 1, demofp);
	cnt += sizeof(header.snapshot_index_offset)*
		fread(&header.snapshot_index_offset, sizeof(header.snapshot_index_offset), 1, demofp);
	cnt += sizeof(header.map_index_size) *
		fread(&header.map_index_size, sizeof(header.map_index_size), 1, demofp);
	cnt += sizeof(header.map_index_offset)*
		fread(&header.map_index_offset, sizeof(header.map_index_offset), 1, demofp);
	cnt += sizeof(header.snapshot_spacing) *
		fread(&header.snapshot_spacing, sizeof(header.snapshot_spacing), 1, demofp);
	cnt += sizeof(header.starting_gametic) *
		fread(&header.starting_gametic, sizeof(header.starting_gametic), 1, demofp);
	cnt += sizeof(header.ending_gametic) *
		fread(&header.ending_gametic, sizeof(header.ending_gametic), 1, demofp);
	cnt += sizeof(header.reserved) *
		fread(&header.reserved, sizeof(header.reserved), 1, demofp);
	
	if (cnt < NetDemo::HEADER_SIZE)
		return false;

	// convert from little-endian to native byte ordering
	header.snapshot_index_size 		= LESHORT(header.snapshot_index_size);
	header.snapshot_index_offset 	= LELONG(header.snapshot_index_offset);
	header.map_index_size 			= LESHORT(header.map_index_size);
	header.map_index_offset 		= LELONG(header.map_index_offset);
	header.snapshot_spacing 		= LESHORT(header.snapshot_spacing);
	header.starting_gametic 		= LELONG(header.starting_gametic);
	header.ending_gametic			= LELONG(header.ending_gametic);
	
	return true;
}
Esempio n. 11
0
void NetDemo::writeChunk(const byte *data, size_t size, netdemo_message_t type)
{
	message_header_t msgheader;
	memset(&msgheader, 0, sizeof(msgheader));
	
	msgheader.type = static_cast<byte>(type);
	msgheader.length = LELONG((uint32_t)size);
	msgheader.gametic = LELONG(gametic);
	
	size_t cnt = 0;
	cnt += sizeof(msgheader.type) *
		fwrite(&msgheader.type, sizeof(msgheader.type), 1, demofp);
	cnt += sizeof(msgheader.length) *
		fwrite(&msgheader.length, sizeof(msgheader.length), 1, demofp);
	cnt += sizeof(msgheader.gametic) *
		fwrite(&msgheader.gametic, sizeof(msgheader.gametic), 1, demofp);

	cnt += fwrite(data, 1, size, demofp);
	if (cnt < size + NetDemo::MESSAGE_HEADER_SIZE)
	{
		error("Unable to write netdemo message chunk\n");
		return;
	}
}
Esempio n. 12
0
//
// R_DrawPatchIntoTexture
//
// Draws a lump in patch_t format into a Texture at the given offset.
//
static void R_DrawPatchIntoTexture(Texture* texture, const byte* lumpdata, int xoffs, int yoffs)
{
	int texwidth = texture->getWidth();
	int texheight = texture->getHeight();
	int patchwidth = LESHORT(*(short*)(lumpdata + 0));

	const int* colofs = (int*)(lumpdata + 8);

	int x1 = MAX(xoffs, 0);
	int x2 = MIN(xoffs + patchwidth - 1, texwidth - 1);

	for (int x = x1; x <= x2; x++)
	{
		int abstopdelta = 0;

		const byte* post = lumpdata + LELONG(colofs[x - xoffs]);
		while (*post != 0xFF)
		{
			int posttopdelta = *(post + 0);
			int postlength = *(post + 1);

			// handle DeePsea tall patches where topdelta is treated as a relative
			// offset instead of an absolute offset
			if (posttopdelta <= abstopdelta)
				abstopdelta += posttopdelta;
			else
				abstopdelta = posttopdelta;

			int topoffset = yoffs + abstopdelta;
			int y1 = MAX(topoffset, 0);
			int y2 = MIN(topoffset + postlength - 1, texheight - 1);

			if (y1 <= y2)
			{
				byte* dest = texture->getData() + texheight * x + y1;
				const byte* source = post + 3;
				memcpy(dest, source, y2 - y1 + 1);

				// set up the mask
				byte* mask = texture->getMaskData() + texheight * x + y1;
				memset(mask, 1, y2 - y1 + 1);	
			}
			
			post += postlength + 4;
		}
	}
}
Esempio n. 13
0
//
// R_CalculateNewPatchSize
//
// Helper function for converting raw patches that use post_t into patches
// that use tallpost_t. Returns the lump size of the converted patch.
//
size_t R_CalculateNewPatchSize(patch_t *patch, size_t length)
{
	if (!patch)
		return 0;

	// sanity check to see if the postofs array fits in the patch lump
	if (length < patch->width() * sizeof(unsigned int))
		return 0;

	int numposts = 0, numpixels = 0;
	unsigned int *postofs = (unsigned int *)((byte*)patch + 8);

	for (int i = 0; i < patch->width(); i++)
	{
		size_t ofs = LELONG(postofs[i]);

		// check that the offset is valid
		if (ofs >= length)
			return 0;

		post_t *post = (post_t*)((byte*)patch + ofs);

		while (post->topdelta != 0xFF)
		{
			if (ofs + post->length >= length)
				return 0;		// patch is corrupt

			numposts++;
			numpixels += post->length;
			post = (post_t*)((byte*)post + post->length + 4);
		}
	}

	// 8 byte patch header
	// 4 * width bytes for column offset table
	// 4 bytes per post for post header
	// 1 byte per pixel
	// 2 bytes per column for termination
	return 8 + 4 * patch->width() + 4 * numposts + numpixels + 2 * patch->width();
}
Esempio n. 14
0
//
// R_InitTextures
// Initializes the texture list
//	with the textures from the world map.
//
void R_InitTextures (void)
{
	maptexture_t*		mtexture;
	texture_t*			texture;
	mappatch_t* 		mpatch;
	texpatch_t* 		patch;

	int					i;
	int 				j;

	int*				maptex;
	int*				maptex2;
	int*				maptex1;

	int*				patchlookup;

	int 				totalwidth;
	int					nummappatches;
	int 				offset;
	int 				maxoff;
	int 				maxoff2;
	int					numtextures1;
	int					numtextures2;

	int*				directory;

	int					errors = 0;


	// Load the patch names from pnames.lmp.
	{
		char *names = (char *)W_CacheLumpName ("PNAMES", PU_STATIC);
		char *name_p = names+4;

		nummappatches = LELONG ( *((int *)names) );
		patchlookup = new int[nummappatches];

		for (i = 0; i < nummappatches; i++)
		{
			patchlookup[i] = W_CheckNumForName (name_p + i*8);
			if (patchlookup[i] == -1)
			{
				// killough 4/17/98:
				// Some wads use sprites as wall patches, so repeat check and
				// look for sprites this time, but only if there were no wall
				// patches found. This is the same as allowing for both, except
				// that wall patches always win over sprites, even when they
				// appear first in a wad. This is a kludgy solution to the wad
				// lump namespace problem.

				patchlookup[i] = W_CheckNumForName (name_p + i*8, ns_sprites);
			}
		}
		Z_Free (names);
	}

	// Load the map texture definitions from textures.lmp.
	// The data is contained in one or two lumps,
	//	TEXTURE1 for shareware, plus TEXTURE2 for commercial.
	maptex = maptex1 = (int *)W_CacheLumpName ("TEXTURE1", PU_STATIC);
	numtextures1 = LELONG(*maptex);
	maxoff = W_LumpLength (W_GetNumForName ("TEXTURE1"));
	directory = maptex+1;

	if (W_CheckNumForName ("TEXTURE2") != -1)
	{
		maptex2 = (int *)W_CacheLumpName ("TEXTURE2", PU_STATIC);
		numtextures2 = LELONG(*maptex2);
		maxoff2 = W_LumpLength (W_GetNumForName ("TEXTURE2"));
	}
	else
	{
		maptex2 = NULL;
		numtextures2 = 0;
		maxoff2 = 0;
	}

	// denis - fix memory leaks
	for (i = 0; i < numtextures; i++)
	{
		delete[] texturecolumnlump[i];
		delete[] texturecolumnofs[i];
	}

	// denis - fix memory leaks
	delete[] textures;
	delete[] texturecolumnlump;
	delete[] texturecolumnofs;
	delete[] texturecomposite;
	delete[] texturecompositesize;
	delete[] texturewidthmask;
	delete[] textureheight;
	delete[] texturescalex;
	delete[] texturescaley;

	numtextures = numtextures1 + numtextures2;

	textures = new texture_t *[numtextures];
	texturecolumnlump = new short *[numtextures];
	texturecolumnofs = new unsigned int *[numtextures];
	texturecomposite = new byte *[numtextures];
	texturecompositesize = new int[numtextures];
	texturewidthmask = new int[numtextures];
	textureheight = new fixed_t[numtextures];
	texturescalex = new fixed_t[numtextures];
	texturescaley = new fixed_t[numtextures];

	totalwidth = 0;

	for (i = 0; i < numtextures; i++, directory++)
	{
		if (i == numtextures1)
		{
			// Start looking in second texture file.
			maptex = maptex2;
			maxoff = maxoff2;
			directory = maptex+1;
		}

		offset = LELONG(*directory);

		if (offset > maxoff)
			I_FatalError ("R_InitTextures: bad texture directory");

		mtexture = (maptexture_t *) ( (byte *)maptex + offset);

		texture = textures[i] = (texture_t *)
			Z_Malloc (sizeof(texture_t)
					  + sizeof(texpatch_t)*(SAFESHORT(mtexture->patchcount)-1),
					  PU_STATIC, 0);

		texture->width = SAFESHORT(mtexture->width);
		texture->height = SAFESHORT(mtexture->height);
		texture->patchcount = SAFESHORT(mtexture->patchcount);

		strncpy (texture->name, mtexture->name, 9); // denis - todo string limit?
		std::transform(texture->name, texture->name + strlen(texture->name), texture->name, toupper);

		mpatch = &mtexture->patches[0];
		patch = &texture->patches[0];

		for (j=0 ; j<texture->patchcount ; j++, mpatch++, patch++)
		{
			patch->originx = LESHORT(mpatch->originx);
			patch->originy = LESHORT(mpatch->originy);
			patch->patch = patchlookup[LESHORT(mpatch->patch)];
			if (patch->patch == -1)
			{
				Printf (PRINT_HIGH, "R_InitTextures: Missing patch in texture %s\n", texture->name);
				errors++;
			}
		}
		texturecolumnlump[i] = new short[texture->width];
		texturecolumnofs[i] = new unsigned int[texture->width];

		for (j = 1; j*2 <= texture->width; j <<= 1)
			;
		texturewidthmask[i] = j-1;

		textureheight[i] = texture->height << FRACBITS;
			
		// [RH] Special for beta 29: Values of 0 will use the tx/ty cvars
		// to determine scaling instead of defaulting to 8. I will likely
		// remove this once I finish the betas, because by then, users
		// should be able to actually create scaled textures.
		texturescalex[i] = mtexture->scalex ? mtexture->scalex << (FRACBITS - 3) : FRACUNIT;
		texturescaley[i] = mtexture->scaley ? mtexture->scaley << (FRACBITS - 3) : FRACUNIT;

		totalwidth += texture->width;
	}
	delete[] patchlookup;

	Z_Free (maptex1);
	if (maptex2)
		Z_Free (maptex2);

	if (errors)
		I_FatalError ("%d errors in R_InitTextures.", errors);

	// [RH] Setup hash chains. Go from back to front so that if
	//		duplicates are found, the first one gets used instead
	//		of the last (thus mimicing the original behavior
	//		of R_CheckTextureNumForName().
	for (i = 0; i < numtextures; i++)
		textures[i]->index = -1;

	for (i = numtextures - 1; i >= 0; i--)
	{
		j = 0; //W_LumpNameHash (textures[i]->name) % (unsigned) numtextures;
		textures[i]->next = textures[j]->index;
		textures[j]->index = i;
	}

	if (clientside)		// server doesn't need to load patches ever
	{
		// Precalculate whatever possible.
		for (i = 0; i < numtextures; i++)
			R_GenerateLookup (i, &errors);
	}

//	if (errors)
//		I_FatalError ("%d errors encountered during texture generation.", errors);

	// Create translation table for global animation.

	delete[] texturetranslation;

	texturetranslation = new int[numtextures+1];

	for (i = 0; i < numtextures; i++)
		texturetranslation[i] = i;
}
Esempio n. 15
0
//
// W_AddFile
//
// All files are optional, but at least one file must be found
// (PWAD, if all required lumps are present).
// Files with a .wad extension are wadlink files with multiple lumps.
// Other files are single lumps with the base filename for the lump name.
//
// Map reloads are supported through WAD reload so no need for vanilla tilde
// reload hack here
//
std::string W_AddFile(std::string filename)
{
	FILE*			handle;
	filelump_t*		fileinfo;

	FixPathSeparator(filename);

	if ( (handle = fopen(filename.c_str(), "rb")) == NULL)
	{
		Printf(PRINT_HIGH, "couldn't open %s\n", filename.c_str());
		return "";
	}

	Printf(PRINT_HIGH, "adding %s", filename.c_str());

	size_t newlumps;

	wadinfo_t header;
	fread(&header, sizeof(header), 1, handle);
	header.identification = LELONG(header.identification);

	if (header.identification != IWAD_ID && header.identification != PWAD_ID)
	{
		// raw lump file
		std::string lumpname;
		M_ExtractFileBase(filename, lumpname);

		fileinfo = new filelump_t[1];	
		fileinfo->filepos = 0;
		fileinfo->size = M_FileLength(handle);
		std::transform(lumpname.c_str(), lumpname.c_str() + 8, fileinfo->name, toupper);

		newlumps = 1;
		Printf(PRINT_HIGH, " (single lump)\n");
	}
	else
	{
		// WAD file
		header.numlumps = LELONG(header.numlumps);
		header.infotableofs = LELONG(header.infotableofs);
		size_t length = header.numlumps * sizeof(filelump_t);

		if (length > (unsigned)M_FileLength(handle))
		{
			Printf(PRINT_HIGH, "\nbad number of lumps for %s\n", filename.c_str());
			fclose(handle);
			return "";
		}

		fileinfo = new filelump_t[header.numlumps];
		fseek(handle, header.infotableofs, SEEK_SET);
		fread(fileinfo, length, 1, handle);

		// convert from little-endian to target arch and capitalize lump name
		for (int i = 0; i < header.numlumps; i++)
		{
			fileinfo[i].filepos = LELONG(fileinfo[i].filepos);
			fileinfo[i].size = LELONG(fileinfo[i].size);
			std::transform(fileinfo[i].name, fileinfo[i].name + 8, fileinfo[i].name, toupper);
		}

		newlumps = header.numlumps;	
		Printf(PRINT_HIGH, " (%d lumps)\n", header.numlumps);
	}

	W_AddLumps(handle, fileinfo, newlumps, false);

	delete [] fileinfo;

	return W_MD5(filename);
}
Esempio n. 16
0
static void R_GenerateLookup(int texnum, int *const errors)
{
	const texture_t *texture = textures[texnum];

	// Composited texture not created yet.

	short *collump = texturecolumnlump[texnum];

	// killough 4/9/98: keep count of posts in addition to patches.
	// Part of fix for medusa bug for multipatched 2s normals.
	unsigned short *patchcount = new unsigned short[texture->width];
	unsigned short *postcount = new unsigned short[texture->width];

	memset(patchcount, 0, sizeof(unsigned short) * texture->width);	
	memset(postcount, 0, sizeof(unsigned short) * texture->width);	

	const texpatch_t *texpatch = texture->patches;

	for (int i = 0; i < texture->patchcount; i++)
	{
		const int patchnum = texpatch->patch;
		const patch_t *patch = W_CachePatch(patchnum);
		int x1 = texpatch++->originx, x2 = x1 + patch->width(), x = x1;
		const int *cofs = patch->columnofs-x1;

		if (x2 > texture->width)
			x2 = texture->width;
		if (x1 < 0)
			x = 0;
		for (; x < x2; x++)
		{
			// killough 4/9/98: keep a count of the number of posts in column,
			// to fix Medusa bug while allowing for transparent multipatches.

			const tallpost_t *post = (tallpost_t*)((byte*)patch + LELONG(cofs[x]));
	
			// NOTE: this offset will be rewritten later if a composite is generated
			// for this texture (eg, there's more than one patch)	
			texturecolumnofs[texnum][x] = (byte *)post - (byte *)patch;

			patchcount[x]++;
			collump[x] = patchnum;

			while (!post->end())
			{
				postcount[x]++;
				post = post->next();
			}
		}
	}

	// Now count the number of columns that are covered by more than one patch.
	// Fill in the lump / offset, so columns with only a single patch are all done.

	texturecomposite[texnum] = 0;
	int csize = 0;

	// [RH] Always create a composite texture for multipatch textures
	// or tall textures in order to keep things simpler.	
	bool needcomposite = (texture->patchcount > 1 || texture->height > 254);

	// [SL] Check for columns without patches.
	// If a texture has columns without patches, generate a composite for
	// the texture, which will create empty posts and prevent crashes.
	for (int x = 0; x < texture->width && !needcomposite; x++)
	{
		if (patchcount[x] == 0)
			needcomposite = true;
	}

	if (needcomposite)
	{
		int x = texture->width;
		while (--x >= 0)
		{
			// killough 1/25/98, 4/9/98:
			//
			// Fix Medusa bug, by adding room for column header
			// and trailer bytes for each post in merged column.
			// For now, just allocate conservatively 4 bytes
			// per post per patch per column, since we don't
			// yet know how many posts the merged column will
			// require, and it's bounded above by this limit.

			collump[x] = -1;				// mark lump as multipatched

			texturecolumnofs[texnum][x] = csize;

			// 4 header bytes per post + column height + 2 byte terminator
			csize += 4 * postcount[x] + 2 + texture->height;
		}
	}
	
	texturecompositesize[texnum] = csize;
	
	delete [] patchcount;
	delete [] postcount;
}
Esempio n. 17
0
//
// R_GetPatchColumn
//
tallpost_t* R_GetPatchColumn(int lumpnum, int colnum)
{
	patch_t* patch = W_CachePatch(lumpnum, PU_CACHE);
	return (tallpost_t*)((byte*)patch + LELONG(patch->columnofs[colnum]));
}
Esempio n. 18
0
//
// TextureManager::addTextureDirectory
//
// Requires that the PNAMES lump has been read and processed.
//
void TextureManager::addTextureDirectory(const char* lumpname)
{
	//
	// Texture definition.
	// Each texture is composed of one or more patches,
	// with patches being lumps stored in the WAD.
	// The lumps are referenced by number, and patched
	// into the rectangular texture space using origin
	// and possibly other attributes.
	//
	struct mappatch_t
	{
		short	originx;
		short	originy;
		short	patch;
		short	stepdir;
		short	colormap;
	};

	//
	// Texture definition.
	// A DOOM wall texture is a list of patches
	// which are to be combined in a predefined order.
	//
	struct maptexture_t
	{
		char		name[8];
		WORD		masked;				// [RH] Unused
		BYTE		scalex;				// [RH] Scaling (8 is normal)
		BYTE		scaley;				// [RH] Same as above
		short		width;
		short		height;
		byte		columndirectory[4];	// OBSOLETE
		short		patchcount;
		mappatch_t	patches[1];
	};

	int lumpnum = W_CheckNumForName(lumpname);
	if (lumpnum == -1)
	{
		if (iequals("TEXTURE1", lumpname))
			I_Error("R_InitTextures: TEXTURE1 lump not found");
		return;
	}

	size_t lumplen = W_LumpLength(lumpnum);
	if (lumplen == 0)
		return;

	byte* lumpdata = new byte[lumplen];
	W_ReadLump(lumpnum, lumpdata);

	int* texoffs = (int*)(lumpdata + 4);

	// keep track of the number of texture errors
	int errors = 0;

	int count = LELONG(*((int*)(lumpdata + 0)));
	for (int i = 0; i < count; i++)
	{
		maptexture_t* mtexdef = (maptexture_t*)((byte*)lumpdata + LELONG(texoffs[i]));
		
		size_t texdefsize = sizeof(texdef_t) + sizeof(texdefpatch_t) * (SAFESHORT(mtexdef->patchcount) - 1);
		texdef_t* texdef = (texdef_t*)(new byte[texdefsize]); 	

		texdef->width = SAFESHORT(mtexdef->width);
		texdef->height = SAFESHORT(mtexdef->height);
		texdef->patchcount = SAFESHORT(mtexdef->patchcount);
		texdef->scalex = mtexdef->scalex;
		texdef->scaley = mtexdef->scaley;

		char uname[9];
		for (int c = 0; c < 8; c++)
			uname[c] = toupper(mtexdef->name[c]);
		uname[8] = 0;

		mappatch_t* mpatch = &mtexdef->patches[0];
		texdefpatch_t* patch = &texdef->patches[0];

		for (int j = 0; j < texdef->patchcount; j++, mpatch++, patch++)
		{
			patch->originx = LESHORT(mpatch->originx);
			patch->originy = LESHORT(mpatch->originy);
			patch->patch = mPNameLookup[LESHORT(mpatch->patch)];
			if (patch->patch == -1)
			{
				Printf(PRINT_HIGH, "R_InitTextures: Missing patch in texture %s\n", uname);
				errors++;
			}
		}

		mTextureDefinitions.push_back(texdef);
		mTextureNameTranslationMap[uname] = mTextureDefinitions.size() - 1;
	}

	delete [] lumpdata;
}
Esempio n. 19
0
void R_GenerateComposite (int texnum)
{
	byte *block = (byte *)Z_Malloc (texturecompositesize[texnum], PU_STATIC,
						   (void **) &texturecomposite[texnum]);
	texture_t *texture = textures[texnum];

	// Composite the columns together.
	texpatch_t *texpatch = texture->patches;
	short *collump = texturecolumnlump[texnum];

	// killough 4/9/98: marks to identify transparent regions in merged textures
	byte *marks = new byte[texture->width * texture->height];
	memset(marks, 0, texture->width * texture->height);

	for (int i = texture->patchcount; --i >=0; texpatch++)
	{
		patch_t *patch = W_CachePatch(texpatch->patch);
		int x1 = texpatch->originx, x2 = x1 + patch->width();
		const int *cofs = patch->columnofs-x1;
		if (x1<0)
			x1 = 0;
		if (x2 > texture->width)
			x2 = texture->width;

		for (; x1 < x2 ; x1++)
		{
			if (collump[x1] == -1)			// Column has multiple patches?
			{
				// killough 1/25/98, 4/9/98: Fix medusa bug.
				tallpost_t *srcpost = (tallpost_t*)((byte*)patch + LELONG(cofs[x1]));
				tallpost_t *destpost = (tallpost_t*)(block + texturecolumnofs[texnum][x1]);

				R_DrawColumnInCache(srcpost, destpost->data(), texpatch->originy, texture->height,
									marks + x1 * texture->height);
			}
		}
	}

	// killough 4/9/98: Next, convert multipatched columns into true columns,
	// to fix Medusa bug while still allowing for transparent regions.

	byte *tmpdata = new byte[texture->height];		// temporary post data
	for (int i = 0; i < texture->width; i++)
	{
		if (collump[i] != -1)	// process only multipatched columns
			continue;

		tallpost_t *post = (tallpost_t *)(block + texturecolumnofs[texnum][i]);
		const byte *mark = marks + i * texture->height;
		int j = 0;

		// save column in temporary so we can shuffle it around
		memcpy(tmpdata, post->data(), texture->height);

		// reconstruct the column by scanning transparency marks
		while (true)
		{
			while (j < texture->height && !mark[j]) // skip transparent pixels
				j++;
			if (j >= texture->height) 				// if at end of column
			{
				post->writeend();					// end-of-column marker
				break;
			}

			post->topdelta = j;						// starting offset of post

			// count opaque pixels
			for (post->length = 0; j < texture->height && mark[j]; j++)
				post->length++;

			// copy opaque pixels from the temporary back into the column
			memcpy(post->data(), tmpdata + post->topdelta, post->length);	
			post = post->next();
		}
	}

	delete [] marks;
	delete [] tmpdata;

	// Now that the texture has been built in column cache,
	// it is purgable from zone memory.

	Z_ChangeTag(block, PU_CACHE);
}
Esempio n. 20
0
std::string W_AddFile (std::string filename)
{
    wadinfo_t		header;
    lumpinfo_t*		lump_p;
    size_t			i;
    FILE			*handle;
    size_t			length;
    size_t			startlump;
    size_t          res;
    filelump_t*		fileinfo;
    filelump_t		singleinfo;

    FixPathSeparator (filename);
    std::string name = filename;
    M_AppendExtension (name, ".wad");

    // open the file
    if ( (handle = fopen (filename.c_str(), "rb")) == NULL)
    {
        Printf (PRINT_HIGH, " couldn't open %s\n", filename.c_str());
        return "";
    }

    Printf (PRINT_HIGH, "adding %s\n", filename.c_str());

    startlump = numlumps;

    res = fread (&header, sizeof(header), 1, handle);
    header.identification = LELONG(header.identification);

    if (header.identification != IWAD_ID && header.identification != PWAD_ID)
    {
        // raw lump file
        fileinfo = &singleinfo;
        singleinfo.filepos = 0;
        singleinfo.size = M_FileLength(handle);
        M_ExtractFileBase (filename, name);
        numlumps++;
        Printf (PRINT_HIGH, " (single lump)\n", header.numlumps);
    }
    else
    {
        // WAD file
        header.numlumps = LELONG(header.numlumps);
        header.infotableofs = LELONG(header.infotableofs);
        length = header.numlumps*sizeof(filelump_t);

        if(length > (unsigned)M_FileLength(handle))
        {
            Printf (PRINT_HIGH, " bad number of lumps for %s\n", filename.c_str());
            fclose(handle);
            return "";
        }

        fileinfo = (filelump_t *)Z_Malloc (length, PU_STATIC, 0);
        fseek (handle, header.infotableofs, SEEK_SET);
        res = fread (fileinfo, length, 1, handle);
        numlumps += header.numlumps;
        Printf (PRINT_HIGH, " (%d lumps)\n", header.numlumps);
    }

    // Fill in lumpinfo
    lumpinfo = (lumpinfo_t *)Realloc (lumpinfo, numlumps*sizeof(lumpinfo_t));

    if (!lumpinfo)
        I_Error ("Couldn't realloc lumpinfo");

    lump_p = &lumpinfo[startlump];

    for (i=startlump ; i<numlumps ; i++,lump_p++, fileinfo++)
    {
        lump_p->handle = handle;
        lump_p->position = LELONG(fileinfo->filepos);
        lump_p->size = LELONG(fileinfo->size);
        strncpy (lump_p->name, fileinfo->name, 8);

        // W_CheckNumForName needs all lump names in upper case
        std::transform(lump_p->name, lump_p->name+8, lump_p->name, toupper);
    }

    return W_MD5(filename);
}
Esempio n. 21
0
void FStringTable::LoadStrings (int lump, int expectedSize, bool enuOnly)
{
	BYTE *strData = (BYTE *)W_CacheLumpNum (lump, PU_CACHE);
	int lumpLen = LELONG(((Header *)strData)->FileSize);
	int nameCount = LESHORT(((Header *)strData)->NameCount);
	int nameLen = LESHORT(((Header *)strData)->NameLen);

	int languageStart = sizeof(Header) + nameCount*4 + nameLen;
	languageStart += (4 - languageStart) & 3;

	if (expectedSize >= 0 && nameCount != expectedSize)
	{
		char name[9];

		W_GetLumpName (name, lump);
		name[8] = 0;
		I_FatalError ("%s had %d strings.\nThis version of ZDoom expects it to have %d.",
			name, nameCount, expectedSize);
	}

	FreeStandardStrings ();

	NumStrings = nameCount;
	LumpNum = lump;
	if (Strings == NULL)
	{
		Strings = new char *[nameCount];
		StringStatus = new BYTE[(nameCount+7)/8];
		memset (StringStatus, 0, (nameCount+7)/8);	// 0 means: from wad (standard)
		memset (Strings, 0, sizeof(char *)*nameCount);
	}

	BYTE *const start = strData + languageStart;
	BYTE *const end = strData + lumpLen;
	int loadedCount, i;

	for (loadedCount = i = 0; i < NumStrings; ++i)
	{
		if (Strings[i] != NULL)
		{
			++loadedCount;
		}
	}

	if (!enuOnly)
	{
		for (i = 0; i < 4 && loadedCount != nameCount; ++i)
		{
			loadedCount += LoadLanguage (LanguageIDs[i], true, start, end);
			loadedCount += LoadLanguage (LanguageIDs[i] & MAKE_ID(0xff,0xff,0,0), true, start, end);
			loadedCount += LoadLanguage (LanguageIDs[i], false, start, end);
		}
	}

	// Fill in any missing strings with the default language (enu)
	if (loadedCount != nameCount)
	{
		loadedCount += LoadLanguage (MAKE_ID('e','n','u',0), true, start, end);
	}

	DoneLoading (start, end);

	if (loadedCount != nameCount)
	{
		I_FatalError ("Loaded %d strings (expected %d)", loadedCount, nameCount);
	}
}
Esempio n. 22
0
void R_GenerateComposite (int texnum)
{
	byte *block = (byte *)Z_Malloc (texturecompositesize[texnum], PU_STATIC,
						   (void **) &texturecomposite[texnum]);
	texture_t *texture = textures[texnum];
	// Composite the columns together.
	texpatch_t *patch = texture->patches;
	short *collump = texturecolumnlump[texnum];
	unsigned *colofs = texturecolumnofs[texnum]; // killough 4/9/98: make 32-bit
	int i = texture->patchcount;
	// killough 4/9/98: marks to identify transparent regions in merged textures
	byte *marks = (byte *)Calloc (texture->width, texture->height), *source;

	for (; --i >=0; patch++)
	{
		patch_t *realpatch = W_CachePatch (patch->patch);
		int x1 = patch->originx, x2 = x1 + realpatch->width();
		const int *cofs = realpatch->columnofs-x1;
		if (x1<0)
			x1 = 0;
		if (x2 > texture->width)
			x2 = texture->width;
		for (; x1<x2 ; x1++)
			if (collump[x1] == -1)			// Column has multiple patches?
				// killough 1/25/98, 4/9/98: Fix medusa bug.
				R_DrawColumnInCache((column_t*)((byte*)realpatch+LELONG(cofs[x1])),
									block+colofs[x1],patch->originy,texture->height,
									marks + x1 * texture->height);
	}

	// killough 4/9/98: Next, convert multipatched columns into true columns,
	// to fix Medusa bug while still allowing for transparent regions.

	source = (byte *)Malloc (texture->height); 		// temporary column
	for (i=0; i < texture->width; i++)
		if (collump[i] == -1) 				// process only multipatched columns
		{
			column_t *col = (column_t *)(block + colofs[i] - 3);	// cached column
			const byte *mark = marks + i * texture->height;
			int j = 0;

			// save column in temporary so we can shuffle it around
			memcpy(source, (byte *) col + 3, texture->height);

			for (;;)	// reconstruct the column by scanning transparency marks
			{
				while (j < texture->height && !mark[j]) // skip transparent cells
					j++;
				if (j >= texture->height) 				// if at end of column
				{
					col->topdelta = 255; 				// end-of-column marker
					break;
				}
				col->topdelta = j;						// starting offset of post
				for (col->length=0; j < texture->height && mark[j]; j++)
					col->length++;						// count opaque cells
				// copy opaque cells from the temporary back into the column
				memcpy((byte *) col + 3, source + col->topdelta, col->length);
				col = (column_t *)((byte *) col + col->length + 4); // next post
			}
		}
	M_Free(source); 				// free temporary column
	M_Free(marks);				// free transparency marks

	// Now that the texture has been built in column cache,
	// it is purgable from zone memory.

	Z_ChangeTag(block, PU_CACHE);
}
Esempio n. 23
0
static void R_GenerateLookup(int texnum, int *const errors)
{
	const texture_t *texture = textures[texnum];

	// Composited texture not created yet.

	short *collump = texturecolumnlump[texnum];
	unsigned *colofs = texturecolumnofs[texnum]; // killough 4/9/98: make 32-bit

	// killough 4/9/98: keep count of posts in addition to patches.
	// Part of fix for medusa bug for multipatched 2s normals.

	struct cs {
		unsigned short patches, posts;
	} *count = (cs *)Calloc (sizeof *count, texture->width);

	int i = texture->patchcount;
	const texpatch_t *patch = texture->patches;

	// [RH] Some wads (I forget which!) have single-patch textures 256
	// pixels tall that have patch lengths recorded as 0. I can't think of
	// any good reason for them to do this, and since I didn't make note
	// of which wad made me hack in support for them, the hack is gone
	// because I've added support for DeePsea's real tall patches.
	while (--i >= 0)
	{
		int pat = patch->patch;
		const patch_t *realpatch = W_CachePatch (pat);
		int x1 = patch++->originx, x2 = x1 + realpatch->width(), x = x1;
		const int *cofs = realpatch->columnofs-x1;

		if (x2 > texture->width)
			x2 = texture->width;
		if (x1 < 0)
			x = 0;
		for (; x < x2; x++)
		{
			// killough 4/9/98: keep a count of the number of posts in column,
			// to fix Medusa bug while allowing for transparent multipatches.

			const column_t *col = (column_t*)((byte*)realpatch + LELONG(cofs[x]));
			for (;col->topdelta != 0xff; count[x].posts++)
			{
				col = (column_t *)((byte *)col + col->length + 4);
				
				// denis - prevent a crash when col goes out of range
				unsigned int n = (const byte *)col - (const byte *)realpatch;
				if (n >= W_LumpLength(pat))
				{
					if (texture->height < 256) // bigger textures are assumed to have a single post anyway
						Printf(PRINT_HIGH, "R_GenerateLookup warning: post truncated for texture %d\n", texnum);

					count[x].posts--;
					break;
				}				
				
			}
			count[x].patches++;
			collump[x] = pat;
			colofs[x] = LELONG(cofs[x])+3;
		}
	}

	// Now count the number of columns
	//	that are covered by more than one patch.
	// Fill in the lump / offset, so columns
	//	with only a single patch are all done.

	texturecomposite[texnum] = 0;

	int x = texture->width;
	int height = texture->height;
	int csize = 0;

	bool multipatch = (texture->patchcount > 1 || texture->height > 254);

	// [SL] Check for columns without patches - these should be handled as
	// multi-patched textures so we can fill in the empty columns with
	// masked columns
	while (--x >= 0 && !multipatch)
	{
		if (!count[x].patches)
			multipatch = true;
	}

	if (multipatch)
	{
		// [RH] Always create a composite texture for multipatch textures
		// or tall textures in order to keep things simpler.	
		texturetype2[texnum] = 1;
		x = texture->width;
		csize = 0;
		while (--x >= 0)
		{
			// killough 1/25/98, 4/9/98:
			//
			// Fix Medusa bug, by adding room for column header
			// and trailer bytes for each post in merged column.
			// For now, just allocate conservatively 4 bytes
			// per post per patch per column, since we don't
			// yet know how many posts the merged column will
			// require, and it's bounded above by this limit.

			collump[x] = -1;				// mark lump as multipatched
			colofs[x] = csize + 4;			// four header bytes in a column
			csize += 4*count[x].posts+2+height;	// 2 stop bytes plus 4 bytes per post
		}
	}
	else
	{
		texturetype2[texnum] = 0;	
		csize = x*height;
	}
	
	texturecompositesize[texnum] = csize;

	M_Free(count);								// killough 4/9/98
}
Esempio n. 24
0
//
// CheckIWAD
//
// Tries to find an IWAD from a set of know IWAD names, and checks the first
// one found's contents to determine whether registered/commercial features
// should be executed (notably loading PWAD's).
//
static bool CheckIWAD (std::string suggestion, std::string &titlestring)
{
    static const char *doomwadnames[] =
    {
        "doom2f.wad",
        "doom2.wad",
        "plutonia.wad",
        "tnt.wad",
        "doomu.wad", // Hack from original Linux version. Not necessary, but I threw it in anyway.
        "doom.wad",
        "doom1.wad",
        "freedoom.wad",
        "freedm.wad",
        "chex.wad",		// [ML] 1/7/10: Hello Chex Quest!
        NULL
    };

    std::string iwad;
    std::string iwad_file;
    int i;

    if(suggestion.length())
    {
        std::string found = BaseFileSearch(suggestion, ".WAD");

        if(found.length())
            iwad = found;
        else
        {
            if(M_FileExists(suggestion.c_str()))
                iwad = suggestion;
        }
        /*	[ML] Removed 1/13/10: we can trust the user to provide an iwad
        if(iwad.length())
        {
        	FILE *f;

        	if ( (f = fopen (iwad.c_str(), "rb")) )
        	{
        		wadinfo_t header;
        		fread (&header, sizeof(header), 1, f);
        		header.identification = LELONG(header.identification);
        		if (header.identification != IWAD_ID)
        		{
        			if(header.identification == PWAD_ID)
        			{
        				Printf(PRINT_HIGH, "Suggested file is a PWAD, not an IWAD: %s \n", iwad.c_str());
        			}
        			else
        			{
        				Printf(PRINT_HIGH, "Suggested file is not an IWAD: %s \n", iwad.c_str());
        			}
        			iwad = "";
        		}
        		fclose(f);
        	}
        }
        */
    }

    if(!iwad.length())
    {
        // Search for a pre-defined IWAD from the list above
        for (i = 0; doomwadnames[i]; i++)
        {
            std::string found = BaseFileSearch(doomwadnames[i]);

            if(found.length())
            {
                iwad = found;
                break;
            }
        }
    }

    // Now scan the contents of the IWAD to determine which one it is
    if (iwad.length())
    {
#define NUM_CHECKLUMPS 9
        static const char checklumps[NUM_CHECKLUMPS][8] = {
            "E1M1", "E2M1", "E4M1", "MAP01",
            { 'A','N','I','M','D','E','F','S'},
            "FINAL2", "REDTNT2", "CAMO1",
            { 'E','X','T','E','N','D','E','D'}
        };
        int lumpsfound[NUM_CHECKLUMPS];
        wadinfo_t header;
        FILE *f;
        M_ExtractFileName(iwad,iwad_file);

        memset (lumpsfound, 0, sizeof(lumpsfound));
        if ( (f = fopen (iwad.c_str(), "rb")) )
        {
            size_t res = fread (&header, sizeof(header), 1, f);
            header.identification = LELONG(header.identification);
            if (header.identification == IWAD_ID ||
                    header.identification == PWAD_ID)
            {
                header.numlumps = LELONG(header.numlumps);
                if (0 == fseek (f, LELONG(header.infotableofs), SEEK_SET))
                {
                    for (i = 0; i < header.numlumps; i++)
                    {
                        filelump_t lump;
                        int j;

                        if (0 == fread (&lump, sizeof(lump), 1, f))
                            break;
                        for (j = 0; j < NUM_CHECKLUMPS; j++)
                            if (!strnicmp (lump.name, checklumps[j], 8))
                                lumpsfound[j]++;
                    }
                }
            }
            fclose (f);
        }

        gamemode = undetermined;

        if (lumpsfound[3])
        {
            gamemode = commercial;
            gameinfo = CommercialGameInfo;
            if (lumpsfound[6])
            {
                gamemission = pack_tnt;
                titlestring = "DOOM 2: TNT - Evilution";
            }
            else if (lumpsfound[7])
            {
                gamemission = pack_plut;
                titlestring = "DOOM 2: Plutonia Experiment";
            }
            else
            {
                gamemission = doom2;
                titlestring = "DOOM 2: Hell on Earth";
            }
        }
        else if (lumpsfound[0])
        {
            gamemission = doom;
            if (lumpsfound[1])
            {
                if (lumpsfound[2])
                {
                    if (!StdStringCompare(iwad_file,"chex.wad",true))	// [ML] 1/7/10: HACK - There's no unique lumps in the chex quest
                    {   // iwad.  It's ultimate doom with their stuff replacing most things.
                        gamemission = chex;
                        gamemode = retail_chex;
                        gameinfo = RetailGameInfo;
                        titlestring = "Chex Quest";
                    }
                    else
                    {
                        gamemode = retail;
                        gameinfo = RetailGameInfo;
                        titlestring = "The Ultimate DOOM";
                    }
                }
                else
                {
                    gamemode = registered;
                    gameinfo = RegisteredGameInfo;
                    titlestring = "DOOM Registered";
                }
            }
            else
            {
                gamemode = shareware;
                gameinfo = SharewareGameInfo;
                titlestring = "DOOM Shareware";
            }
        }
    }

    if (gamemode == undetermined)
    {
        gameinfo = SharewareGameInfo;
    }
    if (iwad.length())
        wadfiles.push_back(iwad);
    else
        I_Error("Cannot find IWAD (try -waddir)");

    return iwad.length() ? true : false;
}