Пример #1
0
//
// TextureManger::cachePatch
//
void TextureManager::cachePatch(texhandle_t handle)
{
	unsigned int lumpnum = handle & ~(PATCH_HANDLE_MASK | SPRITE_HANDLE_MASK);

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

	int width = LESHORT(*(short*)(lumpdata + 0));
	int height = LESHORT(*(short*)(lumpdata + 2));
	int offsetx = LESHORT(*(short*)(lumpdata + 4));
	int offsety = LESHORT(*(short*)(lumpdata + 6));

	Texture* texture = createTexture(handle, width, height);
	texture->mOffsetX = offsetx;
	texture->mOffsetY = offsety;

	if (clientside)
	{
		// TODO: remove this once proper masking is in place
		memset(texture->mData, 0, width * height);

		// initialize the mask to entirely transparent 
		memset(texture->mMask, 0, width * height);

		R_DrawPatchIntoTexture(texture, lumpdata, 0, 0);
		texture->mHasMask = (memchr(texture->mMask, 0, width * height) != NULL);
	}

	delete [] lumpdata;

}
Пример #2
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;
}
Пример #3
0
// Find a string by name
int FStringTable::FindString (const char *name) const
{
	if (Names == NULL)
	{
		LoadNames ();
	}

	const WORD *nameOfs = (WORD *)Names;
	const char *nameBase = (char *)Names + NumStrings*4;

	int min = 0;
	int max = NumStrings-1;

	while (min <= max)
	{
		const int mid = (min + max) / 2;
		const char *const tablename = LESHORT(nameOfs[mid*2]) + nameBase;
		const int lex = stricmp (name, tablename);
		if (lex == 0)
			return nameOfs[mid*2+1];
		else if (lex < 0)
			max = mid - 1;
		else
			min = mid + 1;
	}
	return -1;
}
Пример #4
0
void FStringTable::LoadNames () const
{
	BYTE *lump = (BYTE *)W_CacheLumpNum (LumpNum, PU_CACHE);
	int nameLen = LESHORT(((Header *)lump)->NameLen);

	FlushNames ();
	Names = new BYTE[nameLen + 4*NumStrings];
	memcpy (Names, lump + sizeof(Header), nameLen + 4*NumStrings);
}
Пример #5
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;
}
Пример #6
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;
		}
	}
}
Пример #7
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;
}
Пример #8
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);
	}
}
Пример #9
0
void P_TranslateLineDef (line_t *ld, maplinedef_t *mld)
{
	short special = LESHORT(mld->special);
	short tag = LESHORT(mld->tag);
	short flags = LESHORT(mld->flags);
	bool passthrough = (flags & ML_PASSUSE_BOOM);
	int i;
	
	flags &= 0x01ff;	// Ignore flags unknown to DOOM

	if (special <= NUM_SPECIALS)
	{
		// This is a regular special; translate thru LUT
		flags = flags | (SpecialTranslation[special].flags << 8);
		if (passthrough)
		{	
			if (GET_SPAC(flags) == SPAC_USE)
			{
				flags &= ~ML_SPAC_MASK;
				flags |= SPAC_USETHROUGH << ML_SPAC_SHIFT;
			}
			if (GET_SPAC(flags) == SPAC_CROSS)
			{
				flags &= ~ML_SPAC_MASK;
				flags |= SPAC_CROSSTHROUGH << ML_SPAC_SHIFT;
			}
			
			// TODO: what to do with gun-activated lines with passthrough?
		}

		ld->special = SpecialTranslation[special].newspecial;
		for (i = 0; i < 5; i++)
			ld->args[i] = SpecialTranslation[special].args[i] == TAG ? tag :
						  SpecialTranslation[special].args[i];
	}
	else if (special == 337)
	{
		ld->special = Line_Horizon;
		ld->flags = flags;
		ld->id = tag;
		memset(ld->args, 0, sizeof(ld->args));
	}
	else if (special >= 340 && special <= 347)
	{
		// [SL] 2012-01-30 - convert to ZDoom Plane_Align special for
		// sloping sectors
		ld->special = Plane_Align;
		ld->flags = flags;
		ld->id = tag;
		memset(ld->args, 0, sizeof(ld->args));
		
		switch (special)
		{
		case 340:		// Slope the Floor in front of the line
			ld->args[0] = 1;
			break;
		case 341:		// Slope the Ceiling in front of the line
			ld->args[1] = 1;
			break;
		case 342:		// Slope the Floor+Ceiling in front of the line
			ld->args[0] = ld->args[1] = 1;
			break;
		case 343:		// Slope the Floor behind the line
			ld->args[0] = 2;
			break;
		case 344:		// Slope the Ceiling behind the line
			ld->args[1] = 2;
			break;
		case 345:		// Slope the Floor+Ceiling behind the line
			ld->args[0] = ld->args[1] = 2;
			break;
		case 346:		// Slope the Floor behind+Ceiling in front of the line
			ld->args[0] = 2;
			ld->args[1] = 1;
			break;
		case 347:		// Slope the Floor in front+Ceiling behind the line
			ld->args[0] = 1;
			ld->args[1] = 2;
		}
	}
	else if (special <= GenCrusherBase)
	{
		if (special >= OdamexStaticInits && special < OdamexStaticInits + NUM_STATIC_INITS)
		{
			// An Odamex Static_Init special
			ld->special = Static_Init;
			ld->args[0] = tag;
			ld->args[1] = special - OdamexStaticInits;
		}
		else
		{
			// This is an unknown special. Just zero it.
			ld->special = 0;
			memset (ld->args, 0, sizeof(ld->args));
		}
	}
	else
	{
		// Anything else is a BOOM generalized linedef type
		switch (special & 0x0007)
		{
		case WalkMany:
			flags |= ML_REPEAT_SPECIAL;
		case WalkOnce:
            if (passthrough)
                flags |= SPAC_CROSSTHROUGH << ML_SPAC_SHIFT;
            else
                flags |= SPAC_CROSS << ML_SPAC_SHIFT;
			break;

		case SwitchMany:
		case PushMany:
			flags |= ML_REPEAT_SPECIAL;
		case SwitchOnce:
		case PushOnce:
			if (passthrough)
				flags |= SPAC_USETHROUGH << ML_SPAC_SHIFT;
			else
				flags |= SPAC_USE << ML_SPAC_SHIFT;
			break;

		case GunMany:
			flags |= ML_REPEAT_SPECIAL;
		case GunOnce:
			flags |= SPAC_IMPACT << ML_SPAC_SHIFT;
			break;
		}

		// We treat push triggers like switch triggers with zero tags.
		if ((special & 0x0007) == PushMany ||
			(special & 0x0007) == PushOnce)
			ld->args[0] = 0;
		else
			ld->args[0] = tag;

		if (special <= GenStairsBase)
		{
			// Generalized crusher (tag, dnspeed, upspeed, silent, damage)
			ld->special = Generic_Crusher;
			if (special & 0x0020)
				flags |= ML_MONSTERSCANACTIVATE;
			switch (special & 0x0018) {
				case 0x0000:	ld->args[1] = C_SLOW;	break;
				case 0x0008:	ld->args[1] = C_NORMAL;	break;
				case 0x0010:	ld->args[1] = C_FAST;	break;
				case 0x0018:	ld->args[1] = C_TURBO;	break;
			}
			ld->args[2] = ld->args[1];
			ld->args[3] = (special & 0x0040) >> 6;
			ld->args[4] = 10;
		}
		else if (special <= GenLiftBase)
Пример #10
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;
}