Tutorial *38*

If you've been playing around with modding Quake2, you may have come across the fact that it limits texture sizes to a maximum of 256x256, resizing all images greater than that to that size.

After implementing the code within this tutorial, youll be able to load images with dimensions greater than 256 pixels into the engine, providing that your hardware supports it.

Now, onto the code!

All of our changes are going to take place within the file 'gl_image.c', so open it up now in your editor of choice. Locate the function named 'GL_Upload32' and delete it. We are going to rebuild this function, and we are going to do it right!

Now we shall begin recreating it. Declare the function and its associated variables the same as they was before:



// Fixed 256x256 texture size limitation - MrG

qboolean GL_Upload32 (unsigned *data, int width, int height,  qboolean mipmap)

{	int		samples;

	unsigned 	*scaled;

	int		scaled_width, scaled_height;

	int		i, c;

	byte		*scan;

	int comp;

These are the variables that we will need, and the same function declaration allows it to be easily used instead of the old function that we are replacing.

Next we shall reset the uploaded_paletted variable to false so that Quake2 knows that the textures arent paletted, and then scan the input image data for any non-opaque pixels.



	uploaded_paletted = false;	// scan the texture for any non-255 alpha

	c = width*height;

	scan = ((byte *)data) + 3;

	samples = gl_solid_format;

	for (i=0 ; i

Now that that's done, we'll begin on the block of code that will determine the size that the texture will be uploaded to video memory as. Firstly we'll create a new scope and declare a couple more variables, query OpenGL for the hardwares maximum texture size, and reset some variables values:



	{

		int powers_of_two[] = {16,32,64,128,256,512,1024,2048,4096};

		int max_size;

		int i;

		qglGetIntegerv(GL_MAX_TEXTURE_SIZE,&max_size);

		scaled_width = scaled_height = 0;

Now we have our required variables. The variable 'powers_of_two' is an array of integers containing the values of valid texture sizes that we can use. Each value is power of 2, which is what OpenGL will accept for image dimensions. The highest value in the list is 4096, which is higher = than any realistic texture size that should be used. The value of max_size is the largest texture size that the users OpenGL hardware can use.

Next we will loop through each texture dimension, and adjust the size of the image that we will be uploading. The dimensions that we will use will be one of the values of the powers_of_two array, the value closest to the input images width and height.



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

		{

			if (width >= powers_of_two[i] && width < powers_of_two[i+1]) {

				if (width > ((powers_of_two[i] + powers_of_two[i+1])/2))

					scaled_width = powers_of_two[i+1];

				else

					scaled_width = powers_of_two[i];

			} else if (width == powers_of_two[i+1]) {

				scaled_width = powers_of_two[i+1];

			}

			if (scaled_width && scaled_height)

				break;

			if (height >= powers_of_two[i] && height < powers_of_two[i+1]) {

				if (height > ((powers_of_two[i] + powers_of_two[i+1])/2))

					scaled_height = powers_of_two[i+1];

				else

					scaled_height = powers_of_two[i];

			} else if (height == powers_of_two[i+1]) {

				scaled_height = powers_of_two[i+1];

			}			if (scaled_width && scaled_height)

				break;

		}

Now it's possible that the selected size is larger than what the OpenGL hardware will accept, so we will check it against the maximum texture size that we retrieved earlier, and adjust it if needed:



		if (scaled_width > max_size)

			scaled_width = max_size;

		if (scaled_height > max_size)

			scaled_height = max_size;

	}

Now that that's done, we shall check to see if the image needs resizing, and if so, allocate sufficient memory and resize the texture.



	if (scaled_width != width || scaled_height != height) {

		scaled=malloc((scaled_width * scaled_height) * 4);

		GL_ResampleTexture(data,width,height,scaled,scaled_width,scaled_height);

	} else {

		scaled_width=width;

		scaled_height=height;

		scaled=data;

	}

Now we can begin uploading it to video memory. If the 'mipmap' function parameter has been set to true by the calling function, we will build mipmaps for the texture and then upload it, else we will just upload it as it is. Either way, we are also going to adjust the texture to take into account gamma control. Finally we shall free the memory used by the scaled texture.



	if (mipmap) {

		GL_LightScaleTexture (scaled, scaled_width, scaled_height, !mipmap);

		gluBuild2DMipmaps (GL_TEXTURE_2D, samples, scaled_width, scaled_height, GL_RGBA, GL_UNSIGNED_BYTE, scaled);

	} else {

		GL_LightScaleTexture (scaled, scaled_width, scaled_height, !mipmap );

		qglTexImage2D (GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);

	}

	if (scaled_width != width || scaled_height != height)

		free(scaled);

Now that we have done that, we will inform Quake2 of the sizes that the image was scaled to and uploaded as. We'll also set the filtering methods for the texture, and then we will finally return from the function.



	upload_width=scaled_width; upload_height = scaled_height;

	if (mipmap)

	{

		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);

		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);

	}

	else

	{

		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);

		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);

	}

	return (samples == gl_alpha_format);

}

Before you can compile, you'll need to link to the 'glu32.lib' library. Youll have to find out how to do that for your compiler yourself. After doing that, all that you need to do is compile.

Quake2 is now able to load textures with dimensions greater than 256x256, unless of course your hardware doesnt support it. Enjoy.



 
Not logged in
Sign up
Login:
Passwd: