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

Post by Lonesome Ducky »

I actually have much better code for accomplishing this if you're still interested:

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.TextureLayer[0].Texture = texture;
	//material.TextureLayer[0].TextureWrap = 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);

}
arnir
Competition winner
Posts: 154
Joined: Sat Jan 20, 2007 4:36 pm
Location: Czech Republic

Post by arnir »

wow great, excellent!
finally working code for me :D
programmer is bad designer
designer is bad programmer
Josh1billion
Posts: 125
Joined: Thu Dec 11, 2008 9:50 pm
Location: Wisconsin
Contact:

Post by Josh1billion »

I'm trying to use this new draw2DImage() function in conjunction with rendering-to-texture, but they're not entirely compatible, so many weird glitches are arising. Can anyone (with more Irrlicht experience than me) try and update it? Thanks in advance if so.
www.JoshForde.com

Latest release: Super Orbulite World.
In development: Season of Dreams and others
Josh1billion
Posts: 125
Joined: Thu Dec 11, 2008 9:50 pm
Location: Wisconsin
Contact:

Post by Josh1billion »

Sorry for the double-post, but does anyone at least have any idea on what would need to be changed to make this render-to-texture compatible?

So far, I've changed this:

Code: Select all

   float screenWidth = driver->getScreenSize().Width; 
   float screenHeight = driver->getScreenSize().Height; 
to the width and height of the render-to-texture texture, i.e.:

Code: Select all

   float screenWidth = 200; 
   float screenHeight = 200; 
I don't have any experience in this sort of low[er]-level stuff, so I have no idea what else needs to be changed for it to be render-to-texture compatible... Any help at all would be greatly appreciated, as this is a very important feature in my game, and I'm very stuck on it. :) Thanks.
www.JoshForde.com

Latest release: Super Orbulite World.
In development: Season of Dreams and others
Josh1billion
Posts: 125
Joined: Thu Dec 11, 2008 9:50 pm
Location: Wisconsin
Contact:

Post by Josh1billion »

Got it! A render-to-texture compatible version of the draw2DImage function that Lonesome Ducky posted earlier.

Many thanks to Keless for helping me over IM to figure out what the RTT incompatibility was.

Replace RTT_WIDTH and RTT_HEIGHT to the width and height of the texture that is being rendered to (not the width and height of the image being drawn, but of the texture onto which it is being drawn).

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

   // 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 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 = RTT_WIDTH;
   float screenHeight = RTT_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.TextureLayer[0].TextureWrap = 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); 
   driver->setTransform(irr::video::ETS_WORLD,oldWorldMat);

}


www.JoshForde.com

Latest release: Super Orbulite World.
In development: Season of Dreams and others
mrdoubleb
Posts: 9
Joined: Tue Apr 12, 2011 1:10 pm

Post by mrdoubleb »

This works great only problem i have no i that it gets drawn behind other things. So when i have a map/terrain i cant see it because its behind it. How can i fix that?
Masterhawk
Posts: 299
Joined: Mon Nov 27, 2006 6:52 pm
Location: GERMANY
Contact:

Post by Masterhawk »

what about calling it after "smgr->drawAll()" ?
Image
mrdoubleb
Posts: 9
Joined: Tue Apr 12, 2011 1:10 pm

Post by mrdoubleb »

Masterhawk wrote:what about calling it after "smgr->drawAll()" ?
its already called after smgr->drawAll() its part of a HUD in game.

I draw another image that works fine with the normal. (driver->draw2DImage)

below that image i use the function suplyed above it draws but it appears behind everything.
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

I've fixed it getting drawn behind things it shouldn't (by disabling zbuffer for it, which I should have done already in hindsight) and made it be able to use the texture's alpha and combine it with the alpha you supply through the color value.

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);
}
mrdoubleb
Posts: 9
Joined: Tue Apr 12, 2011 1:10 pm

Post by mrdoubleb »

Lonesome Ducky wrote:I've fixed it getting drawn behind things it shouldn't (by disabling zbuffer for it, which I should have done already in hindsight) and made it be able to use the texture's alpha and combine it with the alpha you supply through the color value. //Code//
Great! thanks.

