Texture sprite sheet animator using matrix.

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
_Neo
Posts: 30
Joined: Thu May 24, 2012 7:47 pm
Location: SiChuan, China

Texture sprite sheet animator using matrix.

Post by _Neo »

Currently, irrlicht only have texture animator that switch texture to animate.
However we should save each frame in saparate file in this way, thus the loading speed is slowed down.
I've read this post to show how to make irrlicht support sprite sheet by using texture matrix.
In order to avoid update texture manually in the game loop, I write this sprite node animater, just for newbies like me.
here's code:

The hearder

Code: Select all

 
// This flie is modified from CSceneNodeAnimatorTexture
 
#ifndef __C_SCENE_NODE_ANIMATOR_SPRITE_H_INCLUDED__
#define __C_SCENE_NODE_ANIMATOR_SPRITE_H_INCLUDED__
 
#include "irrArray.h"
#include "vector2d.h"
#include <irrlicht.h>
 
namespace irr
{
    namespace scene
    {
//I have trouble compile it into the irrlicht core(vs2008 sayed dinput.h is missing), so I have to make it into a dll function.
        __declspec(dllexport) ISceneNodeAnimator* createSpriteAnimator(video::ITexture*texture, 
            const core::array<core::vector2df>&translations,
            core::vector2df& scale,
            s32 timePerFrame, bool loop,
                    //os::timer isn't export in the lib, so you have to pass a timer here(see example below)
                        ITimer*timer);
//Here's the class
        class CSceneNodeAnimatorSprite : public ISceneNodeAnimator
        {
        public:
 
            //! constructor
            CSceneNodeAnimatorSprite(video::ITexture* texture,const core::array<core::vector2df>&translations,core::vector2df& scale,
                s32 timePerFrame, bool loop, u32 now);
 
            //! destructor
            virtual ~CSceneNodeAnimatorSprite();
 
            //! animates a scene node
            virtual void animateNode(ISceneNode* node, u32 timeMs);
 
            //! Writes attributes of the scene node animator.
            virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;
 
            //! Reads attributes of the scene node animator.
            virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);
 
            //! Returns type of the scene node animator
            virtual ESCENE_NODE_ANIMATOR_TYPE getType() const { return ESNAT_UNKNOWN; }
 
            //! Creates a clone of this animator.
            /** Please note that you will have to drop
            (IReferenceCounted::drop()) the returned pointer after calling
            this. */
            virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0);
 
        private:
 
            void clearSprites();
 
            video::ITexture* Texture;
//each frame's position is stored in translations' array
            core::array<core::vector2df>Translations;
            core::vector2df Scale;
            u32 TimePerFrame;
            u32 StartTime;
            u32 FinishTime;
            bool HasFinished;
            bool Loop;
        };
 
 
    } // end namespace scene
} // end namespace irr
 
 
#endif
Here's the source

Code: Select all

 
 
#include "CSceneNodeAnimatorSprite.h"
#include "ITexture.h"
 
namespace irr
{
    namespace scene
    {
 
        ISceneNodeAnimator* createSpriteAnimator(video::ITexture* texture,
            const core::array<core::vector2df>&translations,
            core::vector2df& scale,
            s32 timePerFrame, bool loop,ITimer*timer)
        {
            ISceneNodeAnimator* anim = new CSceneNodeAnimatorSprite(texture,translations,scale,
                timePerFrame, loop, timer->getTime());
 
            return anim;
        }
        //! constructor
        CSceneNodeAnimatorSprite::CSceneNodeAnimatorSprite(video::ITexture* texture, 
            const core::array<core::vector2df>&translations,    core::vector2df& scale,
            s32 timePerFrame, bool loop, u32 now):
            TimePerFrame(timePerFrame), StartTime(now), Loop(loop),Scale(scale)
        {
 
//modified from texure animator, hope this part is right.. Anyway it works well till now
                if (texture)
                    texture->grab();
                Translations=translations;
                Texture=texture;
 
            FinishTime = now + (timePerFrame * translations.size());
        }
 
 
        //! destructor
        CSceneNodeAnimatorSprite::~CSceneNodeAnimatorSprite()
        {
            clearSprites();
        }
 
 
        void CSceneNodeAnimatorSprite::clearSprites()
        {
            /*for (u32 i=0; i<Translations.size(); ++i)
            {
                if (Translations[i])
                    delete Translations[i];
            }*/
            Translations.clear();
            if(Texture)
            {
                Texture->drop();
            }
        }
 
 
        //! animates a scene node
        void CSceneNodeAnimatorSprite::animateNode(ISceneNode* node, u32 timeMs)
        {
            if(!node)
                return;
 
            if (Translations.size())
            {
                const u32 t = (timeMs-StartTime);
 
                u32 idx = 0;
                if (!Loop && timeMs >= FinishTime)
                {
                    idx = Translations.size() - 1;
                    HasFinished = true;
                }
                else
                {
                    idx = (t/TimePerFrame) % Translations.size();
                }
 
                if (idx < Translations.size())
                {
                    core::vector2df tran=Translations[idx];
                    core::matrix4 mat;
                    mat.buildTextureTransform(0,core::vector2df(0.0f),tran,Scale);
                    node->setMaterialTexture(0, Texture);
                    node->getMaterial(0).setTextureMatrix(0,mat);
                }
            }
        }
 
 
        //! Writes attributes of the scene node animator.
        void CSceneNodeAnimatorSprite::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
        {
            out->addInt("TimePerFrame", TimePerFrame);
            out->addBool("Loop", Loop);
            // add texture in addition when serializing for editors
            out->addTexture("Texture",Texture);
            // add one translation in addition when serializing for editors
            // to make it easier to add translations quickly
 
            u32 count = Translations.size();
            if ( options && (options->Flags & io::EARWF_FOR_EDITOR))
                count += 1;
 
            for (u32 i=0; i<count; ++i)
            {
                core::stringc tname = "Translation";
                tname += (int)(i+1);
                out->addVector2d(tname.c_str(), i<Translations.size() ? Translations[i] : core::vector2df(0.0f));
                
            }
        }
 
 
        //! Reads attributes of the scene node animator.
        void CSceneNodeAnimatorSprite::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
        {
            TimePerFrame = in->getAttributeAsInt("TimePerFrame");
            Loop = in->getAttributeAsBool("Loop");
            Texture=in->getAttributeAsTexture("Texture");
            Texture->grab();
            clearSprites();
 
            for(u32 i=1; true; ++i)
            {
                core::stringc tname = "Translation";
                tname += (int)i;
 
                if (in->existsAttribute(tname.c_str()))
                {
                    core::vector2df trans = in->getAttributeAsVector2d(tname.c_str());
                    //if (trans)
                    //{
                        Translations.push_back(trans);
                    //}
                }
                else
                    break;
            }
        }
 
 
        ISceneNodeAnimator* CSceneNodeAnimatorSprite::createClone(ISceneNode* node, ISceneManager* newManager)
        {
            CSceneNodeAnimatorSprite * newAnimator = 
                new CSceneNodeAnimatorSprite(Texture, Translations, Scale, TimePerFrame, Loop, StartTime);
 
            return newAnimator;
        }
 
 
    } // end namespace scene
} // end namespace irr
 
 
Here's an example of how to use it on the bill board

Code: Select all

 
// scale cannot bigger than 1
//scale.x = 1 / how many frames in a row
//scale.y= 1/ how many frames in a column
//For this example, I have a sprite sheet with 7 frames in a row,  totally 3 columna
    vector2df scale(1.f/7.f,1.f/3.0f);
    vector2df trans;
    array<vector2df>ts;
//caculate positions
    for(f32 m=0.f;m<3.f;m+=1.f)
    {
               for(f32 n=0;n<7;n+=1.f)
              {
        trans=vector2df(n,m)*scale;
        ts.push_back(trans);
               }
    }
//get your sprite sheet
ITexture* ft=device->getVideoDriver()->getTexture("sfx/cannon/fire/flame01.bmp");
//my image's background color is black, so I have to remove it
    device->getVideoDriver()->makeColorKeyTexture(ft,video::SColor(0,0,0,0));
//create animator
    ISceneNodeAnimator* ani=scene::createSpriteAnimator(ft,ts,scale,40,true,device->getTimer());
    IBillboardSceneNode* testB=smgr->addBillboardSceneNode();
//add animator
    testB->addAnimator(ani);
//drop it
    ani->drop();
    testB->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
    testB->setMaterialFlag(video::EMF_LIGHTING,false);
 
Have fun gaming!
Post Reply