Page 1 of 1

BSP Textures

Posted: Mon Jun 09, 2008 10:46 pm
by mh
...and loading the first 4 miplevels of a BSP texture from the internally stored miplevels, rather than generating them with GL_MipMap. :D

I don't know if any other engine does this, but it's something that every other GL engine should do.

Posted: Mon Jun 09, 2008 11:49 pm
by MDave
Amen! :) I always wondered why ID never used them for glquake.

Posted: Tue Jun 10, 2008 4:19 am
by LordHavoc
MDave wrote:Amen! :) I always wondered why ID never used them for glquake.
Because they were an approximation of the truecolor mipmaps ID wished they could have used... like the ones glquake generates.

I don't see any advantage to using the palettized mipmaps.

DarkPlaces' only changes compared to glquake in mipmap loading are:
  • uses a higher quality resampling algorithm, which makes scaled up textures look a lot better (r_lerpimages 0 can disable this).
  • uses the GL_ARB_texture_non_power_of_two extension - which avoids the need to resample entirely on GF6/Radeon HD - giving a nice improvement to menu art quality as well as certain ingame textures, and especially model skins.
  • disables mipmapping on model skins (r_lerpskins 1 can enable this).
But if using the paletted dithered mipmaps from the bsp, how about taking it two steps further:
  • use GL_SGIS_texture_lod if supported to limit the mipmapping to only use the first 4 levels.
  • add an option to force each surface to a single LOD based on distance, using GL_TEXTURE_MIN_LOD_SGIS and GL_TEXTURE_MAX_LOD_SGIS (same extension). This would allow people to use GL_NEAREST_MIPMAP_NEAREST, 4 mipmaps (from the bsp), GL_ARB_texture_non_power_of_two, and only one mipmap level per surface, thus giving an identical look to software Quake.
It's a very interesting idea to use the bsp textures though, just not sure whether it would look better or worse :)

Posted: Tue Jun 10, 2008 7:33 pm
by mh
I'm not sure about the "identical look to software Quake" bit ( :lol: ) (why not just run software Quake if that's the objective?) but it does make a (fairly subtle) difference. Where I'm coming from is the colour balance that software Quake had, but which is totally missing from GLQuake. Fixing up lighting gets you part way there, this just brings you further along the road.

Posted: Thu Jun 12, 2008 6:53 pm
by MDave
I've tried to implement your example code it into glquake, but I'm not having much luck. I don't get any compiler warnings or errors, but it crashes when loading a map.

Sorry to sound like a pain :(

Here is what I've got:

Code: Select all

static	unsigned			upload[1024*512];
added to the top of GL_Upload32, and the rest below it here:

Code: Select all

	/*
	if (mipmap)
	{
		int		miplevel;

		miplevel = 0;
		while (scaled_width > 1 || scaled_height > 1)
		{
			GL_MipMap ((byte *)scaled, scaled_width, scaled_height);
			scaled_width >>= 1;
			scaled_height >>= 1;
			if (scaled_width < 1)
				scaled_width = 1;
			if (scaled_height < 1)
				scaled_height = 1;
			miplevel++;
			glTexImage2D (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
		}
	}
	*/

	if (mipmap)
	{
		int miplevel = 1;

		// if it's an 8 bit texture coming from a BSP we handle it differently, as we want to take the first 4 (i.e.
		// (next 3) miplevels from the BSP... this ensures that the colour balance correctly matches software quake
//		if ((flags & TEX_BSP) && !(flags & TEX_32BIT))
//		{
			// BSP textures are ensured to be large enough to survive this...
			for (; miplevel < 4; miplevel++)
			{
				// advance to next stored BSP mipmap
				data += width * height;

				// take down width and height
				width >>= 1;
				height >>= 1;

				// take down scaled_width and scaled_height
				scaled_width >>= 1;
				scaled_height >>= 1;

				// deal with texture resizing
				if (width == scaled_width && height == scaled_height)
				{
					int i;
					int size = width * height;

					// upload is already set and valid, so we can copy it right in
					for (i = 0; i < size; i++) upload[i] = d_8to24table[data[i]];
				}
				else
				{
					// resample the new data into upload (already set and valid here too), never a 32 bpp base
					GL_ResampleTexture (data, width, height, upload, scaled_width, scaled_height);
				}

			// upload (don't increment miplevel for this one as the for loop does it for us)
			glTexImage2D (GL_TEXTURE_2D, miplevel, GL_RGBA, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, upload);
			}
//		}

		// BSP mipmapping sets up so that it will fall through correctly to here...
		while (scaled_width > 1 || scaled_height > 1)
		{
			// generate our mipmaps
			GL_MipMap ((byte *) upload, scaled_width, scaled_height);

			// take down to next level
			scaled_width >>= 1;
			scaled_height >>= 1;

			// never go < 1
			if (scaled_width < 1) scaled_width = 1;
			if (scaled_height < 1) scaled_height = 1;

			glTexImage2D (GL_TEXTURE_2D, miplevel++, GL_RGBA, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, upload);
		}
	}

Posted: Thu Jun 12, 2008 10:13 pm
by mh
This will crash on regular GLQuake because it's only valid for textures coming from a BSP. Other textures don't store the additional miplevels. You'll need some way of identifying whether the texture is coming from a BSP in your GL_Upload32; I suggest dropping the mipmap and alpha parameters and using a single int as a flags parameter. Add some #defines and you're there! :D