Tutorial *21*

If you're wondering what the .m32 texture format is, its basically the .wal format upgraded to 32bit with a few extras.

Before we start, this does not add FULL .m32 support. It only adds support to the OpenGL renderer, qbsp3, and qrad3. The engine itself will still try to download the .wal for a texture even if the GL renderer already loaded a .m32 for it, so the allow_download cvar should be set to "0" unless you want to see a bunch of texture download failures. Don't bother looking for detail or damage textures, because this tutorial doesn't go into that. Also, the qrad tool Raven uses must have been compiled with different light falloff values because the sample map from their SDK (the first level of SOF) was WAY too bright when lit with Quake2's qrad3. If you can't find the Quake2 tools source, its at "ftp://ftp.idsoftware.com/idstuff/quake2/source/old/q2source_12_11.zip". This code works with the 3.19 and 3.21 source.

Quake2:


Open the Quake2 source and set ref_gl as the active project. Open the "Header Files" folder in the File View and open qfiles.h

qfiles.h:

After:



} miptex_t;

Add:



// |nc - .M32 Support Begin:

/*

==============================================================================

.M32 texture file format

==============================================================================

*/



typedef struct miptex32_s

{

	int		version;

	char		name[128];

	char		altname[128];			// texture substitution

	char		animname[128];			// next frame in animation chain

	char		damagename[128];		// image that should be shown when damaged

	unsigned	width[16], height[16];

	unsigned	offsets[16];

	int		flags;

	int		contents;

	int		value;

	float		scale_x, scale_y;

	int		mip_scale;



	// detail texturing info

	char		dt_name[128];		// detailed texture name

	float		dt_scale_x, dt_scale_y;

	float		dt_u, dt_v;

	float		dt_alpha;

	int		dt_src_blend_mode, dt_dst_blend_mode;

	int		flags2;

	float		damage_health;



	int		unused[18];				// future expansion to maintain compatibility with h2

} miptex32_t;

// |nc - .M32 Support End

gl_model.c:

In function Mod_LoadTexinfo():

Replace:



if (!out->image)

{

	ri.Con_Printf (PRINT_ALL, "Couldn't load %s\n", name);

	out->image = r_notexture;

}

With:



// |nc - .M32 Support Begin:

//		if (!out->image)

//		{

//			ri.Con_Printf (PRINT_ALL, "Couldn't load %s\n", name);

//			out->image = r_notexture;

//		}

		if (!out->image || out->image == r_notexture)

		{

			Com_sprintf (name, sizeof(name), "textures/%s.m32", in->texture);

			out->image = GL_FindImage (name, it_wall);



			if (!out->image)

			{

				ri.Con_Printf (PRINT_ALL, "Couldn't load %s\n", name);

				out->image = r_notexture;

			}

		}

		// |nc - .M32 Support End

gl_image.c:

After function GL_LoadWal():

Add:



// |nc - .M32 Support Begin:

/*

================

GL_LoadWal32

================

*/

image_t *GL_LoadWal32 (char *name)

{

	miptex32_t	*mt;

	int			width, height, ofs;

	image_t		*image;



	ri.FS_LoadFile (name, (void **)&mt);

	if (!mt)

	{

		ri.Con_Printf (PRINT_ALL, "GL_FindImage: can't load %s\n", name);

		return r_notexture;

	}



	width = LittleLong (mt->width[0]);

	height = LittleLong (mt->height[0]);

	ofs = LittleLong (mt->offsets[0]);



	image = GL_LoadPic (name, (byte *)mt + ofs, width, height, it_wall, 32);

	ri.FS_FreeFile ((void *)mt);



	return image;

}

// |nc - .M32 Support End

In Function GL_FindImage():

After:



else if (!strcmp(name+len-4, ".tga"))

{

	LoadTGA (name, &pic, &width, &height);

	if (!pic)

		return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name);

		image = GL_LoadPic (name, pic, width, height, type, 32);

	}

Add:



// |nc - .M32 Support Begin:

	else if (!strcmp(name+len-4, ".m32"))

	{

		image = GL_LoadWal32 (name);

	}

// |nc - .M32 Support End


QBSP3:

qfiles.h (in the "External Dependencies" folder):

After:



	} miptex_t;

Add:



/*

==============================================================================



.M32 texture file format



==============================================================================

*/



typedef struct miptex32_s

{

	int		version;

	char		name[128];

	char		altname[128];			// texture substitution

	char		animname[128];			// next frame in animation chain

	char		damagename[128];		// image that should be shown when damaged

	unsigned	width[16], height[16];

	unsigned	offsets[16];

	int		flags;

	int		contents;

	int		value;

	float		scale_x, scale_y;

	int		mip_scale;



	// detail texturing info

	char		dt_name[128];		// detailed texture name

	float		dt_scale_x, dt_scale_y;

	float		dt_u, dt_v;

	float		dt_alpha;

	int		dt_src_blend_mode, dt_dst_blend_mode;

	int		flags2;

	float		damage_health;



	int		unused[18];				// future expansion to maintain compatibility with h2

} miptex32_t;

