use a dds without the best quality level (top mipmap)

Discussion area about developing or extending OGRE, adding plugins for it or building applications on it. No newbie questions please, use the Help forum for that.
User avatar
Assaf Raman
OGRE Team Member
OGRE Team Member
Posts: 3092
Joined: Tue Apr 11, 2006 3:58 pm
Location: TLV, Israel

use a dds without the best quality level (top mipmap)

Post by Assaf Raman » Sun May 31, 2009 3:23 pm

I recently run into a problem when I needed to run a scene that needed many textures – more then low spec computers could load – basically my problem was that I run out of texture memory.
It is very hard for me to limit the number of entities or entity types visible.
All my textures are using the dds format.
The simple solution I found was instead loading the textures directly from file, I load them to the memory and remove the best images (top mipmap) and get a dds texture with a 1/4 of the size ( and 1/4 of the quality), this way I don't run out of memory and have minimum artifacts.

The code to remove the top level mipmap is basically only a memory copy – so the CPU needed is small (much smaller then trying to resize the image and recreating the mipmaps…).

Here is a code snippet of removing the top mipmap:

Code: Select all

		char * tempBuf = NULL;
		...
		// Read the dds file into tempBuf 
		...

		// simplified dds header struct with the minimum data needed
		typedef struct DDSHEADER {
			DWORD dwMagic;
			DWORD dwSize;	
			DWORD dwFlags;	
			DWORD dwHeight;
			DWORD dwWidth;
			DWORD dwPitchOrLinearSize;
			DWORD dwDepth;
			DWORD dwMipMapCount;
			CHAR dataThatWeDoNotNeed[96];
		};

		// read the size of the image from the header
		DDSHEADER * header = (DDSHEADER *)tempBuf;
		int width = header->dwWidth;
		int height = header->dwHeight;

		// calculate the size of the image
		int sizeOfFirstLevel = width  * height / 2;

		// copy over the first level
		char * posOfFirstLevel = tempBuf + sizeof(DDSHEADER);
		char * posOfNextLevel = posOfFirstLevel + sizeOfFirstLevel;
		memcpy(posOfFirstLevel, posOfNextLevel, originalFileSize - sizeof(DDSHEADER) - sizeOfFirstLevel);
		size_t sizeOfFileWithoutLevel = originalFileSize - sizeOfFirstLevel;

		// change the header to be without the top level (resize to be 1/4 of the original size)
		header->dwHeight /= 2;
		header->dwWidth /= 2;

		// decrement the mipmap count by one  
		header->dwMipMapCount -= 1; 

		// tempBuf is now an image with 1/4 of the original size!

What do you think, is this a good idea?
Any other ideas for my problem?
Did I miss existing code that does the same thing?
Can I resize a loaded texture in an easy way that will also keep it compressed on the GPU?
0 x
Watch out for my OGRE related tweets here.

User avatar
Assaf Raman
OGRE Team Member
OGRE Team Member
Posts: 3092
Joined: Tue Apr 11, 2006 3:58 pm
Location: TLV, Israel

Re: use a dds without the best level (top mipmap)

Post by Assaf Raman » Sun May 31, 2009 4:48 pm

The sample code is for DDS DXT1 - but for the other types only a switch on the calc of the size of the image in memory is needed.
After thinking about it - you can also improve by not reading the first level from the file (skip it when you read the file) and get also better io (read a 1/4 of the original data).
0 x
Watch out for my OGRE related tweets here.

User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19265
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 2
Contact:

Re: use a dds without the best level (top mipmap)

Post by sinbad » Sun May 31, 2009 5:52 pm

For DDS just skipping the top mip is probably a good idea for doing this. Hard to generalise unless you know your content though.
0 x

User avatar
cdleonard
Goblin
Posts: 266
Joined: Thu May 31, 2007 9:45 am

Re: use a dds without the best level (top mipmap)

Post by cdleonard » Sun May 31, 2009 6:12 pm

