No Rotate and Mirror methods for IImage

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
Randajad
Posts: 59
Joined: Thu May 03, 2012 10:08 am

No Rotate and Mirror methods for IImage

Post by Randajad »

Subj. It's too strange that engine like irrlicht has not such methods.
Sorry for my English, i'm from Russia.
If i makes mistakes in phrases you can correct me btw. ^_^
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: No Rotate and Mirror methods for IImage

Post by CuteAlien »

Usually you don't want to rotate the image but you want to draw the image rotated. Which you can probably already do by setting the right matrices. But yes, doing that easier and from within the gui for example would be nice. I've seen some patches for that already (and done my own), but none of those really was engine quality (including my own which was just a hack to make it work in an ugly way).
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
gerdb
Posts: 194
Joined: Wed Dec 02, 2009 8:21 pm
Location: Dresden, Germany

Re: No Rotate and Mirror methods for IImage

Post by gerdb »

Hi, maybe you can use these functions from my CImageFactory class ( remember this class does everything in software )

full class can be found here, with filters like sharpening and smoothing also resizing functions ( nearest, bilinear, bicubic interpolation ) and much drawing stuff

http://benjaminhampe.be.ohost.de/Irrlic ... eFactory.h
http://benjaminhampe.be.ohost.de/Irrlic ... actory.cpp

Here is the excerpt of rotation functions within the class you are looking for

Code: Select all

 
// Copyright (C) 2002-2013 BenjaminHampe@gmx.de
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
 
#include "CImageFactory.h"
 
#include <irrlicht.h>
#include <../source/Irrlicht/CImage.h>
#include <../source/Irrlicht/os.h>
 
//! quick copy hole image
IImage* CImageFactory::cloneImage( IImage* src ) const
{
    if (!src)
        return 0;
 
    IImage* dst = new CImage( src->getColorFormat(), src->getDimension() );
    if (!dst)
        return 0;
 
    void* srcPtr = src->lock();
    void* dstPtr = dst->lock();
    memcpy( dstPtr, srcPtr, src->getPitch() * src->getDimension().Height );
    dst->unlock();
//  dst->setColorKeyEnabled( IsColorKeyEnabled );
//  dst->setColorKey( ColorKey );
//  dst->setMemoryOwner( true );
    return dst;
}
 
IImage* CImageFactory::rotateLeft( IImage* src ) const
{
    if (!src)
        return 0;
 
    const core::dimension2du& Size = src->getDimension();
 
    IImage* dst = new CImage( src->getColorFormat(), Size );
    if (!dst)
        return 0;
 
    for (u32 y=0; y<Size.Height; y++)
    {
        for (u32 x=0; x<Size.Width; x++)
        {
            SColor color = src->getPixel(x,y);
            dst->setPixel(y, Size.Width-1-x, color);
        }
    }
 
    return dst;
}
 
 
IImage* CImageFactory::rotateRight( IImage* src ) const
{
    if (!src)
        return 0;
 
    const core::dimension2du& Size = src->getDimension();
 
    IImage* dst = new CImage( src->getColorFormat(), Size );
    if (!dst)
        return 0;
 
    for (u32 y=0; y<Size.Height; y++)
    {
        for (u32 x=0; x<Size.Width; x++)
        {
            SColor color = src->getPixel(x,y);
            dst->setPixel(Size.Height-1-y, x, color);
        }
    }
 
    return dst;
}
 
bool CImageFactory::flipH( IImage* dst ) const
{
    if (!dst) return false;
    const core::dimension2du& Size = dst->getDimension();
    u32 HalfWidth = Size.Width >> 1;
    SColor color1, color2;
 
    for (u32 y=0; y<Size.Height; y++)
    {
        for (u32 x=0; x<HalfWidth; x++)
        {
            color1 = dst->getPixel(x,y);
            color2 = dst->getPixel(Size.Width-1-x,y);
            dst->setPixel(x,y,color2);
            dst->setPixel(Size.Width-1-x,y,color1);
        }
    }
    return true;
}
 
bool CImageFactory::flipV( IImage* dst ) const
{
    if (!dst) return false;
    const core::dimension2du& Size = dst->getDimension();
 
    u32 HalfHeight = Size.Height >> 1;
    SColor color1, color2;
 
    for (u32 y=0; y<HalfHeight; y++)
    {
        for (u32 x=0; x<Size.Width; x++)
        {
            color1 = dst->getPixel(x,y);
            color2 = dst->getPixel(x,Size.Height-1-y);
            dst->setPixel(x,y,color2);
            dst->setPixel(x,Size.Height-1-y,color1);
        }
    }
    return true;
}
 
bool CImageFactory::rotate180( IImage* dst ) const
{
    if (!dst) return false;
    const core::dimension2du& Size = dst->getDimension();
 
    u32 m = Size.Height >> 1;
    SColor color1, color2;
 
    for (u32 y=0; y<m; y++)
    {
        for (u32 x=0; x<Size.Width; x++)
        {
            color1 = dst->getPixel(x,y);
            color2 = dst->getPixel(x,Size.Height-1-y);
            dst->setPixel(x,y,color2);
            dst->setPixel(x,Size.Height-1-y,color1);
        }
    }
    return true;
}
 