textures.c:

In function FindMiptex():

After:



	miptex_t	*mt;

Add:



	// |nc - .M32 Support Begin:

	miptex32_t	*mt32;

	// |nc - .M32 Support End

After:



	if (TryLoadFile (path, (void **)&mt) != -1)

	{

		textureref[i].value = LittleLong (mt->value);

		textureref[i].flags = LittleLong (mt->flags);

		textureref[i].contents = LittleLong (mt->contents);

		strcpy (textureref[i].animname, mt->animname);

		free (mt);

	}

Add:



	// |nc - .M32 Support Begin:

	else

	{

		sprintf (path, "%stextures/%s.m32", gamedir, name);

		if (TryLoadFile (path, (void **)&mt32) != -1)

		{

			textureref[i].value = LittleLong (mt32->value);

			textureref[i].flags = LittleLong (mt32->flags);

			textureref[i].contents = LittleLong (mt32->contents);

			strcpy (textureref[i].animname, mt32->animname);

			free (mt32);

		}

	}

	// |nc - .M32 Support End


QRAD3:

patches.c:

Replace the entire CalcTextureReflectivity() funcion with:



// |nc - .M32 Support Begin

void CalcTextureReflectivity (void)

{

	int		i;

	int		j, k, texels;

	int		color[3];

	int		texel;

	byte		*palette;

	char		path[1024];

	float		r, scale;

	miptex_t	*mt;

	miptex32_t	*mt32;

	int		offset;

	byte		*temp;



	sprintf (path, "%spics/colormap.pcx", gamedir);



	// get the game palette

	Load256Image (path, NULL, &palette, NULL, NULL);



	// allways set index 0 even if no textures

	texture_reflectivity[0][0] = 0.5;

	texture_reflectivity[0][1] = 0.5;

	texture_reflectivity[0][2] = 0.5;



	for (i=0 ; i < numtexinfo ; i++)

	{

		// see if an earlier texinfo allready got the value

		for (j=0 ; j < i ; j++)

		{

			if (!strcmp (texinfo[i].texture, texinfo[j].texture))

			{

				VectorCopy (texture_reflectivity[j], texture_reflectivity[i]);

				break;

			}

		}



		if (j != i)

			continue;



		// load the wal file

		sprintf (path, "%stextures/%s.wal", gamedir, texinfo[i].texture);

		if (TryLoadFile (path, (void **)&mt) != -1)

		{

			texels = LittleLong(mt->width)*LittleLong(mt->height);

			offset = LittleLong(mt->offsets[0]);

			temp = (byte *)mt;

			color[0] = color[1] = color[2] = 0;



			for (j=0 ; j<texels ; j++)

			{

				texel = temp[offset + j];

				for (k=0 ; k < 3 ; k++)

					color[k] += palette[texel*3+k];

			}

		}

		else

		{

			sprintf (path, "%stextures/%s.m32", gamedir, texinfo[i].texture);

			if (TryLoadFile (path, (void **)&mt32) != -1)

			{

				texels = LittleLong(mt32->width[0])*LittleLong(mt32->height[0]);

				offset = LittleLong(mt32->offsets[0]);

				temp = (byte *)mt32;

				color[0] = color[1] = color[2] = 0;



				for (j=0 ; j < texels ; j++)

				{

					texel = temp[offset + j];

					for (k=0 ; k<3 ; k++)

						color[k] += texel*4+k;

				}

			}

			else

			{

				printf ("Couldn't load %s\n", path);

				texture_reflectivity[i][0] = 0.5;

				texture_reflectivity[i][1] = 0.5;

				texture_reflectivity[i][2] = 0.5;

				continue;

			}

		}



		for (j=0 ; j<3 ; j++)

		{

			r = color[j]/texels/255.0;

			texture_reflectivity[i][j] = r;

		}

		// scale the reflectivity up, because the textures are

		// so dim

		scale = ColorNormalize (texture_reflectivity[i],

		texture_reflectivity[i]);

		if (scale < 0.5)

		{

			scale *= 2;

			VectorScale (texture_reflectivity[i], scale, texture_reflectivity[i]);

		}

		#if 0

		texture_reflectivity[i][0] = 0.5;

		texture_reflectivity[i][1] = 0.5;

		texture_reflectivity[i][2] = 0.5;

		#endif

	}

}

// |nc - .M32 Support End

Now you can compile maps with .m32 textures and Quake2 will load them if theres no .wals with the same name.



 
Sign up
Login:
Passwd:
[Remember Me]