i had to add somethings though:

at top:

Code: Select all

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

Code: Select all

driver->setTransform(irr::video::ETS_WORLD,oldWorldMat); 
like mentioned in posts aboved but it works now! Thanks!

My code now:

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

   // 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 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);
   driver->setTransform(irr::video::ETS_WORLD,oldWorldMat);
}
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Re: 2D images with rotation

Post by Lonesome Ducky »

I have written the completed version of this snippet. I have incorporated all fixes mentioned, and optimized it from 8 sin/cos calls to 2, so it is less computationally intensive. The code is also cleaned up a bit and should be easier to understand. Here you go! :D

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);
}
 
 
SGH
Posts: 13
Joined: Wed Aug 24, 2011 2:53 pm

Re: 2D images with rotation

Post by SGH »

Got tired to have a lot of warnings in the console and to have to "using" every namespace. I want to share the final file with you:

Code: Select all

#include <irrlicht.h>
class cImage {
        irr::core::recti ImageRect, OrigImageRect, TextureRect, BoundRect;
        irr::core::position2di RotationPoint;
        irr::f32 Rotation, OldRotation;
        irr::video::ITexture* Texture;
        irr::core::aabbox3df Box;
        irr::video::S3DVertex Vertices[4];
        irr::video::SMaterial Material;
        bool Transparent;
        irr::video::SColor TransColor;
        irr::video::SColor Color;
        irr::core::vector2df Scale;
public:
        cImage(irr::video::ITexture* texture, irr::core::recti nsize, irr::core::recti texpos)
        {
                Color = irr::video::SColor(0,255,255,255);
                Rotation = 0.f;
                OldRotation = 1.f;
                Scale = irr::core::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;
                irr::core::position2di ulc = texpos.UpperLeftCorner;
                irr::core::position2di lrc = texpos.LowerRightCorner;
                irr::core::dimension2du td = texture->getSize();
 
                Vertices[0] = irr::video::S3DVertex(-0.5,0.5,0, 1,1,0,
                        irr::video::SColor(255,255,255,255), (irr::f32)ulc.X/(irr::f32)td.Width, (irr::f32)ulc.Y/(irr::f32)td.Height);
                Vertices[1] = irr::video::S3DVertex(0.5,0.5,0, 1,0,0,
                        irr::video::SColor(255,255,255,255), (irr::f32)lrc.X/(irr::f32)td.Width, (irr::f32)ulc.Y/(irr::f32)td.Height);
                Vertices[2] = irr::video::S3DVertex(-0.5,-0.5,0, 0,1,1,
                        irr::video::SColor(255,255,255,255), (irr::f32)ulc.X/(irr::f32)td.Width, (irr::f32)lrc.Y/(irr::f32)td.Height);
                Vertices[3] = irr::video::S3DVertex(0.5,-0.5,0, 0,0,1,
                        irr::video::SColor(255,255,255,255), (irr::f32)lrc.X/(irr::f32)td.Width, (irr::f32)lrc.Y/(irr::f32)td.Height);
 
                Box.reset(Vertices[0].Pos);
                for (irr::u32 i=1; i<4; ++i)
                        Box.addInternalPoint(Vertices[i].Pos);
                OrigImageRect = ImageRect;
                switch(texture->getColorFormat())
                {
                case irr::video::ECF_A1R5G5B5:
                case irr::video::ECF_A8R8G8B8:
                case irr::video::ECF_A16B16G16R16F:
                case irr::video::ECF_A32B32G32R32F:
                        this->SetTransparent(true);
                        break;
                default:
                        this->SetTransparent(false);
                        break;
                }
        }
        void Draw(irr::scene::ISceneManager* SceneManager) {
                irr::u16 indices[] = {  0,1,2,  3,2,1};
                irr::video::IVideoDriver* driver = SceneManager->getVideoDriver();
                irr::core::line3df rays[4];
                irr::core::position2di pos[4];
                irr::core::position2di imagpos[4];
                imagpos[0] = ImageRect.UpperLeftCorner;
                imagpos[1] = irr::core::position2di(ImageRect.LowerRightCorner.X, ImageRect.UpperLeftCorner.Y);
                imagpos[2] = irr::core::position2di(ImageRect.UpperLeftCorner.X,ImageRect.LowerRightCorner.Y);
                imagpos[3] = irr::core::position2di(ImageRect.LowerRightCorner);
                irr::f32 gx, gy, lx, ly;
                gx = (irr::f32)imagpos[0].X;
                gy = (irr::f32)imagpos[0].Y;
                lx = (irr::f32)imagpos[0].X;
                ly = (irr::f32)imagpos[0].Y;
                for (irr::u16 x = 0; x < 4; x++) {
                        if (imagpos[x].X > gx)
                                gx = (irr::f32)imagpos[x].X;
                        if (imagpos[x].X < lx)
                                lx = (irr::f32)imagpos[x].X;
                        if (imagpos[x].Y > gy)
                                gy = (irr::f32)imagpos[x].Y;
                        if (imagpos[x].Y < ly)
                                ly = (irr::f32)imagpos[x].Y;
                }
                RotationPoint.X = (irr::s32)(lx+gx)/2;
                RotationPoint.Y = (irr::s32)(ly+gy)/2;          
                irr::f32 angles[4];
                irr::f32 ed[4];
                for (irr::u16 x = 0; x < 4; x++) {
                        angles[x] = atan2((irr::f32)imagpos[x].Y-RotationPoint.Y,(irr::f32)imagpos[x].X-RotationPoint.X);
                        ed[x] = sqrt((irr::f32)((RotationPoint.X-imagpos[x].X)*(RotationPoint.X-imagpos[x].X)) + ((RotationPoint.Y-imagpos[x].Y)*(RotationPoint.Y-imagpos[x].Y)));
                        irr::f32 realang = angles[x] + Rotation*irr::core::DEGTORAD;
                        imagpos[x].X = RotationPoint.X+(irr::s32)(cos(realang)*ed[x]);
                        imagpos[x].Y = RotationPoint.Y+(irr::s32)(sin(realang)*ed[x]);
                }
                gx = (irr::f32)imagpos[0].X;
                gy = (irr::f32)imagpos[0].Y;
                lx = (irr::f32)imagpos[0].X;
                ly = (irr::f32)imagpos[0].Y;
                for (irr::u16 x = 0; x < 4; x++) {
                        if (imagpos[x].X > gx)
                                gx = (irr::f32)imagpos[x].X;
                        if (imagpos[x].X < lx)
                                lx = (irr::f32)imagpos[x].X;
                        if (imagpos[x].Y > gy)
                                gy = (irr::f32)imagpos[x].Y;
                        if (imagpos[x].Y < ly)
                                ly = (irr::f32)imagpos[x].Y;
                }
                BoundRect = irr::core::recti((irr::s32)lx,(irr::s32)ly,(irr::s32)gx,(irr::s32)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());
                irr::f32 dist = rays[0].end.getDistanceFrom(SceneManager->getActiveCamera()->getPosition());
                irr::f32 div = dist/((SceneManager->getActiveCamera()->getNearValue()+1)*(SceneManager->getActiveCamera()->getNearValue()+1));          
                for (irr::u16 x = 0; x < 4; x++) {
                        irr::f32 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);
                irr::core::matrix4 mat;
                driver->setTransform(irr::video::ETS_WORLD, mat);
                driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4);       
        }
        void SetTransparent(bool trans) { 
                Transparent = trans; 
                if (Transparent)
                        Material.MaterialType = irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL;
                else
                        Material.MaterialType = irr::video::EMT_SOLID;
        };
        bool GetTransparent() { return Transparent; };
        void SetTransparentColor(irr::video::SColor trans, irr::video::IVideoDriver *driver) { 
                TransColor = trans; 
                driver->makeColorKeyTexture(Texture,TransColor); 
        };
        void SetPosition(irr::core::position2di newpos) {
                irr::f32 xd, yd;
                xd = irr::f32(newpos.X - ImageRect.UpperLeftCorner.X);
                yd = irr::f32(newpos.Y - ImageRect.UpperLeftCorner.Y);
                ImageRect = irr::core::recti(ImageRect.UpperLeftCorner.X+(irr::s32)xd,ImageRect.UpperLeftCorner.Y+(irr::s32)yd,ImageRect.LowerRightCorner.X+(irr::s32)xd,ImageRect.LowerRightCorner.Y+(irr::s32)yd);
                OrigImageRect = irr::core::recti(OrigImageRect.UpperLeftCorner.X+(irr::s32)xd,OrigImageRect.UpperLeftCorner.Y+(irr::s32)yd,OrigImageRect.LowerRightCorner.X+(irr::s32)xd,OrigImageRect.LowerRightCorner.Y+(irr::s32)yd);        
        }
        void SetColor(irr::video::SColor newc) {
                Color = newc;
                for (irr::u16 x = 0; x < 4; x++) {
                        Vertices[x].Color = Color;
                }
        }
        irr::video::SColor GetColor() { return Color; };
        irr::video::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 > 0; };
        void SetRotation(irr::f32 newrot) { Rotation = newrot; };
        irr::f32 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(irr::video::ITexture* tex) { Texture = tex; Material.TextureLayer[0].Texture = Texture; };
        irr::core::recti GetBoundRect() { return BoundRect; };
        void SetScale(irr::core::vector2df news) {
                Scale = news;
                ImageRect = irr::core::recti(OrigImageRect.UpperLeftCorner.X, OrigImageRect.UpperLeftCorner.Y, OrigImageRect.UpperLeftCorner.X+(irr::s32)(this->GetOrigWidth()*news.X), OrigImageRect.UpperLeftCorner.Y+(irr::s32)(this->GetOrigHeight()*news.Y));
        }
        irr::video::ITexture *GetTexture() { return Texture; };
};
I didn't "Fix" the eventual crash, because i don't notice it. Dunno.