Couldn't this be integrated with ogre texture loading somehow? There's already a limit for the worst mipmap level (TextureUnitState::NumMipMaps); couldn't this be added as another limit in all the same places? It would be an awesome feature!
0 x

User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19265
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 2
Contact:

Re: use a dds without the best level (top mipmap)

Post by sinbad » Sun May 31, 2009 6:38 pm

My only problems with that idea are:

a) You'd probably want to make it a maximum size, not maximum level. Otherwise you could end up trepanning small textures for no reason
b) It would only work with DDS files with pregenerated mipmaps (or manually loaded files where mipmaps are explicitly provided). So it could be made a DDSCodec option, but that does seem a missed opportunity. Making it a general texture loading option is better, but that's much more complicated; regular jpg/png/bmp etc files would need to be loaded and then resized.
c) It's a bit broad-brush even with size rather than miplevel - I can imagine cases where you want to give certain textures priority to use bigger sizes, but downgrade less important ones.

Of course the ultimate progression of this feature is to include a PageContent component which can page in just the lower level mips and replace them later with the higher-level mips as required.

But, as a very specific feature usable in just this scenario I guess it wouldn't hurt to add this to DDSCodec and explore the more generalised options later.
0 x

User avatar
cdleonard
Goblin
Posts: 266
Joined: Thu May 31, 2007 9:45 am

Re: use a dds without the best level (top mipmap)

Post by cdleonard » Sun May 31, 2009 7:47 pm

sinbad wrote:a) You'd probably want to make it a maximum size, not maximum level. Otherwise you could end up trepanning small textures for no reason
b) It would only work with DDS files with pregenerated mipmaps (or manually loaded files where mipmaps are explicitly provided). So it could be made a DDSCodec option, but that does seem a missed opportunity. Making it a general texture loading option is better, but that's much more complicated; regular jpg/png/bmp etc files would need to be loaded and then resized.
You could create a MipmapRequestParams struct with min/max levels and sizes. That would be added as a hint to ImageCodec::decode to return a subset of the file. Other codecs could simply ignore that aspect and always return the full file.

Ogre::Texture can then deal with automatically shrinking the texture or dropping unused mips; just how it now deals with creating new mips. It makes sense to support this for all kinds of files. Using less video memory is a worthwhile feature even if you end up with longer load times.

In code this would look like replacing a big bunch of numMipmaps parameters with a struct (at least in TextureUnitState, Texture and TextureManager).
sinbad wrote:c) It's a bit broad-brush even with size rather than miplevel - I can imagine cases where you want to give certain textures priority to use bigger sizes, but downgrade less important ones.

Of course the ultimate progression of this feature is to include a PageContent component which can page in just the lower level mips and replace them later with the higher-level mips as required.
If you get these parameters in the material you can create various techniques which use less video memory; and switch them based on schemes and lod distances. I don't know how this relates to the new paging features.
0 x

User avatar
iloseall
Gremlin
Posts: 156
Joined: Sun Sep 14, 2003 3:54 am
Location: Beijing China
Contact:

Re: use a dds without the best level (top mipmap)

Post by iloseall » Mon Jun 01, 2009 4:39 pm

If you get these parameters in the material you can create various techniques which use less video memory; and switch them based on schemes and lod distances. I don't know how this relates to the new paging features.
I think :
Scheme swith technique and texture use,but cound not switch texture load.
Ogre load all textures (in all technique) when material load.
Is it yes or no?

I like the function to stop load some mipmap.
0 x

User avatar
Assaf Raman
OGRE Team Member
OGRE Team Member
Posts: 3092
Joined: Tue Apr 11, 2006 3:58 pm
Location: TLV, Israel

Re: use a dds without the best level (top mipmap)

Post by Assaf Raman » Tue Jun 02, 2009 1:44 pm

Here is a final version of my dds top mipmap remover.
This version of the function:
  • Can be used at load time (to load without top mipmaps io).
  • Supports DXT1, DXT2, DXT3, DXT4 and DXT5 pixel formats.
  • Can be used on a memory stream to convert in realtime - in memory.
  • Can remove as much top mipmap levels as you select (EX: the two top mipmaps).
  • Checks if the file type is valid – if not – it returns the original data.

Code: Select all

	/** Removes top MipMap levels from a dds file (stream)
	@remarks This function loads an image file from a stream,
	    if the file is a dds file that has MipMaps -
	    the number of top MipMap level that are defined
	    by a parameter will be removed
	@param sourceStream - source stream with the image file data
	@param numberOfTopMipMapToSkip - number of top MipMap levels that will be removed
	@returns - a self releasing memory stream with the modified dds
	*/
	Ogre::MemoryDataStream * removeTopMipMapsFromDds(Ogre::DataStream * sourceStream, const size_t numberOfTopMipMapToSkip)
	{
		// simplified dds header struct with the minimum data needed
		struct DDSHEADER {
			char cMagic[4];
			unsigned long dwSize;	
			unsigned long dwFlags;	
			unsigned long dwHeight;
			unsigned long dwWidth;
			unsigned long dwPitchOrLinearSize;
			unsigned long dwDepth;
			unsigned long dwMipMapCount;
			unsigned long dwReserved1[11];
			unsigned long dwSizeOfPixelFormat;	
			unsigned long dwFlagsOfPixelFormat;	
			char cFourCharIdOfPixelFormat[4];
			char dataThatWeDoNotNeed[40];
		};

		// return to the stream beginning 
		sourceStream->seek(0);

		// read the header
		DDSHEADER header;
		sourceStream->read(&header, sizeof(DDSHEADER));

		// check if this is a valid dds file by the image type id
		bool isMagicValid = ( memcmp(header.cMagic, "DDS ", 4) == 0);

		// check if the pixel type is DXT (do the check only if the magic is valid...)
		bool isDXT = isMagicValid && memcmp(header.cFourCharIdOfPixelFormat, "DXT", 3) == 0;

		// check if this is a valid dds file by the image type id
		bool isValidDdsFile = isMagicValid && isDXT;

		unsigned long totalSizeOfTheSkipTopLevels = 0;

		if (isValidDdsFile)
		{

			// store the width and height as local vars for easy access 
			unsigned long width = header.dwWidth;
			unsigned long height = header.dwHeight;
			unsigned long mipMapCount = header.dwMipMapCount;
			bool isDXT1 = memcmp(header.cFourCharIdOfPixelFormat, "DXT1", 4) == 0;


			// skip the levels (if has MipMap and a valid file)
			for (size_t i = 0 ; i < numberOfTopMipMapToSkip && mipMapCount > 1 && isValidDdsFile ; i++)
			{
				// calculate the size current top level
				long sizeOfCurTopLevel = width  * height;

				// if the pixel type is DXT1 - the size is half of DXT3 or DXT5
				if (isDXT1)
				{
					 sizeOfCurTopLevel /= 2; 
				}

				// skip the current top level
				totalSizeOfTheSkipTopLevels += sizeOfCurTopLevel;
				
				// update to the new size
				height /= 2;
				width /= 2;

				// decrement the MipMap count by one  
				mipMapCount -= 1; 
			}

			// change the header to be without the top levels that were removed
			header.dwHeight = height;
			header.dwWidth = width;
			header.dwMipMapCount = mipMapCount; 

			// skip the top levels in the stream
			sourceStream->skip(totalSizeOfTheSkipTopLevels);
		}


		// create the memory for the loaded data
		size_t sizeOfTheDddWithoutTopLevels = 
			sourceStream->size() - totalSizeOfTheSkipTopLevels;

		Ogre::uint8 * bufferForDdsData = new Ogre::uint8[sizeOfTheDddWithoutTopLevels];

		// add the header
		memcpy(bufferForDdsData, &header, sizeof(DDSHEADER));

		// read the rest of the data
		size_t sizeOfTheDddsWithoutTopLevelsAndHeaders 
			= sizeOfTheDddWithoutTopLevels - sizeof(DDSHEADER);

		sourceStream->read(bufferForDdsData + sizeof(DDSHEADER), 
			sizeOfTheDddsWithoutTopLevelsAndHeaders);

		// return the new memory stream
		return new MemoryDataStream(bufferForDdsData, sizeOfTheDddWithoutTopLevels, true);
	}
Feel free to comment, improve or use.

EDIT: Just to be clear - the code license is – "public domain" – free for any use.
0 x
Watch out for my OGRE related tweets here.

User avatar
Praetor
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3335
Joined: Tue Jun 21, 2005 8:26 pm
Location: Rochester, New York, US
Contact:

Re: use a dds without the best level (top mipmap)

Post by Praetor » Tue Jun 02, 2009 2:45 pm

How useful. I suppose something similar in nature could then be used to stream in that top mipmap later? I'm of course thinking of loading all images at a lower mipmap level, and then loading in higher mipmaps when detail is needed (proximity). It seems to be the start of neat texture streaming utility. Now you've given me all sorts of ideas.
0 x
Game Development, Engine Development, Porting
http://www.darkwindmedia.com

User avatar
Assaf Raman
OGRE Team Member
OGRE Team Member
Posts: 3092
Joined: Tue Apr 11, 2006 3:58 pm
Location: TLV, Israel

Re: use a dds without the best level (top mipmap)

Post by Assaf Raman » Tue Jun 02, 2009 3:00 pm

Praetor wrote:I suppose something similar in nature could then be used to stream in that top mipmap later?
Yes. If you needed help with that - I can help - just tell me what you need.
0 x
Watch out for my OGRE related tweets here.

User avatar
Praetor
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3335
Joined: Tue Jun 21, 2005 8:26 pm
Location: Rochester, New York, US
Contact:

Re: use a dds without the best level (top mipmap)

Post by Praetor » Tue Jun 02, 2009 4:01 pm

Probably wouldn't be possible to stream the new mipmaps into existing textures. You'd need to create a new texture containing all the mipmaps, and then replace the old one with the new one.
0 x
Game Development, Engine Development, Porting
http://www.darkwindmedia.com

User avatar
Assaf Raman
OGRE Team Member
OGRE Team Member
Posts: 3092
Joined: Tue Apr 11, 2006 3:58 pm
Location: TLV, Israel

Re: use a dds without the best level (top mipmap)

Post by Assaf Raman » Tue Jun 02, 2009 4:07 pm

That is what I am doing now.
0 x
Watch out for my OGRE related tweets here.

User avatar
Assaf Raman
OGRE Team Member
OGRE Team Member
Posts: 3092
Joined: Tue Apr 11, 2006 3:58 pm
Location: TLV, Israel

Re: use a dds without the best level (top mipmap)

Post by Assaf Raman » Wed Jun 03, 2009 9:41 am

I am thinking of using the code from the bottom of this thread to find out how much video memory I have (total).
The code seems to return the amount without including AGP.
The only case I found that it the results are not so good – are in the case you have multiple graphic adaptors, but for most cases it does the job.
Attachments
getVideoMemory.zip
code sample from the thread
(4.92 KiB) Downloaded 313 times
0 x
Watch out for my OGRE related tweets here.

User avatar
xadhoom
Minaton
Posts: 973
Joined: Fri Dec 28, 2007 4:35 pm
Location: Germany

Re: use a dds without the best quality level (top mipmap)

Post by xadhoom » Wed Jun 03, 2009 12:30 pm

Hi Assaf!

Very interesting feature. In terms of paging the first thing which jumped to my mind reading this thread was the ability to load from bottom to top (of all mipmaps) in the background. If the user defines some kind of (e.g. time) limit which leads to a skipping of loading the larger textures until the next update this could smooth loading of pages.
Ofcourse this is a different target then using limited memory but not contradicting.

Nice work!

xad
0 x

User avatar
Assaf Raman
OGRE Team Member
OGRE Team Member
Posts: 3092
Joined: Tue Apr 11, 2006 3:58 pm
Location: TLV, Israel

Re: use a dds without the best quality level (top mipmap)

Post by Assaf Raman » Wed Jun 03, 2009 1:10 pm

My use is to check the available memory and if it is smaller then I needed - load smaller images (You have all the code needed for that in this thread).

You can use the same code to get the environment up faster (use lower quality textures) then updated to better quality textures while the application is running.

Note – you will have to create a new "texture" object for the better quality image then switch the texture name or reference in the material – in real-time.
0 x
Watch out for my OGRE related tweets here.

User avatar
Praetor
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3335
Joined: Tue Jun 21, 2005 8:26 pm
Location: Rochester, New York, US
Contact:

Re: use a dds without the best quality level (top mipmap)

Post by Praetor » Wed Jun 03, 2009 5:02 pm

I've been pondering lately why it isn't easier to get how much video memory a card has. Seems like the sort of useful information that should come standard with any caps query.
0 x
Game Development, Engine Development, Porting
http://www.darkwindmedia.com

User avatar
Assaf Raman
OGRE Team Member
OGRE Team Member
Posts: 3092
Joined: Tue Apr 11, 2006 3:58 pm
Location: TLV, Israel

Re: use a dds without the best quality level (top mipmap)

Post by Assaf Raman » Wed Jun 03, 2009 6:19 pm

Well, you can always start the program by allocation as much as you can - until the allocation fail - and find out what is the "real" size of the memory you can use. The only problem with that idea is that you will not know how much of the memory is GPU memory and not AGP memory.
0 x
Watch out for my OGRE related tweets here.

User avatar
Jabberwocky
OGRE Moderator
OGRE Moderator
Posts: 2819
Joined: Mon Mar 05, 2007 11:17 pm
Location: Canada
Contact:

Re: use a dds without the best quality level (top mipmap)

Post by Jabberwocky » Sat Jun 06, 2009 2:01 am

This would be really useful to help support a graphics setting for texture resolution. It would be nice if this could be worked directly into the material script somehow, but maybe that's a lot of work. Here's an example of what I'm thinking, using a HiRes and LoRes scheme:

Code: Select all

material RockWall
{
   technique
   {
      scheme HiRes
      pass
      {
         texture_unit
         {
            texture RockWall.DDS
         }
      }
   }
   technique
   {
      scheme LoRes
      pass
      {
         texture_unit
         {
            texture RockWall.DDS 
            dds_mipmap_maxsize 256 256
            // or alternatively
            dds_mipmap_discard 1
         }
      }
   }
}
This is nothing you couldn't do by just using a whole separate set of LoRes textures, but it would save some diskspace, and some work converting the high resolution to low resolution textures.

Working this into the material file would allow precise control over exactly which textures you wanted to affect - allowing you to only modify large and/or unimportant textures in the LoRes scheme.
0 x
Image

User avatar
Praetor
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3335
Joined: Tue Jun 21, 2005 8:26 pm
Location: Rochester, New York, US
Contact:

Re: use a dds without the best quality level (top mipmap)

Post by Praetor » Sat Jun 06, 2009 6:00 am

In general the mipmapping is a texture setting, making texture_unit script settings not very well-suited for the job. What happens when multiple scripts reference the same texture, but with different mipmap settings?
0 x
Game Development, Engine Development, Porting
http://www.darkwindmedia.com

User avatar
Jabberwocky
OGRE Moderator
OGRE Moderator
Posts: 2819
Joined: Mon Mar 05, 2007 11:17 pm
Location: Canada
Contact:

Re: use a dds without the best quality level (top mipmap)

Post by Jabberwocky » Sat Jun 06, 2009 7:03 am

Praetor wrote:In general the mipmapping is a texture setting, making texture_unit script settings not very well-suited for the job. What happens when multiple scripts reference the same texture, but with different mipmap settings?
Hmm, good point. I had a vague feeling something might get complicated with the material script approach. I guess I could imagine each mipmap-altered texture being its own unique resource somehow, but perhaps things may then rapidly become more complicated than it's worth.
0 x
Image

User avatar
Praetor
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 3335
Joined: Tue Jun 21, 2005 8:26 pm
Location: Rochester, New York, US
Contact:

Re: use a dds without the best quality level (top mipmap)

Post by Praetor » Sat Jun 06, 2009 4:34 pm

I think something like this is better suited to being controlled from a higher-level. If you want it to be script-driven it's probably best to do that from application-level scripts.
0 x
Game Development, Engine Development, Porting
http://www.darkwindmedia.com

User avatar
Jabberwocky
OGRE Moderator
OGRE Moderator
Posts: 2819
Joined: Mon Mar 05, 2007 11:17 pm
Location: Canada
Contact:

Re: use a dds without the best quality level (top mipmap)

Post by Jabberwocky » Sat Jun 06, 2009 9:56 pm

Yeah, I think you're right.
0 x

oiking
Kobold
Posts: 39
Joined: Fri Jun 06, 2008 1:59 pm
Location: Germany
Contact:

Re: use a dds without the best level (top mipmap)

Post by oiking » Thu Aug 27, 2009 10:58 am

Assaf Raman wrote:Here is a final version of my dds top mipmap remover.
What is a good place to plug this in? You said you're loading all your textures from memory instead of loading from files - did you modify your TextureManager to support it?
I'm really looking for this feature to have in my OGRE build.
0 x
Working at Z-Software

User avatar
Assaf Raman
OGRE Team Member
OGRE Team Member
Posts: 3092
Joined: Tue Apr 11, 2006 3:58 pm
Location: TLV, Israel

Re: use a dds without the best quality level (top mipmap)

Post by Assaf Raman » Thu Aug 27, 2009 12:29 pm

One option is to change the end of FileSystemArchive::open to use the function.
0 x
Watch out for my OGRE related tweets here.

User avatar
mkultra333
Gold Sponsor
Gold Sponsor
Posts: 1889
Joined: Sun Mar 08, 2009 5:25 am
x 36

Re: use a dds without the best level (top mipmap)

Post by mkultra333 » Wed Jan 06, 2010 10:56 am

Assaf Raman wrote:Here is a final version of my dds top mipmap remover.
This version of the function:
  • Can be used at load time (to load without top mipmaps io).
  • Supports DXT1, DXT2, DXT3, DXT4 and DXT5 pixel formats.
  • Can be used on a memory stream to convert in realtime - in memory.
  • Can remove as much top mipmap levels as you select (EX: the two top mipmaps).
  • Checks if the file type is valid – if not – it returns the original data.

Code: Select all

	/** Removes top MipMap levels from a dds file (stream)
	@remarks This function loads an image file from a stream,
	    if the file is a dds file that has MipMaps -
	    the number of top MipMap level that are defined
	    by a parameter will be removed
	@param sourceStream - source stream with the image file data
	@param numberOfTopMipMapToSkip - number of top MipMap levels that will be removed
	@returns - a self releasing memory stream with the modified dds
	*/
	Ogre::MemoryDataStream * removeTopMipMapsFromDds(Ogre::DataStream * sourceStream, const size_t numberOfTopMipMapToSkip)
	{
		// simplified dds header struct with the minimum data needed
		struct DDSHEADER {
			char cMagic[4];
			unsigned long dwSize;	
			unsigned long dwFlags;	
			unsigned long dwHeight;
			unsigned long dwWidth;
			unsigned long dwPitchOrLinearSize;
			unsigned long dwDepth;
			unsigned long dwMipMapCount;
			unsigned long dwReserved1[11];
			unsigned long dwSizeOfPixelFormat;	
			unsigned long dwFlagsOfPixelFormat;	
			char cFourCharIdOfPixelFormat[4];
			char dataThatWeDoNotNeed[40];
		};

		// return to the stream beginning 
		sourceStream->seek(0);

		// read the header
		DDSHEADER header;
		sourceStream->read(&header, sizeof(DDSHEADER));

		// check if this is a valid dds file by the image type id
		bool isMagicValid = ( memcmp(header.cMagic, "DDS ", 4) == 0);

		// check if the pixel type is DXT (do the check only if the magic is valid...)
		bool isDXT = isMagicValid && memcmp(header.cFourCharIdOfPixelFormat, "DXT", 3) == 0;

		// check if this is a valid dds file by the image type id
		bool isValidDdsFile = isMagicValid && isDXT;

		unsigned long totalSizeOfTheSkipTopLevels = 0;

		if (isValidDdsFile)
		{

			// store the width and height as local vars for easy access 
			unsigned long width = header.dwWidth;
			unsigned long height = header.dwHeight;
			unsigned long mipMapCount = header.dwMipMapCount;
			bool isDXT1 = memcmp(header.cFourCharIdOfPixelFormat, "DXT1", 4) == 0;


			// skip the levels (if has MipMap and a valid file)
			for (size_t i = 0 ; i < numberOfTopMipMapToSkip && mipMapCount > 1 && isValidDdsFile ; i++)
			{
				// calculate the size current top level
				long sizeOfCurTopLevel = width  * height;

				// if the pixel type is DXT1 - the size is half of DXT3 or DXT5
				if (isDXT1)
				{
					 sizeOfCurTopLevel /= 2; 
				}

				// skip the current top level
				totalSizeOfTheSkipTopLevels += sizeOfCurTopLevel;
				
				// update to the new size
				height /= 2;
				width /= 2;

				// decrement the MipMap count by one  
				mipMapCount -= 1; 
			}

			// change the header to be without the top levels that were removed
			header.dwHeight = height;
			header.dwWidth = width;
			header.dwMipMapCount = mipMapCount; 

			// skip the top levels in the stream
			sourceStream->skip(totalSizeOfTheSkipTopLevels);
		}


		// create the memory for the loaded data
		size_t sizeOfTheDddWithoutTopLevels = 
			sourceStream->size() - totalSizeOfTheSkipTopLevels;

		Ogre::uint8 * bufferForDdsData = new Ogre::uint8[sizeOfTheDddWithoutTopLevels];

		// add the header
		memcpy(bufferForDdsData, &header, sizeof(DDSHEADER));

		// read the rest of the data
		size_t sizeOfTheDddsWithoutTopLevelsAndHeaders 
			= sizeOfTheDddWithoutTopLevels - sizeof(DDSHEADER);

		sourceStream->read(bufferForDdsData + sizeof(DDSHEADER), 
			sizeOfTheDddsWithoutTopLevelsAndHeaders);

		// return the new memory stream
		return new MemoryDataStream(bufferForDdsData, sizeOfTheDddWithoutTopLevels, true);
	}
Feel free to comment, improve or use.
Hi, I'm just reaching a point where this code could be very useful to me. Almost all my textures will be DXT and I'd like them to be hi resolution, 1024x1024. However this will be too much for a lot of cards, so skipping the top mip map level will help a lot. I can have low, medium and high options for the texture resolution.

But I don't really understand the overall workings of Ogre, I haven't messed with the automated texture loading. I don't understand whether this code has to be added to the Ogre source, compiled into the DLLs, or whether it's something applied from your app.

Could you give an example (or even just some hints) of how to apply the above code, for someone who's only ever let Ogre load its textures automatically?

Edit: Also, could you give some license info? MIT, GPL, other? I always feel very nervous using code published without a clear indication of license, and usually just avoid it even if I really need it.
0 x
"In theory there is no difference between practice and theory. In practice, there is." - Psychology Textbook.

Post Reply