2D images with rotation

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

2D images with rotation

Post by Lonesome Ducky »

Okay, well technically it's 3d, but that's because I wanted to be able to take advantage of hardware acceleration and such. But, it comes out exactly the same as its 2d counterpart.

EDIT: All fixes implemented, optimized, and cleaned up

Code: Select all

void draw2DImage(irr::video::IVideoDriver *driver, irr::video::ITexture* texture, irr::core::rect<irr::s32> sourceRect, irr::core::position2d<irr::s32> position, irr::core::position2d<irr::s32> rotationPoint, irr::f32 rotation, irr::core::vector2df scale, bool useAlphaChannel, irr::video::SColor color) {
 
        // Store and clear the projection matrix
        irr::core::matrix4 oldProjMat = driver->getTransform(irr::video::ETS_PROJECTION);
        driver->setTransform(irr::video::ETS_PROJECTION,irr::core::matrix4());
        
        // Store and clear the view matrix
        irr::core::matrix4 oldViewMat = driver->getTransform(irr::video::ETS_VIEW);
        driver->setTransform(irr::video::ETS_VIEW,irr::core::matrix4());
 
        // Store and clear the world matrix
        irr::core::matrix4 oldWorldMat = driver->getTransform(irr::video::ETS_WORLD);
        driver->setTransform(irr::video::ETS_WORLD,irr::core::matrix4());
 
        // Find horizontal and vertical axes after rotation
        irr::f32 c = cos(-rotation*irr::core::DEGTORAD);
        irr::f32 s = sin(-rotation*irr::core::DEGTORAD);
        irr::core::vector2df horizontalAxis(c,s);
        irr::core::vector2df verticalAxis(s,-c);
 
        // First, we'll find the offset of the center and then where the center would be after rotation
        irr::core::vector2df centerOffset(position.X+sourceRect.getWidth()/2.0f*scale.X-rotationPoint.X,position.Y+sourceRect.getHeight()/2.0f*scale.Y-rotationPoint.Y);
        irr::core::vector2df center = centerOffset.X*horizontalAxis - centerOffset.Y*verticalAxis;
        center.X += rotationPoint.X;
        center.Y += rotationPoint.Y;
 
        // Now find the corners based off the center
        irr::core::vector2df cornerOffset(sourceRect.getWidth()*scale.X/2.0f,sourceRect.getHeight()*scale.Y/2.0f);
        verticalAxis *= cornerOffset.Y;
        horizontalAxis *= cornerOffset.X;
        irr::core::vector2df corner[4];
        corner[0] = center + verticalAxis - horizontalAxis;
        corner[1] = center + verticalAxis + horizontalAxis;
        corner[2] = center - verticalAxis - horizontalAxis;
        corner[3] = center - verticalAxis + horizontalAxis;
 
        // Find the uv coordinates of the sourceRect
        irr::core::vector2df textureSize(texture->getSize().Width, texture->getSize().Height);
        irr::core::vector2df uvCorner[4];
        uvCorner[0] = irr::core::vector2df(sourceRect.UpperLeftCorner.X,sourceRect.UpperLeftCorner.Y);
        uvCorner[1] = irr::core::vector2df(sourceRect.LowerRightCorner.X,sourceRect.UpperLeftCorner.Y);
        uvCorner[2] = irr::core::vector2df(sourceRect.UpperLeftCorner.X,sourceRect.LowerRightCorner.Y);
        uvCorner[3] = irr::core::vector2df(sourceRect.LowerRightCorner.X,sourceRect.LowerRightCorner.Y);
        for (irr::s32 i = 0; i < 4; i++) 
                uvCorner[i] /= textureSize;
                
        // Vertices for the image
        irr::video::S3DVertex vertices[4];
        irr::u16 indices[6] = { 0, 1, 2, 3 ,2 ,1 };
 
        // Convert pixels to world coordinates
        irr::core::vector2df screenSize(driver->getViewPort().getWidth(), driver->getViewPort().getHeight());
        for (irr::s32 i = 0; i < 4; i++) {
                vertices[i].Pos = irr::core::vector3df(((corner[i].X/screenSize.X)-0.5f)*2.0f,((corner[i].Y/screenSize.Y)-0.5f)*-2.0f,1);
                vertices[i].TCoords = uvCorner[i];
                vertices[i].Color = color;
        }
 
        // Create the material
        // IMPORTANT: For irrlicht 1.8 and above you MUST ADD THIS LINE:
        // material.BlendOperation = irr::video::EBO_ADD;
        irr::video::SMaterial material;
        material.Lighting = false;
        material.ZWriteEnable = false;
        material.ZBuffer = false;
        material.BackfaceCulling = false;
        material.TextureLayer[0].Texture = texture;
        material.MaterialTypeParam = irr::video::pack_texureBlendFunc(irr::video::EBF_SRC_ALPHA, irr::video::EBF_ONE_MINUS_SRC_ALPHA, irr::video::EMFN_MODULATE_1X, irr::video::EAS_TEXTURE | irr::video::EAS_VERTEX_COLOR); 
        //material.BlendOperation = irr::video::EBO_ADD;
        if (useAlphaChannel)
                material.MaterialType = irr::video::EMT_ONETEXTURE_BLEND;
        else
                material.MaterialType = irr::video::EMT_SOLID;
 
        driver->setMaterial(material);
        driver->drawIndexedTriangleList(&vertices[0],4,&indices[0],2);
 
        // Restore projection, world, and view matrices
        driver->setTransform(irr::video::ETS_PROJECTION,oldProjMat);
        driver->setTransform(irr::video::ETS_VIEW,oldViewMat);
        driver->setTransform(irr::video::ETS_WORLD,oldWorldMat);
}
 
Last edited by Lonesome Ducky on Wed Oct 12, 2011 8:15 pm, edited 4 times in total.
wyrmmage
Posts: 204
Joined: Sun Mar 16, 2008 3:12 am
Contact:

Post by wyrmmage »

Nice! :)

Is this what you use in your 3D model to 2D sprite converter?
Last edited by wyrmmage on Tue Feb 17, 2009 10:07 pm, edited 1 time in total.
Worlds at War (Current Project) - http://www.awkward-games.com
Ganadu'r, The Eternal Sage (Other Current Project) - http://rpg.naget.com
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

Not yet, but I do plan on it. I'm gonna release a new version with a few more features, and I'll use this instead of what I had before.
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

Code: Select all

class cImage {
	rect<s32> ImageRect, OrigImageRect, TextureRect, BoundRect;
	position2d<s32> RotationPoint;
	float Rotation, OldRotation;
	ITexture* Texture;
	aabbox3d<f32> Box;
	S3DVertex Vertices[4];
	SMaterial Material;
	bool Transparent;
	SColor TransColor;
	SColor Color;
	vector2df Scale;
public:
	cImage(ITexture* texture, rect<s32> nsize, rect<s32> texpos)
	{
		Color = SColor(0,255,255,255);
		Rotation = 0;
		OldRotation = 1;
		Scale = vector2df(1,1);
		Texture = texture;
		Material.Wireframe = false;
		Material.Lighting = false;
		Material.ZBuffer = 0;
		Material.TextureLayer[0].Texture = Texture;
		ImageRect = nsize;
		OrigImageRect = ImageRect;
		TextureRect = texpos;
		position2d<s32> ulc = texpos.UpperLeftCorner;
		position2d<s32> lrc = texpos.LowerRightCorner;
		dimension2d<s32> td = texture->getSize();

		Vertices[0] = video::S3DVertex(-0.5,0.5,0, 1,1,0,
				video::SColor(255,255,255,255), (float)ulc.X/(float)td.Width, (float)ulc.Y/(float)td.Height);
		Vertices[1] = video::S3DVertex(0.5,0.5,0, 1,0,0,
				video::SColor(255,255,255,255), (float)lrc.X/(float)td.Width, (float)ulc.Y/(float)td.Height);
		Vertices[2] = video::S3DVertex(-0.5,-0.5,0, 0,1,1,
				video::SColor(255,255,255,255), (float)ulc.X/(float)td.Width, (float)lrc.Y/(float)td.Height);
		Vertices[3] = video::S3DVertex(0.5,-0.5,0, 0,0,1,
				video::SColor(255,255,255,255), (float)lrc.X/(float)td.Width, (float)lrc.Y/(float)td.Height);

		Box.reset(Vertices[0].Pos);
		for (s32 i=1; i<4; ++i)
			Box.addInternalPoint(Vertices[i].Pos);
		OrigImageRect = ImageRect;
	}
	void Draw(ISceneManager* SceneManager) {
		u16 indices[] = {	0,1,2,	3,2,1};
		video::IVideoDriver* driver = SceneManager->getVideoDriver();
		line3df rays[4];
		position2d<s32> pos[4];
		position2d<s32> imagpos[4];
		imagpos[0] = ImageRect.UpperLeftCorner;
		imagpos[1] = position2d<s32>(ImageRect.LowerRightCorner.X, ImageRect.UpperLeftCorner.Y);
		imagpos[2] = position2d<s32>(ImageRect.UpperLeftCorner.X,ImageRect.LowerRightCorner.Y);
		imagpos[3] = position2d<s32>(ImageRect.LowerRightCorner);
		float gx, gy, lx, ly;
		gx = imagpos[0].X;
		gy = imagpos[0].Y;
		lx = imagpos[0].X;
		ly = imagpos[0].Y;
		for (int x = 0; x < 4; x++) {
			if (imagpos[x].X > gx)
				gx = imagpos[x].X;
			if (imagpos[x].X < lx)
				lx = imagpos[x].X;
			if (imagpos[x].Y > gy)
				gy = imagpos[x].Y;
			if (imagpos[x].Y < ly)
				ly = imagpos[x].Y;
		}

		RotationPoint.X = (lx+gx)/2;
		RotationPoint.Y = (ly+gy)/2;		
		float angles[4];
		float ed[4];
		for (int x = 0; x < 4; x++) {
			angles[x] = atan2((float)imagpos[x].Y-RotationPoint.Y,(float)imagpos[x].X-RotationPoint.X);
			ed[x] = sqrt((float)((RotationPoint.X-imagpos[x].X)*(RotationPoint.X-imagpos[x].X)) + ((RotationPoint.Y-imagpos[x].Y)*(RotationPoint.Y-imagpos[x].Y)));
			float realang = angles[x] + Rotation*DEGTORAD;
			imagpos[x].X = RotationPoint.X+cos(realang)*ed[x];
			imagpos[x].Y = RotationPoint.Y+sin(realang)*ed[x];
		}
		gx = imagpos[0].X;
		gy = imagpos[0].Y;
		lx = imagpos[0].X;
		ly = imagpos[0].Y;
		for (int x = 0; x < 4; x++) {
			if (imagpos[x].X > gx)
				gx = imagpos[x].X;
			if (imagpos[x].X < lx)
				lx = imagpos[x].X;
			if (imagpos[x].Y > gy)
				gy = imagpos[x].Y;
			if (imagpos[x].Y < ly)
				ly = imagpos[x].Y;
		}
		BoundRect = rect<s32>(lx,ly,gx,gy);
		rays[0] = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(imagpos[0],SceneManager->getActiveCamera());
		rays[1] = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(imagpos[1],SceneManager->getActiveCamera());
		rays[2] = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(imagpos[2],SceneManager->getActiveCamera());
		rays[3] = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(imagpos[3],SceneManager->getActiveCamera());
		float dist = rays[0].end.getDistanceFrom(SceneManager->getActiveCamera()->getPosition());
		float div = dist/((SceneManager->getActiveCamera()->getNearValue()+1)*(SceneManager->getActiveCamera()->getNearValue()+1));		
		for (int x = 0; x < 4; x++) {
			float xd,yd,zd;
			xd = rays[x].end.X - rays[x].start.X;
			yd = rays[x].end.Y - rays[x].start.Y;
			zd = rays[x].end.Z - rays[x].start.Z;

			rays[x].start.X += (xd/div);
			rays[x].start.Y += (yd/div);
			rays[x].start.Z += (zd/div);
			Vertices[x].Pos = rays[x].start;
		}

	    driver->setMaterial(Material);
		matrix4 mat;
		driver->setTransform(video::ETS_WORLD, mat);
        driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4);	
	}
	void SetTransparent(bool trans) { 
		Transparent = trans; 
		if (Transparent)
			Material.MaterialType = EMT_TRANSPARENT_ALPHA_CHANNEL;
		else
			Material.MaterialType = EMT_SOLID;
	};
	bool GetTransparent() { return Transparent; };
	void SetTransparentColor(SColor trans, IVideoDriver *driver) { 
		TransColor = trans; 
		driver->makeColorKeyTexture(Texture,TransColor); 
	};
	void SetPosition(position2d<s32> newpos) {
		float xd, yd;
		xd = newpos.X - ImageRect.UpperLeftCorner.X;
		yd = newpos.Y - ImageRect.UpperLeftCorner.Y;
		ImageRect = rect<s32>(ImageRect.UpperLeftCorner.X+xd,ImageRect.UpperLeftCorner.Y+yd,ImageRect.LowerRightCorner.X+xd,ImageRect.LowerRightCorner.Y+yd);
		OrigImageRect = rect<s32>(OrigImageRect.UpperLeftCorner.X+xd,OrigImageRect.UpperLeftCorner.Y+yd,OrigImageRect.LowerRightCorner.X+xd,OrigImageRect.LowerRightCorner.Y+yd);	
	}
	void SetColor(SColor newc) {
		Color = newc;
		for (int x = 0; x < 4; x++) {
			Vertices[x].Color = Color;
		}
	}
	SColor GetColor() { return Color; };
	SColor GetTransparentColor() { return TransColor; };
	void SetBilinearFilter(bool on) { Material.TextureLayer[0].BilinearFilter = on; };
	void SetTrilinearFilter(bool on) { Material.TextureLayer[0].TrilinearFilter = on; };
	void SetAnisotropicFilter(bool on) { Material.TextureLayer[0].AnisotropicFilter = on; };
	bool GetBilinearFilter() { return Material.TextureLayer[0].BilinearFilter; };
	bool GetTrilinearFilter() { return Material.TextureLayer[0].TrilinearFilter; };
	bool GetAnisotropicFilter() { return Material.TextureLayer[0].AnisotropicFilter; };
	void SetRotation(float newrot) { Rotation = newrot; };
	float GetRotation() { return Rotation; };
	int GetWidth() { return ImageRect.UpperLeftCorner.X-ImageRect.LowerRightCorner.X; };
	int GetHeight() { return ImageRect.UpperLeftCorner.Y-ImageRect.LowerRightCorner.Y; };
	int GetOrigWidth() { return OrigImageRect.UpperLeftCorner.X-ImageRect.LowerRightCorner.X; };
	int GetOrigHeight() { return OrigImageRect.UpperLeftCorner.Y-ImageRect.LowerRightCorner.Y; };
	void SetTexture(ITexture* tex) { Texture = tex; Material.TextureLayer[0].Texture = Texture; };
	rect<s32> GetBoundRect() { return BoundRect; };
	void SetScale(vector2df news) {
		Scale = news;
		ImageRect = rect<s32>(OrigImageRect.UpperLeftCorner.X, OrigImageRect.UpperLeftCorner.Y, OrigImageRect.UpperLeftCorner.X+(this->GetOrigWidth()*news.X), OrigImageRect.UpperLeftCorner.Y+(this->GetOrigHeight()*news.Y));
	}
	ITexture *GetTexture() { return Texture; };
};
You can now scale the image, change the color, and get the bounding rectangle.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Why not make something that fits into the GUI framework (i.e., something that inherits from IGUIElement)? Perhaps something like this or this.

Travis
FuzzYspo0N
Posts: 914
Joined: Fri Aug 03, 2007 12:43 pm
Location: South Africa
Contact:

Post by FuzzYspo0N »

this is a cool resource, thanks for it.
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

vitek wrote:Why not make something that fits into the GUI framework (i.e., something that inherits from IGUIElement)? Perhaps something like this or this.

Travis
I think I'll do that, I just thought before that it would be nicer to have it separate but I do see the advantages.
FuzzYspo0N wrote:this is a cool resource, thanks for it.
You're welcome :)
zshe41
Posts: 2
Joined: Thu Oct 29, 2009 11:17 pm

Post by zshe41 »

This is exactly what I need. Thank you for your work.

However, I have problem implementing it.
I paste the code into Dev C++ and i got several errors.

Code: Select all

43 C:\irrlicht1.6\examples\06.2DGraphics - Copy\main.cpp conversion from `const irr::core::dimension2d<irr::u32>' to non-scalar type `irr::core::dimension2d<irr::s32>' requested  
error on line: dimension2d<s32> td = texture->getSize();

Is there something i missed when I copy paste?
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

You'll need to change that from dimension2d<s32> to dimension2d<u32>. Recent changes in Irrlicht changed many of the functions that returned dimension2d<s32> to dimension2d<u32>. So if you just change it it should work just fine :D
zshe41
Posts: 2
Joined: Thu Oct 29, 2009 11:17 pm

Post by zshe41 »

Thank you very much for the codes and helps.
roelor
Posts: 240
Joined: Wed Aug 13, 2008 8:06 am

Post by roelor »

Well, it doesn't work for me, it states that ISO c++ forbids declaration of 'rect' with no type, thats this: " rect<u32> ImageRect, OrigImageRect, TextureRect, BoundRect;" line.
same goes for position2d and other similarities.
It also states: expected ; before < token.
(please note that my knowledge is limited about c++ and even moreso about irrlicht)
(I added this to the 2d example)
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

You don't need to use rect<u32>, it should be left as rect<s32>. Only dimension<s32> needs to be changed. And you may be missing a namespace.
arnir
Competition winner
Posts: 154
Joined: Sat Jan 20, 2007 4:36 pm
Location: Czech Republic

Post by arnir »

wow great! :wink:
your code is best of "image with rotation" codes I think :P

but now Iam making this code working with irrlicht 1.7.1 but my app every time crash... (I think on line: driver->drawIndexedTriangleList() )

and I must add many (s32)() conversions, is it wrong?

do you have working 1.7.1 version?
thanks
programmer is bad designer
designer is bad programmer
mylesb
Posts: 1
Joined: Mon Sep 06, 2010 2:56 am
Location: Australia
Contact:

Post by mylesb »

Hi guys,
This is my first post :)
I would also like to know if this works with 1.7.1 because it crashes for me.

Cheers,
Myles Blasonato.
Game Designer / C++ Programmer
Sundar
Posts: 84
Joined: Mon Jun 05, 2006 11:05 am

Post by Sundar »

Yes. It was crashing for me also in drawVertexPrimitiveList and i have found a fix (irrlicht version 1.7.1)

The documentation for drawVertexPrimitiveList states that the fourth parameter is usually no of indices/3 . our total no of indice is 6.


so in Draw function

instead of this

Code: Select all

driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4); 
you call this

Code: Select all

driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 2); 
the crash goes away
Post Reply