EDIT: Damn, didn't notice the second page D: I leave the code in case you want to use it.
kiel814
Posts: 37
Joined: Mon May 23, 2011 4:30 pm

Re: 2D images with rotation

Post by kiel814 »

I started developing a 2D game and I wanted to flip characters horizontally without having to have 2 images of every character (looking to the right and looking to the left).
I thought that the code in this post would do the trick if I used negative values for the scale.
At first it didn't, but after a simple modification I was able to solve it.
If you are interested, here's the link:
http://irrlicht.sourceforge.net/forum/v ... 61#p258661

Regards!
swesoulc
Posts: 17
Joined: Tue Apr 03, 2007 10:05 am

Re: 2D images with rotation

Post by swesoulc »

So i've been having a wee bit of a problem here.
Been folling around with the draw2DImage function here to enhance my sprite animator with.

aaand i got , some kind of anomily happening. it's Always at the same frames.
So what it does is that it draws the square quite allright, the jagged edges i'd assume is from my laptops crappy grapics card ( then again, if i am wrong and that is something that is out of order as well, please do let me know how to adress it ) then on a few frames, it , jumpes sizes. And i will frace myself as that cause it's the best description. Now i've monitored the process and written out all screen cords, all vertices cords, all texture cords on each frame. And the SOB's are always 1-1. As they should. But darnit that dont stop me from seeing with my very eyes that the bloody Y cord likes to skip up a bit. Enough to grab a bit of the next frames texture coordinates.

So, any idea what this might be? I myself will go through the sprite animations code for getting texture co-ords but they have been working perfectly for quite a long while, and the only modification have been the addidtion of the draw2DImage as the primary rendering function. And that was just pasted in and given the needed variables.
Small notes.
i have not specified a camera, mipmap settings have not been set, AA is on. I have had same result with two versions of the draw2DImage , i am now on the latest one you posted.

EDIT

ok so I did some digging and the jaggedness is gone ( a small 1 instead of a 0 at the wrong place as usuall )
but the other problem still lingers. I've gone through each frame size and they are fixed at 100 - 100 px
I've uploaded a small exe to demonstrate my problem.
Last edited by swesoulc on Tue May 29, 2012 11:08 am, edited 1 time in total.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: 2D images with rotation

Post by CuteAlien »

Your test contains just the .exe, but for anyone to debug this we would need code to reproduce it (and with code I mean certainly an example that is already reduced to just the problem, not some large project with all the code).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply