Page 1 of 1

2D image rotation?

Posted: Fri Apr 08, 2011 6:25 pm
by RdR
Hello,

What is the best and easiest way to rotate and or scale a 2D image?
I want to create a HUD and need to rotate some images on the fly.

Posted: Sat Apr 09, 2011 6:02 am
by hendu
By using an image library intended for the purpose, like devil or imlib2 ;)

Posted: Sat Apr 09, 2011 10:18 am
by RdR
hendu wrote:By using an image library intended for the purpose, like devil or imlib2 ;)
I dont really want to create more dependencies, is there a good alternative when only using Irrilcht?

Posted: Sat Apr 09, 2011 12:21 pm
by greenya
RdR wrote:is there a good alternative when only using Irrilcht?
Yes. You can create plane and set texture. You can rotate plane, zooming is also will be a piece of cake if you use perspective camera. You should draw this UI after your main "smgr->drawAll()" call, to make UI to be always on top of 3d objects.

Posted: Sat Apr 09, 2011 12:30 pm
by RdR
greenya wrote:
RdR wrote:is there a good alternative when only using Irrilcht?
Yes. You can create plane and set texture. You can rotate place, zooming is also will be a piece of cake if you use perspective camera. You should draw this UI after your main "smgr->drawAll()" call, to make UI to be always on top of 3d objects.
Thanks for your comment, but do you have a simple example?

Posted: Sat Apr 09, 2011 2:09 pm
by cobra
I believe this is under the zlib license.

Code: Select all

// draw2DImage source from Lonesome Ducky
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)
{

   irr::video::SMaterial material;

   // 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());

   // Find the positions of corners
   irr::core::vector2df corner[4];

   corner[0] = irr::core::vector2df(position.X,position.Y);
   corner[1] = irr::core::vector2df(position.X+sourceRect.getWidth()*scale.X,position.Y);
   corner[2] = irr::core::vector2df(position.X,position.Y+sourceRect.getHeight()*scale.Y);
   corner[3] = irr::core::vector2df(position.X+sourceRect.getWidth()*scale.X,position.Y+sourceRect.getHeight()*scale.Y);

   // Rotate corners
   if (rotation != 0.0f)
      for (int x = 0; x < 4; x++)
         corner[x].rotateBy(rotation,irr::core::vector2df(rotationPoint.X, rotationPoint.Y));


   // Find the uv coordinates of the sourceRect
   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 (int x = 0; x < 4; x++) {
      float uvX = uvCorner[x].X/(float)texture->getSize().Width;
      float uvY = uvCorner[x].Y/(float)texture->getSize().Height;
      uvCorner[x] = irr::core::vector2df(uvX,uvY);
   }

   // Vertices for the image
   irr::video::S3DVertex vertices[4];
   irr::u16 indices[6] = { 0, 1, 2, 3 ,2 ,1 };

   // Convert pixels to world coordinates
   float screenWidth = driver->getScreenSize().Width;
   float screenHeight = driver->getScreenSize().Height;
   for (int x = 0; x < 4; x++) {
      float screenPosX = ((corner[x].X/screenWidth)-0.5f)*2.0f;
      float screenPosY = ((corner[x].Y/screenHeight)-0.5f)*-2.0f;
      vertices[x].Pos = irr::core::vector3df(screenPosX,screenPosY,1);
      vertices[x].TCoords = uvCorner[x];
      vertices[x].Color = color;
   }
   material.Lighting = false;
   material.ZWriteEnable = false;
   material.TextureLayer[0].Texture = texture;
   //material.
   //material.TextureLayer[0].TextureWrapU = irr::video::ETC_CLAMP;
   //material.TextureLayer[0].TextureWrapV = irr::video::ETC_CLAMP;

   if (useAlphaChannel)
      material.MaterialType = irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL;
   else
      material.MaterialType = irr::video::EMT_SOLID;

   driver->setMaterial(material);
   driver->drawIndexedTriangleList(&vertices[0],4,&indices[0],2);


   // Restore projection and view matrices
   driver->setTransform(irr::video::ETS_PROJECTION,oldProjMat);
   driver->setTransform(irr::video::ETS_VIEW,oldViewMat);

} 

Posted: Sun Apr 10, 2011 2:30 pm
by RdR
Thanks cobra, I used this function instead because the above function had a weird problem aswell.

Somehow it looks like its behind everything in the world.
Here some screenshots:

Image

If I look a bit up, so there is nothing between de camera and the image it looks good:
Image

If I draw a normal 2D image using driver->draw2DImage() ( which I cant rotate ), everything works fine.[/url]

Posted: Sun Apr 10, 2011 3:58 pm
by shadowslair
You need to draw the turret image after drawing the terrain. If you need to draw another turret over this one, you need to draw it after etc. In this case the draw call sequence matters.

Posted: Sun Apr 10, 2011 4:40 pm
by RdR
shadowslair wrote:You need to draw the turret image after drawing the terrain. If you need to draw another turret over this one, you need to draw it after etc. In this case the draw call sequence matters.
I am, else the other 2D images won't be visible right?
I'm drawing all the 2D images (not visible in this screenshot) after the terrain, and everything is displayed correctly except the one which i'm trying to rotate (with the above function)

Edit:
The right image is using the standard draw2Image() method, they are both drawed at the same time (same method)
Image

Posted: Tue Apr 12, 2011 9:37 pm
by Lonesome Ducky
Sorry for the very late reply, but you should make it completely disregard the zbuffer. Here's the updated code:

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) {
	
	irr::video::SMaterial material;

	// 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());

	// Find the positions of corners
	irr::core::vector2df corner[4];

	corner[0] = irr::core::vector2df(position.X,position.Y);
	corner[1] = irr::core::vector2df(position.X+sourceRect.getWidth()*scale.X,position.Y);
	corner[2] = irr::core::vector2df(position.X,position.Y+sourceRect.getHeight()*scale.Y);
	corner[3] = irr::core::vector2df(position.X+sourceRect.getWidth()*scale.X,position.Y+sourceRect.getHeight()*scale.Y);

	// Rotate corners
	if (rotation != 0.0f) 
		for (int x = 0; x < 4; x++)
			corner[x].rotateBy(rotation,irr::core::vector2df(rotationPoint.X, rotationPoint.Y));


	// Find the uv coordinates of the sourceRect
	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 (int x = 0; x < 4; x++) {
		float uvX = uvCorner[x].X/(float)texture->getSize().Width;
		float uvY = uvCorner[x].Y/(float)texture->getSize().Height;
		uvCorner[x] = irr::core::vector2df(uvX,uvY);
	}

	// Vertices for the image
	irr::video::S3DVertex vertices[4];
	irr::u16 indices[6] = { 0, 1, 2, 3 ,2 ,1 };

	// Convert pixels to world coordinates
	float screenWidth = driver->getScreenSize().Width;
	float screenHeight = driver->getScreenSize().Height;
	for (int x = 0; x < 4; x++) {
		float screenPosX = ((corner[x].X/screenWidth)-0.5f)*2.0f;
		float screenPosY = ((corner[x].Y/screenHeight)-0.5f)*-2.0f;
		vertices[x].Pos = irr::core::vector3df(screenPosX,screenPosY,1);
		vertices[x].TCoords = uvCorner[x];
		vertices[x].Color = color;
	}

	material.Lighting = false;
	material.ZWriteEnable = false;
	material.ZBuffer = 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); 

	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 and view matrices
	driver->setTransform(irr::video::ETS_PROJECTION,oldProjMat);
	driver->setTransform(irr::video::ETS_VIEW,oldViewMat);
}

Posted: Wed Apr 13, 2011 10:36 am
by RdR
Lonesome Ducky, thanks!
Disableing Zbuffer did the trick 8)