IImage* CImageFactory::rotate( IImage* src, f32 angleDegreesCCW, SColor* colorKey ) const
{
    if (!src)
        return 0;
 
    const core::dimension2du& Size = src->getDimension();
 
    // Winkel
    while (angleDegreesCCW<0.0f)    {   angleDegreesCCW+=360.0f;    }
    while (angleDegreesCCW>=360.0f) {   angleDegreesCCW-=360.0f;    }
 
    //
    if (core::equals(angleDegreesCCW,0.0f))
    {
        return cloneImage(src);
    }
    else if (core::equals(angleDegreesCCW,90.0f))
    {
        return rotateLeft(src);
    }
    else if (core::equals(angleDegreesCCW,270.0f))
    {
        return rotateRight(src);
    }
    else if (core::equals(angleDegreesCCW,180.0f))
    {
        IImage* tmp = cloneImage(src);
        rotate180(tmp);
        return tmp;
    }
    else
    {
        // alpha
        const f32 a=(360.0f-angleDegreesCCW)*core::DEGTORAD;
        const f32 sa=sinf(a);
        const f32 ca=cosf(a);
 
        // gamma
        const f32 g=angleDegreesCCW*core::DEGTORAD;
        const f32 sg=sinf(g);
        const f32 cg=cosf(g);
 
        // BERECHNNUNG des Mittelpunktes von MEM
        const f32 mXh=0.5f*(f32)Size.Width;
        const f32 mYh=0.5f*(f32)Size.Height;
 
        // BERECHNNUNG der Eckpunkte
        const f32 Ax= mXh,  Ay=-mYh;
        const f32 Bx=-mXh,  By=-mYh;
        const f32 Cx=-mXh,  Cy= mYh;
        const f32 Dx= mXh,  Dy= mYh;
 
        // TRANSFORMATION der Eckpunkte
        f32 Anx=Ax*ca - Ay*sa;
        f32 Any=Ax*sa + Ay*ca;
        f32 Bnx=Bx*ca - By*sa;
        f32 Bny=Bx*sa + By*ca;
        f32 Cnx=Cx*ca - Cy*sa;
        f32 Cny=Cx*sa + Cy*ca;
        f32 Dnx=Dx*ca - Dy*sa;
        f32 Dny=Dx*sa + Dy*ca;
 
        // BERECHNUNG der FINAL WIDTH and HEIGHT
        f32 minX=0.0f, maxX=0.0f;
        f32 minY=0.0f, maxY=0.0f;
        if (Anx<minX) minX=Anx;      if (Any<minY) minY=Any;
        if (Anx>maxX) maxX=Anx;      if (Any>maxY) maxY=Any;
        if (Bnx<minX) minX=Bnx;      if (Bny<minY) minY=Bny;
        if (Bnx>maxX) maxX=Bnx;      if (Bny>maxY) maxY=Bny;
        if (Cnx<minX) minX=Cnx;      if (Cny<minY) minY=Cny;
        if (Cnx>maxX) maxX=Cnx;      if (Cny>maxY) maxY=Cny;
        if (Dnx<minX) minX=Dnx;      if (Dny<minY) minY=Dny;
        if (Dnx>maxX) maxX=Dnx;      if (Dny>maxY) maxY=Dny;
 
        f32 fdx=maxX-minX;
        f32 fdy=maxY-minY;
 
        u32 dx=core::abs_(core::round32(fdx));
        u32 dy=core::abs_(core::round32(fdy));
 
        core::stringc txt = "New Image with size (";
        txt += dx;
        txt += ", ";
        txt += dy;
        txt += ")";
        os::Printer::log(txt.c_str(), ELL_INFORMATION);
 
        // FINAL MEMBLOCK
        IImage* dst = new CImage( src->getColorFormat(), core::dimension2du(dx,dy));
        if (!dst)
            return 0;
 
        const core::dimension2du& Size2 = dst->getDimension();
 
        // BERECHNUNG des Mittelpunktes von FINAL
        f32 fdxh=0.5f*fdx;
        f32 fdyh=0.5f*fdy;
 
        // LET'S ROTATE
        s32 x,y;
        SColor color;
        f32 x0,y0,x1,y1;
 
        os::Printer::log("OK", ELL_INFORMATION);
        // Fuer alle Punkte im Zielbild den entsprechenden Punkt im Ausgangsbild
        // suchen. Dadurch entstehen keine Luecken im Bild.
        for (u32 j=0; j<dy; j++)
        {
            for (u32 i=0; i<dx; i++)
            {
                if ( (i<Size2.Width) && (j<Size2.Height) )
                {
                    x0=(f32)i-fdxh; // relativ zu FinalMem Mittelpunkt
                    y0=(f32)j-fdyh; // relativ zu FinalMem Mittelpunkt
                    x1=(cg*x0-sg*y0)+mXh; // relativ zu SourceMem Mittelpunkt
                    y1=(cg*y0+sg*x0)+mYh; // relativ zu SourceMem Mittelpunkt
    x=core::round32(x1);
    y=core::round32(y1);
 
                    // PIXEL von SourceMem
                    if ((x>=0) && (y>=0) && (x<Size.Width) && (y<Size.Height))
                    {
                        color=src->getPixel((u32)x, (u32)y);
                    }
                    else
                    {
                        if (colorKey)
                            color=*colorKey;
                        else
                            color.color = 0;
                    }
 
                    dst->setPixel( i,j,color );
                }
            }
        }
        return dst;
    }
    return 0;
}
 
 
 
Usage

Load image, i.e. earth.jpg from media dir and rotate 24 degrees ccw.

Image

Code: Select all

    video::IImage* img = driver->createImageFromFile( "../../media/earth.jpg");
 
    video::CImageFactory factory;
 
    video::IImage* img2 = factory.rotate( img, 24.0f );
 
    driver->writeImageToFile( img2, "./rotated_earth.png");
 
    img->drop();
    img2->drop();
 
Result
Image

but it lacks some smoothing and sharpening, also the borders of the image are very aliased, but it works
Post Reply