Manipulate Textures - Blitting - Copying - Drawing - etc.

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
Post Reply
nebukadnezzar
Posts: 25
Joined: Tue Dec 02, 2003 7:45 pm
Location: Germany - Bornheim

Manipulate Textures - Blitting - Copying - Drawing - etc.

Post by nebukadnezzar »

I am new to the Irrlicht engine but after only two hours of working with it i searched for functions to manipulate textures - but I found: none.


So I started writing them and I am going to publish them here


I have written them in MSVC++6 - so they maybe have to be worked out for cross-platform development

(maybe you got some Improvments)

Code: Select all

video::ITexture* dplTexture(video::ITexture *tex, c8* name)
// Duplicates a texture.
// parameters: the Texture to Duplicate and the name for the new one
{
	if (!tex) return NULL;
	
	video::ITexture *tmp = device->getVideoDriver()->addTexture(tex->getDimension(),name);

	if (tex->getColorFormat() != tmp->getColorFormat()) return NULL;

	s32 pitch = tex->getPitch() ;
	s32 height = tex->getDimension().Height;

	c8 *s = (c8*) tex->lock();
	c8 *d = (c8*) tmp->lock();

	memcpy(d ,s ,pitch*height);

	tmp->unlock();
	tex->unlock();
	
	return tmp;
};


s32 BlitTexture(video::ITexture *dest, video::ITexture *src, core::rect<s32> destrec, core::rect<s32> srcrec )
//Blits a texture (or a part of it) to another
//parameters: destination and source texture and the destiantion and source rectangle
{
	if ( (!dest) || (!src)) return 0;
	if (src->getColorFormat() != dest->getColorFormat()) return 0;

	s32 spitch = src->getPitch();
	s32 dpitch = dest->getPitch();
	
	s32 pixsize = spitch / src->getDimension().Width;
	if (pixsize != (dpitch / dest->getDimension().Width)) return 0;

	destrec.clipAgainst(core::rect<s32>(core::position2d<s32>(0,0),dest->getDimension()) );
  	srcrec.clipAgainst(core::rect<s32>(core::position2d<s32>(0,0),src->getDimension()) );

	core::rect<s32> cprec(srcrec);
	cprec.clipAgainst(destrec);	

	s32 newpitch = pixsize * cprec.getWidth();

	c8 *s = (c8*) src->lock();
	c8 *d = (c8*) dest->lock();

	for (s32 i = 0; i < cprec.getHeight(); i++)
		memcpy(
			d + ((destrec.UpperLeftCorner.Y + i) * dpitch) + (pixsize * destrec.UpperLeftCorner.X) ,
			s + ((srcrec.UpperLeftCorner.Y + i) * spitch) + (pixsize * srcrec.UpperLeftCorner.X),newpitch );

	src->unlock();
	dest->unlock();
	
	return 1;
};



s32 StretchTextureFast(video::ITexture *dest, video::ITexture *src, core::rect<s32> destrec, core::rect<s32> srcrec )
//Stretch a textures (to size of destrec) and blits it to another
//parameters: destination and source texture and the destiantion and source rectangle
//Remarks: Its so fast because of fix point arithmethic and NO filtering (means pixel doubling)
{
	if ( (!dest) || (!src)) return 0;
	if (src->getColorFormat() != dest->getColorFormat()) return 0;

	s32 spitch = src->getPitch();
	s32 dpitch = dest->getPitch();
	
	s32 pixsize = spitch / src->getDimension().Width;
	if (pixsize != (dpitch / dest->getDimension().Width)) return 0;

	u32 yscale = (destrec.getHeight() << 16) / srcrec.getHeight();
	u32 xscale = (destrec.getWidth() << 16) / srcrec.getWidth();

	c8 *s = (c8*) src->lock();
	c8 *d = (c8*) dest->lock();

	for (s32 i = 0; i < destrec.getHeight(); i++)
		for (s32 j = 0; j < destrec.getWidth();j++)
		{
			memcpy(
					d + ((destrec.UpperLeftCorner.Y + i) * dpitch) + (pixsize * (destrec.UpperLeftCorner.X + j)) ,
					s + ((srcrec.UpperLeftCorner.Y + ((i << 16) / yscale)) * spitch) + (pixsize * (srcrec.UpperLeftCorner.X + ((j << 16) / xscale))),
					pixsize);

		}

	src->unlock();
	dest->unlock();
	
	return 1;
};
at next i am going for transparent blitting and stretching with resampling

--sorry for my bad english, i am from germany--
Last edited by nebukadnezzar on Thu Dec 04, 2003 8:31 pm, edited 1 time in total.
niko
Site Admin
Posts: 1759
Joined: Fri Aug 22, 2003 4:44 am
Location: Vienna, Austria
Contact:

Post by niko »

Cool, very useful. :)
nebukadnezzar
Posts: 25
Joined: Tue Dec 02, 2003 7:45 pm
Location: Germany - Bornheim

Post by nebukadnezzar »

Here is the code for the transparent blitting.
there are two versions:
one expects a colorvalue for deciding wich color is transparent
and the other expects the position where the transparent color is

Code: Select all

s32 TransBlitTexture(video::ITexture *dest, video::ITexture *src, core::rect<s32> destrec, core::rect<s32> srcrec,video::SColor *transcolor)
//blits a texture witch a transparent color to another
//parameters: destination + source texture;destiantion + source rectangle;and the colorvalue to be transparent
//Remarks: can't cope EHCF_R5G6B5 format
{
	if ( (!dest) || (!src)) return 0;
	if (src->getColorFormat() != dest->getColorFormat()) return 0;

	s32 spitch = src->getPitch();
	s32 dpitch = dest->getPitch();
	
	s32 pixsize = spitch / src->getDimension().Width;
	if (pixsize != (dpitch / dest->getDimension().Width)) return 0;

	destrec.clipAgainst(core::rect<s32>(core::position2d<s32>(0,0),dest->getDimension()) );
  	srcrec.clipAgainst(core::rect<s32>(core::position2d<s32>(0,0),src->getDimension()) );

	core::rect<s32> cprec(srcrec);
	cprec.clipAgainst(destrec);	

	c8 *trans = (c8*) malloc(pixsize);

	switch (src->getColorFormat())
	{
	case video::EHCF_R5G5B5: *trans = transcolor->toA1R5G5B5();
		break;
	case video::EHCF_R5G6B5: return 0; //IS THERE A WAY TO GET THIS FORMAT FROM SCOLOR ???
		break;
	case video::EHCF_A8R8G8B8: *trans = transcolor->color;
		break;
	default: return 0;
	}

	c8 *s = (c8*) src->lock();
	c8 *d = (c8*) dest->lock();
	c8 *tmp = (c8*) malloc(pixsize);

	for (s32 i = 0; i < cprec.getHeight(); i++)
		for (s32 j = 0; j < cprec.getWidth();j++)
		{
			memcpy(tmp,
					s + ((srcrec.UpperLeftCorner.Y + i) * spitch) + (pixsize * (srcrec.UpperLeftCorner.X + j)),
					pixsize);
		
			if (*tmp != *trans) memcpy(d + ((destrec.UpperLeftCorner.Y + i) * dpitch) + (pixsize * (destrec.UpperLeftCorner.X + j)),
					tmp,pixsize);
		}
	free(tmp);
	free(trans);

	src->unlock();
	dest->unlock();
	
	return 1;
};

