2D Sprite scaling

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
LordNyson
Posts: 31
Joined: Tue Nov 11, 2008 12:02 pm
Location: Perth, Australia

2D Sprite scaling

Post by LordNyson »

Hey there, I have been having a little bit of a hiccup for a while. Basically due to the ability to alter the resolution of the application I am designing I am getting a headache.

What is happening is I have got the restarting of the engine running fine, however, I have to scale the 2d GUI to the new resolution. I was given some code not too long ago, that scaled it for me, and have since.. I think... got my head around it, but there are still a few grey areas. The code itself, once you restarted the engine did not always work, and upon editing it, I find that every time I now restart the engine (by this I mean change resolution, press apply and it creates a new irrlicht window, in place of the old one) It gives me an error.

Here is my edited version:

Code: Select all

irr::video::ITexture* EngineElements::scaleTexture(irr::video::ITexture* SrcTexture, const irr::core::dimension2di& destSize, stringc image)
{ 
   ITexture* IntTexture = 0; 
   stringc SrcName = image; 

   IntTexture = driver->getTexture((image += (stringc)destSize.Width += (stringc)"x" += (stringc)destSize.Height += (stringc)".png").c_str()); 
   if(IntTexture != 0)return IntTexture;
 
   IImage* SrcImage = 0;
   IImage* DestImage = 0; 

   driver->setTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS, false); 

   try
   {
		IntTexture = driver->addTexture(destSize, "IntermediateTexture"); 
		SrcImage = driver->createImageFromData(SrcTexture->getColorFormat(), SrcTexture->getSize(), SrcTexture->lock()); 
		DestImage = driver->createImageFromData(SrcTexture->getColorFormat(), destSize, IntTexture->lock());   
   }
   catch(...)
   {
		int temp = MessageBox(NULL, ((stringc)"Error in scaling image: " += image += (stringc)"\nThis can be caused by incorrect resolution settings.").c_str(),"Fatal Error",MB_OK | MB_ICONSTOP);
		return NULL;
   };
   
   SrcTexture->unlock(); 
   SrcImage->copyToScaling(DestImage);
   IntTexture->unlock();

   driver->writeImageToFile(DestImage,(SrcName += (stringc)destSize.Width += (stringc)"x" += (stringc)destSize.Height += (stringc)".png").c_str());

   driver->removeTexture(IntTexture); 
   IntTexture = driver->addTexture(SrcName.c_str(), DestImage); 
   SrcImage->drop(); 
   DestImage->drop(); 

   driver->setTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS, true);  
   
   return IntTexture; 
}  
Here is the given code:

Code: Select all

irr::video::ITexture* Game::scaleTexture(irr::video::ITexture* SrcTexture, const irr::core::dimension2di& destSize) const 
{ 
   static irr::u32 counter = 0; 
   irr::video::IImage* SrcImage = 0; 
   irr::video::IImage* DestImage = 0; 
   irr::video::ITexture* IntTexture = 0; 
   irr::core::stringc SrcName = "NewTexture"; 
   SrcName += counter; 

   videoDriver->setTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS, false); 

   IntTexture = this->videoDriver->addTexture(destSize, "IntermediateTexture"); 
   SrcImage = this->videoDriver->createImageFromData(SrcTexture->getColorFormat(), SrcTexture->getSize(), SrcTexture->lock()); 
   DestImage = this->videoDriver->createImageFromData(SrcTexture->getColorFormat(), destSize, IntTexture->lock()); 

   IntTexture->unlock(); 
   SrcImage->copyToScaling(DestImage); 
   SrcTexture->unlock(); 

   this->videoDriver->removeTexture(IntTexture); 
   IntTexture = this->videoDriver->addTexture(SrcName.c_str(), DestImage); 
   SrcImage->drop(); 
   DestImage->drop(); 

   videoDriver->setTextureCreationFlag(irr::video::ETCF_CREATE_MIP_MAPS, true); 

   ++counter; 

   return IntTexture; 
} 
I have a question regarding:

Code: Select all

  DestImage = driver->createImageFromData(SrcTexture->getColorFormat(), destSize, IntTexture->lock());   
I experimented with that line a great deal and was wondering why using:

Code: Select all

createImage(ECF_A8R8G8B8, destSize)
wouldn't that make a blank image? how does using a texture of a different resolution work and a blank one doesn't?

Also, yes it does produce a file name in this format: AMIBackground2.png800x600.png
But the cage only had "Warning: Vicious Lions" on it! Im a programmer! I only listen to errors!
DavidJE13
Posts: 165
Joined: Tue Jan 09, 2007 7:17 pm

Post by DavidJE13 »

the code isn't too complex - ignoring the beginning setup,

Code: Select all

IntTexture = this->videoDriver->addTexture(destSize, "IntermediateTexture");
Create a texture with the destination size. We already have SrcTexture which is the input texture.

Code: Select all

   SrcImage = this->videoDriver->createImageFromData(SrcTexture->getColorFormat(), SrcTexture->getSize(), SrcTexture->lock());
   DestImage = this->videoDriver->createImageFromData(SrcTexture->getColorFormat(), destSize, IntTexture->lock());
Create images from these textures - these images are *exactly* the same size as their textures. BlahTexture->lock() gives it a reference to the bytedata of the textures to initialise with. Your code omitting this bit doesn't work because it has no data to start with, and there is no stretching going on here.

Code: Select all

IntTexture->unlock();
   SrcImage->copyToScaling(DestImage);
   SrcTexture->unlock();
Here's the magic line! The destination image becomes a scaled version of SrcImage, and both textures are unlocked (always call unlock after a call to lock)

Code: Select all

this->videoDriver->removeTexture(IntTexture);
   IntTexture = this->videoDriver->addTexture(SrcName.c_str(), DestImage);
finally IntTexture is re-allocated. now it has size of the destination, and is set with the new scaled image data.

Not the most efficient function - "Intermediate Texture" is just wasted space, and it's using a static variable as a counter (to ensure each new texture has a unique name), which isn't the best practice.

As for your code, I see no blatant error; maybe you're calling it with the same image name twice? or running out of vram?
LordNyson
Posts: 31
Joined: Tue Nov 11, 2008 12:02 pm
Location: Perth, Australia

Post by LordNyson »

Basically there are two errors, if we don't get an error here =:

Code: Select all

   try
   {
		IntTexture = driver->addTexture(destSize, "IntermediateTexture"); 
		SrcImage = driver->createImageFromData(SrcTexture->getColorFormat(), SrcTexture->getSize(), SrcTexture->lock()); 
		DestImage = driver->createImageFromData(SrcTexture->getColorFormat(), destSize, IntTexture->lock());   
   }
   catch(...)
   {
		int temp = MessageBox(NULL, ((stringc)"Error in scaling image: " += image += (stringc)"\nThis can be caused by incorrect resolution settings.").c_str(),"Fatal Error",MB_OK | MB_ICONSTOP);
		return NULL;
   };
Which is fairly common, it will drop out into the main game loop and get an error when

Code: Select all

  gi->drawAll();
is called.

Really the only thought I have is that the dimensions being passed are invalid, so when the texture is returned and tried to be applied it screws up. But I have checked the debug data, it passes correct values, and you can tell that by the filename too...
But the cage only had "Warning: Vicious Lions" on it! Im a programmer! I only listen to errors!
Post Reply