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.

2D images with rotation

Postby Lonesome Ducky » Sun Feb 15, 2009 2:09 am

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

cpp 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.
User avatar
Lonesome Ducky
Competition winner
 
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Postby wyrmmage » Tue Feb 17, 2009 9:59 pm

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
User avatar
wyrmmage
 
Posts: 204
Joined: Sun Mar 16, 2008 3:12 am

Postby Lonesome Ducky » Tue Feb 17, 2009 10:01 pm

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.
User avatar
Lonesome Ducky
Competition winner
 
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Postby Lonesome Ducky » Wed Feb 18, 2009 3:13 am

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.
User avatar
Lonesome Ducky
Competition winner
 
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Postby vitek » Wed Feb 18, 2009 5:56 am

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

Travis
User avatar
vitek
Bug Slayer
 
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Postby FuzzYspo0N » Wed Feb 18, 2009 8:08 am

this is a cool resource, thanks for it.
User avatar
FuzzYspo0N
 
Posts: 914
Joined: Fri Aug 03, 2007 12:43 pm
Location: South Africa

Postby Lonesome Ducky » Wed Feb 18, 2009 2:20 pm

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 :)
User avatar
Lonesome Ducky
Competition winner
 
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Postby zshe41 » Thu Oct 29, 2009 11:47 pm

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?
zshe41
 
Posts: 2
Joined: Thu Oct 29, 2009 11:17 pm

Postby Lonesome Ducky » Fri Oct 30, 2009 1:23 am

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
User avatar
Lonesome Ducky
Competition winner
 
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Postby zshe41 » Thu Nov 05, 2009 6:24 pm

Thank you very much for the codes and helps.
zshe41
 
Posts: 2
Joined: Thu Oct 29, 2009 11:17 pm

Postby roelor » Sun Nov 08, 2009 8:37 pm

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)
( : I like the old school text smileys best! : )
User avatar
roelor
 
Posts: 236
Joined: Wed Aug 13, 2008 8:06 am

Postby Lonesome Ducky » Sun Nov 08, 2009 9:04 pm

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.
User avatar
Lonesome Ducky
Competition winner
 
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Postby arnir » Thu Jun 24, 2010 7:17 pm

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
arnir
Competition winner
 
Posts: 134
Joined: Sat Jan 20, 2007 4:36 pm
Location: Czech Republic

Postby mylesb » Mon Sep 06, 2010 1:41 pm

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
User avatar
mylesb
 
Posts: 1
Joined: Mon Sep 06, 2010 2:56 am
Location: Australia

Postby Sundar » Tue Sep 07, 2010 1:34 pm

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
Sundar
 
Posts: 84
Joined: Mon Jun 05, 2006 11:05 am

Next

Return to Code Snippets

Who is online

Users browsing this forum: No registered users and 1 guest