s32 TransBlitTexture(video::ITexture *dest, video::ITexture *src, core::rect<s32> destrec, core::rect<s32> srcrec,core::position2d<s32> transpos = core::position2d<s32>(0,0) )
//blits a texture witch a transparent color to another
//parameters: destination + source texture;destiantion + source rectangle;the position where to find the transparent color
{
	if ( (!dest) || (!src)) return 0;
	if (src->getColorFormat() != dest->getColorFormat()) return 0;

	s32 spitch = src->getPitch();
	s32 dpitch = dest->getPitch();
	
	s32 pixsize = spitch / src->getDimension().Width;
	if (pixsize != (dpitch / dest->getDimension().Width)) return 0;

	destrec.clipAgainst(core::rect<s32>(core::position2d<s32>(0,0),dest->getDimension()) );
  	srcrec.clipAgainst(core::rect<s32>(core::position2d<s32>(0,0),src->getDimension()) );

	core::rect<s32> cprec(srcrec);
	cprec.clipAgainst(destrec);	

	c8 *trans = (c8*) malloc(pixsize);
	c8 *s = (c8*) src->lock();
	c8 *d = (c8*) dest->lock();
	c8 *tmp = (c8*) malloc(pixsize);

	memcpy(trans,s + (transpos.Y * spitch) + (transpos.X * pixsize),pixsize);

	for (s32 i = 0; i < cprec.getHeight(); i++)
		for (s32 j = 0; j < cprec.getWidth();j++)		{
			memcpy(tmp,
					s + ((srcrec.UpperLeftCorner.Y + i) * spitch) + (pixsize * (srcrec.UpperLeftCorner.X + j)),
					pixsize);
		
			if (*tmp != *trans) memcpy(d + ((destrec.UpperLeftCorner.Y + i) * dpitch) + (pixsize * (destrec.UpperLeftCorner.X + j)),
					tmp,pixsize);
		}
	free(tmp);
	free(trans);

	src->unlock();
	dest->unlock();
	
	return 1;
};
rt
Posts: 150
Joined: Sun Nov 30, 2003 6:54 am
Location: canada
Contact:

example

Post by rt »

could you give and example of how to use 'StretchTextureFast'? for example, loading a 32x32 texture, and then stretching it to 800x600 and rendering it to screen? specifically, how are you creating the destination ITexture?

this is how i think it will go, please correct anything i get wrong:


thanks! :)

Code: Select all

	irr::video::ITexture* dest = ????????
	irr::video::ITexture* orig = grr.driver->getTexture("somegraphic.bmp");
	driver->makeColorKeyTexture(orig, irr::video::SColor(255,255,255,255));
	StretchTextureFast(dest,orig,irr::core::rect<irr::s32>(0,0,800,600),irr::core::rect<irr::s32>(0,0,32,32));
   orig->drop();
...
		device->getVideoDriver()->draw2DImage(dest,irr::core::position2d<s32>(0,0),irr::core::rect<s32>(0,0,800,600),NULL,irr::video::SColor(255,255,255,255),true); 

nebukadnezzar
Posts: 25
Joined: Tue Dec 02, 2003 7:45 pm
Location: Germany - Bornheim

Post by nebukadnezzar »

oyu should use the addTexture() function provided by the driver
see api doc http://irrlicht.sourceforge.net/docu/cl ... er.html#a8

Code: Select all

   irr::video::ITexture* dest = grr.driver->addTetxture(irr::core::dimesnion2d<s32>(800,600),"newTex");
   irr::video::ITexture* orig = grr.driver->getTexture("somegraphic.bmp"); 
   driver->makeColorKeyTexture(orig, irr::video::SColor(255,255,255,255)); 
   StretchTextureFast(dest,orig,irr::core::rect<irr::s32>(0,0,800,600),irr::core::rect<irr::s32>(0,0,32,32)); 
   orig->drop(); 
... 
      device->getVideoDriver()->draw2DImage(dest,irr::core::position2d<s32>(0,0),irr::core::rect<s32>(0,0,800,600),NULL,irr::video::SColor(255,255,255,255),true); 
 
nebukadnezzar
Posts: 25
Joined: Tue Dec 02, 2003 7:45 pm
Location: Germany - Bornheim

Post by nebukadnezzar »

I think i made a serious mistake:
the clipping of the source rectangle against the destination rectangle (=cprect) is wrong
i used this to get the width and height of the rectangle to copy - but instead you have to get it by __min(destrect.getWidth(),srcrect.getWidth()); (similar for Height)
and use this value for the loops

(this bug is in everyfunction except the StretchBlitTextureFast() )
rt
Posts: 150
Joined: Sun Nov 30, 2003 6:54 am
Location: canada
Contact:

more stuff

Post by rt »

unless you already have a FlipTexture function here is one i wrote.. it's the first thing that out of my head so it might not be the best way to do it

Code: Select all

// flips a texture upsidedown
irr::s32 FlipTexture(irr::video::ITexture *tex) {
   if ( (!tex) ) return 0; 

   irr::s32 dpitch = tex->getPitch(); 
   irr::u32 *d = (irr::u32*) tex->lock(); 
   irr::core::dimension2d<s32> size = tex->getSize();
	//construct the new image
    //slow method
/*	for (irr::s32 i = 0; i < size.getHeight()/2;++i) 
		for (irr::s32 j = 0; j < texsize.getWidth;++j) {
			DWORD temp = *(d+j + dpitch*i/4);
            *(d+j + dpitch*i/4) = *( (d+j)+dpitch*(texsize.getHeight-(i+1))/4 );
			*( (d+j)+dpitch*(texsize.getHeight-(i+1))/4 ) = temp;
		}
*/	
   //faster method
	irr::u8* temp = new irr::u8[size.Width*4];
	for (irr::s32 i = 0; i < size.Height/2;++i) {
		memcpy( temp , (d + dpitch*i/4) , size.Width*4);
		memcpy( (d+dpitch*i/4) , (d+dpitch*(size.Height-(i+1))/4) , size.Width*4 );
		memcpy( (d+dpitch*(size.Height-(i+1))/4) , temp , size.Width*4 );
	}
	delete[] temp;
	tex->unlock(); 
	return 1; 
} 
knightoflight
Posts: 199
Joined: Sun Aug 24, 2003 5:47 pm
Location: Germany

Post by knightoflight »

i found another bug in the TransBlit...-Functions, they dont blit some colours. Its cause the
if (*tmp != *trans) memcpy(d +...
only tests the first byte of the colour-bytes.
For example something like
if ((tmp[0] != trans[0]) || (tmp[1] != trans[1]) ) ...
and switched for other pixsize
Guest

Post by Guest »

i think it would be better to use the memcmp() function
knightoflight
Posts: 199
Joined: Sun Aug 24, 2003 5:47 pm
Location: Germany

Post by knightoflight »

to the lines of Mr.guest:
theres always many ways but yes, it seems to be the best solution
if (memcmp(tmp, trans, pixsize ) !=0 ) memcpy(d ...
playerdark
Posts: 64
Joined: Mon Aug 01, 2005 5:06 am

Post by playerdark »

Not to push this topic or so, but I just ran into the same problems: I was in need of a few simple blit operations and found nothing. The routines provided here work well (well at least so far as I have used them yet :D ) and I am very glad I found them here. Wouldn't it be a good idea to include these routines in the next version of Irrlicht? It's a common problem and I am sure many people are missing this kind of routines
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

There are some similar routines [executeBlit_*] in CImage.cpp that are used for blitting. It would be nice if that blitter code was exposed publicly and open for extension.

Travis
Niko40
Posts: 1
Joined: Mon Jan 29, 2007 7:09 pm
Location: Finland

Post by Niko40 »

Now. This is not about IrrLicht but I really need help with this and I don't know, where to start asking. But this seemed to be the right place to try.

The case is this: There is one new programming language called CoolBasic (and it has only about 1000 users, including me. It is not able to do alpha blend (no hardware support) and it has no 3d possibilities). It is barely possible to make a simple dll call. CB builds quite slow exe:s and it pushed me to look power from dll:s. CB is able to draw 2d images fast but with pixel manipulation to the images, it's hopeless. So I'm now looking a way to do the manipulation inside a dll. I may be able to get the pointer to the image and image's color format. Now the only problem, before I can test my theory, is that I do not have even the smallest idea about how to use the pointer to get the RGBA values from memory.

What do the IrrLicht Lock() function return?
tbedran
Posts: 5
Joined: Wed Nov 08, 2006 8:54 pm

Post by tbedran »

I get an error when I use your code. The complier says that it tried to write to memory that we did not have access too.

We copy/pasted your code.

src->getDimension() did not exist
we replaced with getSize() which should have worked.

: (
Post Reply