Cursor control problems with SDL - Almost done..just one more thing

Started by
6 comments, last by garyfletcher 18 years, 11 months ago
Hi all. I'm having problems with my cursor control modules. I've decided that my engine will take over cursor processign when ever it is instansiated. The reasons for this is that SDL (my API of choice at the moment) doesn't automatically provide cursor processing in fullscreen mode. Anyway. I've got a cursor class that is dervived from my base sprite class. I'm calling the cursor control during each iteration of the game loop, clearing the old position, calling pumpevents and the SDL_GetRelativeMouseState() for the X and Y deltas, adding the new X and Y to the current X and Y values and then redrawing the cursor sprite. The old position of the cursor isn't being removed, the new cursors Y coordinates doesn't seem to change and the cursor movement isn't smooth at all. I've also noticed that if something is happening on screen, ie. I'm drawing something else, then that stops while the cursor is being moved. I'm assuming that the get mouse state functions wait until there is no mouse movement/action before returning? Does anyone know of any tutorials regarding SDL and cursor controls. The SDL documentation is pretty scant for this? [Edited by - garyfletcher on May 23, 2005 5:26:23 PM]
Gary.Goodbye, and thanks for all the fish.
Advertisement
Well, SDL kind of is too low level to support that stuff.

You will have to post some sort of source code for any help...my only idea from what i can see is that the SDL mouse positions are right (the delta's it returns with SDL_GetRelative...() ), but since it has to wait to draw it, the delta's just keep adding up...like the mouse is moving, it just doesnt draw until everything else is done.

But then again, some code would help...
gib.son
Okay. I'll post code. I was trying to avoid this coz it's pretty long.

I'll Add an explination of how the sprites are used as well. Code 1st though..:)

Cursor class:
#ifndef INCLUDE_CURSOR_H#define INCLUDE_CURSOR_H#include "SiSEBaseSprite.h"#include "SiSEVector2D.h"const std::string CURSKEY = "CURSKEY";const std::string CLEARKEY = "CURSCLEARKEY";class SiSECursor : public SiSEBaseSprite{    public:        SiSECursor(SDL_Surface *screen, float x = 0.0f, float y = 0.0f, float speed = 0.0f);        ~SiSECursor();        void mProcessCursor(void);        inline void mEnableCurs(void){mEnabled = true;}        inline void mDisableCurs(void){mEnabled = false;}        inline void mToggleCurs(void){mEnabled = !mEnabled;}        inline bool mIsEnabled(void){return mEnabled;}        inline void mSetClearKey(std::string& clrKey){mClearKey = clrKey;}        inline void mSetCursKey(std::string& cursKey){mCursAnimKey = cursKey;}        inline void mSetDefaults(void){mClearKey = CLEARKEY; mCursAnimKey = CLEARKEY;}            private:        void mSetCursPos(void);        void mAddRelCursPos(void);        void mGetCursPos(void);        bool mEnabled;        int mouseAX;        int mouseAY;        int mouseRX;        int mouseRY;        int button;        std::string mClearKey;        std::string mCursAnimKey;        };#endif#include "SiSECursor.h"#include "SDL/SDL.h" enum MBUTTONS{NONPRESSED,LPRESSED,RPRESSED}; SiSECursor::SiSECursor(SDL_Surface *screen, float x, float y, float speed) : SiSEBaseSprite(screen,x,y,speed){    SDL_ShowCursor(SDL_DISABLE);            mEnabled = true;        mouseAX=0;    mouseAY=0;    mouseRX=0;    mouseRY=0;    button=NONPRESSED;    mCursAnimKey = CURSKEY;    mClearKey = CLEARKEY;}SiSECursor::~SiSECursor(){    mEnabled = false;        SDL_ShowCursor(SDL_ENABLE);}void SiSECursor::mProcessCursor(){        if (mEnabled)    {        mGetCursPos();        mAddRelCursPos();        mAnimKey = mClearKey;        clearBG();        mAnimKey = mCursAnimKey;        draw();    }        return;}void SiSECursor::mAddRelCursPos(){    std::cerr << "mAddRelCursPos() - mouseRX: " << mouseRX << std::endl;    std::cerr << "mAddRelCursPos() - mouseRY: " << mouseRY << std::endl;        xyAdd(mouseRX,mouseRY);}void SiSECursor::mSetCursPos(){    xySet(mouseAX,mouseAY); } void SiSECursor::mGetCursPos(){    mouseAX=0;    mouseAY=0;    mouseRX=0;    mouseRY=0;    button=NONPRESSED;        int height = GetHeight();    int width = GetWidth();        SDL_PumpEvents();        SDL_GetMouseState(&mouseAX,&mouseAY);        if (mouseAX < 0)    {        mouseAX = 0;    }    else if (mouseAX > height)    {        mouseAX = height;    }            if (mouseAY < 0)    {        mouseAY = 0;    }    else if (mouseAY > width)    {        mouseAY = width;       }        SDL_PumpEvents();        SDL_GetRelativeMouseState(&mouseRX,&mouseRY);        if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_LEFT))    {        button = LPRESSED;    }    else if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))    {        button = RPRESSED;    }}


Base sprite class:
#ifndef INCLUDE_BSPRITE_H#define INCLUDE_BSPRITE_H#include <map>#include <string>#include "SiSEAnimation.h"#include "SiSEVector2D.h"enum SpriteState{NORMAL,HIT,COLLISION,CRITICAL,FIRE,JUMP,LEFT,RIGHT,UP,DOWN,STRAFFE,SPIN,SPINRIGHT,SPINLEFT};class SiSEBaseSprite{    public:        SiSEBaseSprite(SDL_Surface *screen, float x = 0.0f, float y = 0.0f, float speed = 0.0f);  // Constructor        ~SiSEBaseSprite();         // Destructor                void m_addAnimation(SiSEAnimation* SAnim);                // Drawing functions        void draw();        void clearBG();        void updateBG();        void DrawSpriteIMG(SDL_Surface *img, float x, float y);        void mDrawSprite(void);                // Accessor functions        Vector2D* Pos(void){return pos;}        Vector2D* OldPos(void){return oldPos;}        int GetHeight(void){return m_getAnimation()->mGetHeight();}        int GetWidth(void){return m_getAnimation()->mGetWidth();}        void SetFrame(int nr){mFrame = nr;}        int GetFrame(void){return mFrame;}        void SetSpeed(float nr){mSpeed = nr;}        float GetSpeed(void){return mSpeed;}        void SetScreen(SDL_Surface *aScreen){mScreen = aScreen;}        SDL_Surface* GetScreen(void){return mScreen;}        SpriteState GetState(void){return mState;}                // Animations control functions        void ToggleAnim(void){mAnimating = !mAnimating;}        void StartAnim(void){mAnimating = true;}        void StopAnim(void){mAnimating = false;}        void Rewind(void){mFrame = 0;}        bool isAnimating();        void setAnimKey(const std::string& animKey){mAnimKey = animKey;}                // COORD control functions        void xAdd(float nr);        void yAdd(float nr);        void xyAdd(float x, float y);        void xSet(float nr);        void ySet(float nr);        void xySet(float x, float y);            protected:        int mFrame;                     // Animation frame tracker                // Coordinate vectors        Vector2D* pos;        Vector2D* oldPos;        std::string mAnimKey;           // Animation key        bool mDrawn;                    // Drawn flag        bool mAnimating;        float mSpeed;                   // Speed indicator (pause multiplier)        long mLastUpdate;               // Time sprite was last animated        SiSEAnimation* mSpriteAnim;     // Pointer to animations (sprite frames)        typedef std::map<std::string, SiSEAnimation*> mAnimMap;        typedef std::pair<std::string, SiSEAnimation*> mAnimPair;        mAnimMap mAnimations;        SDL_Surface* mScreen;           // Pointer to the surface to animate on        SiSEAnimation* m_getAnimation();        SpriteState mState; };#endif#include <cmath>#include "SiSEBaseSprite.h"#include "SiSEException.h"SiSEBaseSprite::SiSEBaseSprite(SDL_Surface *screen, float x, float y, float speed){    mFrame = 0;                 // Animation frame tracker    mDrawn = false;             // Drawn flag    mSpeed = speed;             // Speed indicator (pause multiplier)    mLastUpdate = 0L;           // Time sprite was last animated    mSpriteAnim = 0;            // Pointer to animations (sprite frames)    mState = NORMAL;            // Set Sprite state    mScreen = screen;           // Set screen for output    mAnimating = false;        // Coordinaye vectors    pos = new Vector2D(x,y);    oldPos = new Vector2D();}        SiSEBaseSprite::~SiSEBaseSprite(){    mSpriteAnim = 0;        delete pos;    pos = 0;        delete oldPos;    oldPos = 0;        mAnimMap::iterator animIter = mAnimations.begin();    mAnimMap::const_iterator animEnd = mAnimations.end();        while(animIter != animEnd)    {        delete animIter->second;        animIter->second = 0;                ++animIter;    }}void SiSEBaseSprite::m_addAnimation(SiSEAnimation* SAnim){    mAnimMap::iterator animIter = mAnimations.find(mAnimKey);        if (animIter == mAnimations.end())    {        mAnimations.insert(mAnimPair(mAnimKey,SAnim));                if (SAnim->mGetFramesNum() > 1)            mAnimating = true;            }    else    {        throw SiSEException("SiSEBaseSprite() ERROR: Duplicate Animation key.");    }     return;   }bool SiSEBaseSprite::isAnimating(){    mAnimMap::iterator animIter = mAnimations.find(mAnimKey);        if (animIter != mAnimations.end())    {        return animIter->second->isAnimating();    }    else    {        throw SiSEException("SiSEBaseSprite() isAnimating()  ERROR: Cannot find Animation key.");    }}void SiSEBaseSprite::xyAdd(float x, float y){    oldPos = pos;    pos->SetX(pos->GetX()+x);        pos->SetX(pos->GetY()+y);};void SiSEBaseSprite::xAdd(float nr){    oldPos = pos;    pos->SetX(pos->GetX()+nr);    return;}void SiSEBaseSprite::yAdd(float nr){    oldPos = pos;     pos->SetY(pos->GetY()+nr);    return;    }        void SiSEBaseSprite::xSet(float nr){    oldPos = pos;    pos->SetX(nr);    return;    }        void SiSEBaseSprite::ySet(float nr){    oldPos = pos;    pos->SetY(nr);        return;    }        void SiSEBaseSprite::xySet(float x, float y){    oldPos = pos;     pos->SetXY(x,y);        return;    }SiSEAnimation* SiSEBaseSprite::m_getAnimation(){    mAnimMap::iterator mapIter = mAnimations.find(mAnimKey);        if (mapIter != mAnimations.end())    {        return mapIter->second;      }    else    {        std::string errMsg = "SiSEBaseSprite draw() ERROR: Unable to find animation key " + mAnimKey;        throw SiSEException(errMsg);    }}// Drawing functionsvoid SiSEBaseSprite::draw(){    mSpriteAnim = m_getAnimation();        int numFrames = mSpriteAnim->mGetFramesNum();        if(numFrames > 1 && mAnimating)    {        if((mLastUpdate+mSpriteAnim->mAnim[mFrame]->pause*mSpeed) < SDL_GetTicks())        {            if (mFrame > (numFrames-1))            {                mFrame = 0;            }                        mLastUpdate = SDL_GetTicks();        }    }        DrawSpriteIMG(mSpriteAnim->mAnim[mFrame]->image, pos->GetX(), pos->GetY());        if(!mDrawn)    {        mDrawn = true;      }        return;}void SiSEBaseSprite::DrawSpriteIMG(SDL_Surface *img, float x, float y){    SDL_Rect dest;        dest.x = (Sint16)x;    dest.y = (Sint16)y;        SDL_BlitSurface(img, NULL, mScreen, &dest);        return;}    void SiSEBaseSprite::clearBG(){    if(mDrawn)    {        mSpriteAnim = m_getAnimation();                SDL_Rect dest;                dest.x = (Sint16)oldPos->GetX();        dest.y = (Sint16)oldPos->GetY();        dest.w = mSpriteAnim->mGetWidth();        dest.h = mSpriteAnim->mGetHeight();                SDL_BlitSurface(mSpriteAnim->mAnim[0]->image, NULL, mScreen, &dest);                //DrawSpriteIMG(mSpriteAnim->mAnim[mFrame]->image, pos->GetX(), pos->GetY());    }        return;   }void SiSEBaseSprite::updateBG(){       SDL_Rect srcRect;        mSpriteAnim = m_getAnimation();        srcRect.w = mSpriteAnim->mGetWidth();    srcRect.h =  mSpriteAnim->mGetHeight();    srcRect.x = (Sint16)pos->GetX();    srcRect.y = (Sint16)pos->GetY();    oldPos = pos;        SDL_BlitSurface(mScreen, &srcRect, mSpriteAnim->mAnim[mFrame]->image, NULL);    //DrawSpriteIMG(mSpriteAnim->mAnim[mFrame]->image, pos->GetX(), pos->GetY());        return;}void SiSEBaseSprite::mDrawSprite(){    //clearBG();    //updateBG();    draw();        return;   }


animation class:
#ifndef INCLUDE_SISEANIM_H#define INCLUDE_SISEANIM_H#include <string>#include <vector>#include "SDL/SDL.h"class SiSEAnimation{    private:        typedef struct        {            SDL_Surface *image;         // Pointer to frame image            int pause;                  // Milliseconds to pause after drawing image        } SiSEFrame;                bool mBuilt;        bool mAnimating;        int mNumFrames;        int mWidth;        int mHeight;            public:        SiSEAnimation(const std::string& SpriteFile);       // Constructor        ~SiSEAnimation();                                   // Destructor                                                   // Pointer to animations frames        std::vector<SiSEFrame*> mAnim;        typedef std::vector<SiSEFrame*>::iterator animIter;        typedef std::vector<SiSEFrame*>::const_iterator canimIter;                // Accessor functions        inline std::vector<SiSEFrame*>& mGetFrames(void){return mAnim;}        inline bool mIsBuilt(void){return mBuilt;}        inline int mGetFramesNum(void){return mNumFrames;}        inline int mGetWidth(void){return mWidth;}        inline int mGetHeight(void){return mHeight;}        inline animIter mAnimStart(){return mAnim.begin();}        inline animIter mAnimEnd(){return mAnim.end();}        inline bool isAnimating(void){return mAnimating;}        };#endif#include <cstdlib>#include <iostream>#include <fstream>#include "SiSEAnimation.h"#include "SiSEException.h"using std::string;using std::cerr;using std::endl;using std::ifstream;SiSEAnimation::SiSEAnimation(const string& SpriteFile){       mNumFrames = 0;    string buffer;    string fileName;    string name;    int pause = 0;    int red = 0;    int green = 0;    int blue = 0;    FILE *fp = 0;    mWidth = 0;    mHeight = 0;    mAnimating = false;        // Get our information file for this sprite animation        fileName = SpriteFile;        ifstream inFile(fileName.c_str());        if (!inFile)    {        std::string ErrMsg = "SiSEAnimation() ERROR: Cannot open " + fileName;        throw SiSEException(ErrMsg);    }            getline(inFile,buffer);            sscanf(buffer.c_str(),"FILES: %d",&mNumFrames);            //mAnim = new SiSEFrame[mNumFrames];    mAnim.reserve(mNumFrames);    mBuilt = true;            int frameCount = 0;            while(getline(inFile,buffer))	{        // check for a valid line        if (buffer[0] != '#' && buffer[0] != '\r' && buffer[0] != '\0' &&            buffer[0] != '\n' && buffer.size() != 0)        {            char tmpName[50];                            memset(tmpName,0,sizeof(tmpName));                            // Read our animation data            sscanf(buffer.c_str(),"%s %d %d %d %d",tmpName,&pause,&red,&green,&blue);                            name = tmpName;                        // set the sprite file for the current animation frame            fileName = name;                            // Read in the current frame            SDL_Surface *temp = 0;                         if ((temp = SDL_LoadBMP(fileName.c_str())) == NULL)            {                std::string ErrMsg = "SiSEAnimation() ERROR: " + static_cast<string>(SDL_GetError());                throw SiSEException(ErrMsg);            }                        // Check the transprancy colour for the animation            if (red >= 0)            {                SDL_SetColorKey(temp, SDL_SRCCOLORKEY,SDL_MapRGB(temp->format,red,green,blue));                    }                        // Set the current animation frame to the currently read sprite            // Just set the formats to help speed things up a little when blitting                        SiSEFrame* tempFrame = new SiSEFrame;                        tempFrame->image = SDL_DisplayFormat(temp);                        // Free the temp memory            SDL_FreeSurface(temp);                        // Set the pause value            tempFrame->pause = pause;                        // Set the width and height if we need to            if (!mWidth)            {                mWidth = tempFrame->image->w;            }                        if (!mHeight)            {                mHeight = tempFrame->image->h;            }                        mAnim.push_back(tempFrame);                        // No dangling            tempFrame = 0;                        // Update the count for next one            frameCount++;        }                }        if (frameCount > 1)        mAnimating = true;            inFile.close();    }SiSEAnimation::~SiSEAnimation(){    animIter aIter = mAnim.begin();    canimIter animEnd = mAnim.end();        while (aIter != animEnd)    {        delete *aIter;        *aIter = 0;        ++aIter;    }    }


game loop (called from stack):
void SiSE::m_gameLoop(void){    /* The game loop. Loop until the game stack is empty */    while(!m_StateStack.empty())    {        if ((SDL_GetTicks() - m_Timer) >= FRAME_RATE)        {                /* In order to use the function pointed to on top of the stack      */            /* it needs to be called with an object of the appropriate type     */            /* In this case a SiSE object. Pass the function pointer      */            /* to a member function that will execute it as (this->*funcPtr)()  */            ExecuteFunc(m_StateStack.top().funcPtr);                        // Do cursor processing            cerr <<  "About to process cursor" << endl;            cursor->mProcessCursor();            cerr << "Cursor processed" << endl;                        m_Timer = SDL_GetTicks();        }    }        return;    }


In order to load multiple animations for a sprite I use a map of animations using a key to indicate which animations we are currently working on. So to inistansiate a sprite an key is set and a set of animations or a single frame loaded into the sprite:

/* Cursor */
baseCursor = new SiSEAnimation("cursor/CursInfo");
clearCursor = new SiSEAnimation("cursor/ClearCursInfo");
cursor = new SiSECursor(m_Window,250.0f,250.0f);
cursor->setAnimKey(CLEARKEY);
cursor->m_addAnimation(clearCursor);
cursor->setAnimKey(CURSKEY);
cursor->m_addAnimation(baseCursor);

Hope someone can help..:)

For anyone interested the Vector2D class is shown below:

#ifndef INCLUDE_VEC2D_H#define INCLUDE_VEC2D_Htypedef float SCALAR;class Vector2D{    public:        Vector2D();        Vector2D(const SCALAR& a, const SCALAR& b);        ~Vector2D();        SCALAR& operator[](const long i);        const bool operator==(const Vector2D& v) const;        const bool operator!=(const Vector2D& v) const;        const Vector2D operator-(void) const;        const Vector2D& operator=(const Vector2D& v);        const Vector2D& operator+=(const Vector2D& v);        const Vector2D& operator-=(const Vector2D& v);        const Vector2D& operator*=(const SCALAR& s);        const Vector2D& operator/=(const SCALAR& s);        const Vector2D operator+(const Vector2D& v) const;        const Vector2D operator-(const Vector2D& v) const;        const Vector2D operator*(const SCALAR& s) const;        friend inline const Vector2D operator* (const SCALAR& s, const Vector2D v){return v*s;}        const Vector2D operator/(const SCALAR& s) const;        const Vector2D perpen(void) const;        const SCALAR dot(const Vector2D& v) const;        const SCALAR length(void) const;        const Vector2D unit(void) const;        void normalise(void);        const bool nearlyEquals(const Vector2D& v, const SCALAR e) const;        void SetX(SCALAR xPos){x=xPos; calcMagnitude();}        SCALAR GetX(void){return x;}        void SetY(SCALAR yPos){y=yPos; calcMagnitude();}        SCALAR GetY(void){return y;}        void SetXY(SCALAR xPos, SCALAR yPos){x=xPos; y=yPos; calcMagnitude();}        double GetMagSQRD(void){return magnitude;}            private:        void calcMagnitude(void);        SCALAR x;        SCALAR y;        double magnitude;};typedef Vector2D POINT;#endif#include "SiSEVector2D.h"#include <cmath>Vector2D::Vector2D():x(0), y(0), magnitude(0.0){}Vector2D::Vector2D(const SCALAR& a, const SCALAR& b):x(a), y(b){    calcMagnitude();}Vector2D::~Vector2D(){}void Vector2D::calcMagnitude(void){    magnitude = (fabs(x*x)+fabs(y*y));}SCALAR& Vector2D::operator[](const long i){    return *((&x)+i);}        const bool Vector2D::operator==(const Vector2D& v) const{    return (v.x==x && v.y==y);}        const bool Vector2D::operator!=(const Vector2D& v) const{    return !(v==*this);}const Vector2D Vector2D::operator-(void) const{    return Vector2D(-x,-y);} const Vector2D& Vector2D::operator=(const Vector2D& v){    x=v.x;    y=v.y;        return *this;}const Vector2D& Vector2D::operator+=(const Vector2D& v){    x+=v.x;    y+=v.y;        return *this;}const Vector2D& Vector2D::operator-=(const Vector2D& v){    x-=v.x;    y-=v.y;        return *this;}const Vector2D& Vector2D::operator*=(const SCALAR& s){    x*=s;    y*=s;        return *this;}const Vector2D& Vector2D::operator/=(const SCALAR& s){    const SCALAR r = 1/s;        x*=r;    y*=r;        return *this;}const Vector2D Vector2D::operator+(const Vector2D& v) const{    return Vector2D(x+v.x,x+v.y);}        const Vector2D Vector2D::operator-(const Vector2D& v) const{    return Vector2D(x-v.x,y-v.y);}const Vector2D Vector2D::operator*(const SCALAR& s) const{    return Vector2D(x*s, y*s);}const Vector2D Vector2D::operator/(const SCALAR& s) const{    SCALAR t=1/s;        return Vector2D(t*x,t*y);}const Vector2D Vector2D::perpen(void) const{    return Vector2D(this->y, -(this->x));}const SCALAR Vector2D::dot(const Vector2D& v) const{    return x*v.x + y*v.y;}const SCALAR Vector2D::length(void) const{    return (SCALAR)sqrt((double)this->dot(*this));}const Vector2D Vector2D::unit(void) const{    return (*this)/length();}void Vector2D::normalise(void){    (*this)/=length();}const bool Vector2D::nearlyEquals(const Vector2D& v, const SCALAR e) const{    return fabs(x-v.x)<e && fabs(y-v.y) < e;}


[Edited by - garyfletcher on May 23, 2005 1:45:49 AM]
Gary.Goodbye, and thanks for all the fish.
ANY tutorials/articles on this would be great..:)
Gary.Goodbye, and thanks for all the fish.
Anybody..not even 1 tutorial/article...boohoo!!!!
Gary.Goodbye, and thanks for all the fish.
Slightly unrelated, what sort of problems were you having with the mouse in fullscreen mode? I've had no problems with SDL in fullscreen with the mouse in my tests (both Windows and Linux).
It might be different under Linux but with windows cursor control isn't provided with SDL.

Not too sure why...think I read somewhere it's to do with problems with directly accessing hardware, but some cards provide support.

Although don't quote me on that..:)
Gary.Goodbye, and thanks for all the fish.
Okay I'm almost there.

I've now got a cursor on screen and moving and got mouse events being detected...hooray.

I have noticed though that when a mouse even is taking place, such as mouse motion, background rendering starts slowing down.

Is there anything that I can do to prevent this?

My code is now quite simple:

void SiSECursor::mGetCursPos(){    SDL_Event event;        button = NONPRESSED;        if (SDL_PollEvent(&event))    {        if (event.type == SDL_MOUSEMOTION )         {            SDL_GetMouseState(&mouseAX,&mouseAY);        }        else if  (event.type == SDL_MOUSEBUTTONDOWN )        {            if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_LEFT))            {                button = LPRESSED;            }            else if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))            {                button = RPRESSED;            }        }    }}


Any suggestions?
Gary.Goodbye, and thanks for all the fish.

This topic is closed to new replies.

Advertisement