2D image mirroring

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
kiel814
Posts: 37
Joined: Mon May 23, 2011 4:30 pm

2D image mirroring

Post by kiel814 »

I am working on a 2D game and I'm looking for a simple way to mirror an image (player should look left instead of right).
I have seen some posts about rotation and transformation but it looks way too complicated...
Is there a simple way to do this without having to duplicate all the assets for the player animations?

Thank you guys in advance!
kiel814
Posts: 37
Joined: Mon May 23, 2011 4:30 pm

Re: 2D image mirroring

Post by kiel814 »

Oh... forgot to say I am using this to render the character:

rect<s32> sprite(currentFrame * size.X, 0, (currentFrame + 1) * size.X - 1, size.Y - 1);
driver->draw2DImage(image, position, sprite, 0, SColor(255, 255, 255, 255), true);
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Re: 2D image mirroring

Post by Lonesome Ducky »

I have no idea if this would actually work, but how about flipping the coordinates of the source rect?
kiel814
Posts: 37
Joined: Mon May 23, 2011 4:30 pm

Re: 2D image mirroring

Post by kiel814 »

Tried that.
Didn't work.

Thanks anyway ;)
kiel814
Posts: 37
Joined: Mon May 23, 2011 4:30 pm

Re: 2D image mirroring

Post by kiel814 »

I finally solved this issue using some code from Lonesome Ducky:
http://irrlicht.sourceforge.net/forum/v ... 8&start=15

My idea was to use negative scale values in order to flip the image.
Initially it didn't work. But after some trial an error, accidentally I figured that if the image is flipped (either horizontally or vertically) the triangles must be drawn in the opposite direction.
We do this by reordering the indices of the vertices.

So instead of:
irr::u16 indices[6] = { 0, 1, 2, 3, 2, 1 };

I do:
irr::u16 indices[6] = { 0, 2, 1, 3, 1, 2 };

But if the image is not flipped in any axis, or it is flipped in both axes, then the indices stay as in the original version.

If there's anybody interested, I can post the complete final code.
mnunesvsc
Posts: 22
Joined: Sun May 28, 2006 9:04 pm
Contact:

Re: 2D image mirroring

Post by mnunesvsc »

I'd like do use your cod on a project of mine, can you send to me or disponibilize it here.

thanks in advance.
kiel814
Posts: 37
Joined: Mon May 23, 2011 4:30 pm

Re: 2D image mirroring

Post by kiel814 »

Here's my code.

Code: Select all

void Animation::draw2DImage(IVideoDriver *driver, ITexture* texture,
        rect<s32> sourceRect,
        position2d<s32> position,
        position2d<s32> rotationPoint,
        f32 rotation,
        vector2df scale,
        bool useAlphaChannel,
        SColor color)
{
        SMaterial material;
        
        // Store and clear the projection matrix
        matrix4 oldProjMat = driver->getTransform(ETS_PROJECTION);
        driver->setTransform(ETS_PROJECTION,matrix4());
        
        // Store and clear the view matrix
        matrix4 oldViewMat = driver->getTransform(ETS_VIEW);
        driver->setTransform(ETS_VIEW,matrix4());
        
        // Find the positions of corners
        vector2df corner[4];
        
        corner[0] = vector2df((f32)position.X, (f32)position.Y);
        corner[1] = vector2df((f32)position.X + sourceRect.getWidth() * scale.X, (f32)position.Y);
        corner[2] = vector2df((f32)position.X, (f32)position.Y + sourceRect.getHeight() * scale.Y);
        corner[3] = vector2df((f32)position.X + sourceRect.getWidth() * scale.X, (f32)position.Y + sourceRect.getHeight() * scale.Y);
        
        // Rotate corners
        if (rotation != 0.0f)
        {       
                for (int x = 0; x < 4; x++)
                {
                        corner[x].rotateBy(rotation, vector2df((f32)rotationPoint.X, (f32)rotationPoint.Y));
                }
        }
        
        // Find the uv coordinates of the sourceRect
        vector2df uvCorner[4];
        uvCorner[0] = vector2df((f32)sourceRect.UpperLeftCorner.X, (f32)sourceRect.UpperLeftCorner.Y);
        uvCorner[1] = vector2df((f32)sourceRect.LowerRightCorner.X, (f32)sourceRect.UpperLeftCorner.Y);
        uvCorner[2] = vector2df((f32)sourceRect.UpperLeftCorner.X, (f32)sourceRect.LowerRightCorner.Y);
        uvCorner[3] = vector2df((f32)sourceRect.LowerRightCorner.X, (f32)sourceRect.LowerRightCorner.Y);
        for (int x = 0; x < 4; x++)
        {
                f32 uvX = uvCorner[x].X / (f32)texture->getSize().Width;
                f32 uvY = uvCorner[x].Y / (f32)texture->getSize().Height;
                uvCorner[x] = vector2df(uvX, uvY);
        }
        
        // Vertices for the image
        S3DVertex vertices[4];
        u16 indices[6] = { 0, 1, 2, 3, 2, 1 }; // original & double flip
        if((scale.X > 0.0f && scale.Y < 0.0f) || (scale.X < 0.0f && scale.Y > 0.0f))
        {
                indices[1] = 2;
                indices[2] = 1;
                indices[4] = 1;
                indices[5] = 2;
        }
        //u16 indices[6] = { 0, 2, 1, 3, 1, 2 }; // single flip
        
        // Convert pixels to world coordinates
        f32 screenWidth = (f32)driver->getScreenSize().Width;
        f32 screenHeight = (f32)driver->getScreenSize().Height;
        for (int x = 0; x < 4; x++)
        {
                f32 screenPosX = ((corner[x].X / screenWidth) - 0.5f) * 2.0f;
                f32 screenPosY = ((corner[x].Y / screenHeight) - 0.5f) * (-2.0f);
                vertices[x].Pos = 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 = ETC_CLAMP;
        
        if (useAlphaChannel)
                material.MaterialType = EMT_TRANSPARENT_ALPHA_CHANNEL;
        else
                material.MaterialType = EMT_SOLID;
        
        driver->setMaterial(material);
        driver->drawIndexedTriangleList(&vertices[0], 4, &indices[0], 2);
        
        // Restore projection and view matrices
        driver->setTransform(ETS_PROJECTION, oldProjMat);
        driver->setTransform(ETS_VIEW, oldViewMat);
}
However, I realized I used an old version of the code in the link of my previous post.
You may want to check that link. Use the updated code, and simply add this:

Code: Select all

if((scale.X > 0.0f && scale.Y < 0.0f) || (scale.X < 0.0f && scale.Y > 0.0f))
        {
                indices[1] = 2;
                indices[2] = 1;
                indices[4] = 1;
                indices[5] = 2;
        }
mnunesvsc
Posts: 22
Joined: Sun May 28, 2006 9:04 pm
Contact:

Re: 2D image mirroring

Post by mnunesvsc »

thankyou very much, i am going to use it right now
Post Reply