GP2X Early Days Into Sdl But ...


jimb

Still Fresh
Joined
Oct 15, 2005
Messages
32
Fellow coders,

I'm just getting into SDL and therefore I'm still at 'newbie' level 1.
So far, I have manged knocked up a tiny example which *should* display an image going around the screen in an arc using sin() and cos().

Only thing is, the image does not move. Any ideas?

Note: I have wrapped a few SDL functions here to make them easier for me to remember.



Main Code
Code:
#include <cmath>
#include "Blitz.h"
using namespace std;

//       blitz example #1

int main(int argc, char *argv[]){
    Graphics(320, 240, 0);
    SetTitle("Load/Display image");

    SDL_Surface *image=LoadBMP("testimage.bmp");
    
    float v;
    while (!AppClosed()){
          Cls();
          DrawImage(image,60+int(sin(v)*40.0),60+int(cos(v)*30.0));
          v+=0.009;
          Flip();
    }
    End();
}




The Blitz.h include:
Code:
#include <SDL/SDL.h>
  
// globals
SDL_Surface *screen; // main screen
int gfxW;         // graphics width
int gfxH;         // graphics height
Uint8 *inkeys;

// functions

void LockScreen(){
     if (SDL_MUSTLOCK(screen)){
     SDL_LockSurface(screen);
     }
}

void UnLockScreen(){
    if(SDL_MUSTLOCK(screen)){
    SDL_UnlockSurface(screen);
    }
}

void End(){
    SDL_Quit();
}

bool AppClosed(){
    SDL_Event event;
    if(!SDL_PollEvent(&event)) return 0;
    inkeys = SDL_GetKeyState(NULL);
    if(inkeys[SDLK_ESCAPE]) return 1;
    if(event.type == SDL_QUIT) return 1;
    return 0;
} 

void Graphics(int width, int height, bool full)
{
    gfxW = width;
    gfxH = height;

    if(SDL_Init(SDL_INIT_VIDEO) < 0){
       printf("Unable to init SDL: %s\n", SDL_GetError());
       SDL_Quit();
    }
    if(!full==0){
        screen = SDL_SetVideoMode(width,height,32,SDL_SWSURFACE|SDL_FULLSCREEN);
        //LockScreen();
    }
    else{
        screen = SDL_SetVideoMode(width,height,32,SDL_HWSURFACE|SDL_HWPALETTE);
    }
    if(screen == NULL)
    {
        printf("Unable to set video: %s\n", SDL_GetError());
        SDL_Quit();
    }
}

void SetTitle(char *text){
     SDL_WM_SetCaption(text, NULL);
}

void Flip(){
    SDL_UpdateRect(screen, 0, 0, 0, 0);
    SDL_Delay(1);
}

void Cls(int r=0,int g=0,int b=0){
    SDL_FillRect(screen, NULL, 65536 * r + 256 * g + b);
}

SDL_Surface *LoadBMP(char *file){
            SDL_Surface *img = SDL_LoadBMP(file);
            if ( img == NULL ){
               fprintf(stderr, "Error loading BMP %s: %s\n", file, SDL_GetError());
            }
            return img;
}

void DrawImage(SDL_Surface *img,int x,int y){     
     SDL_Rect dest;
     dest.x = x;
     dest.y = y;
     dest.w = img->w;
     dest.h = img->h;
     SDL_BlitSurface(img, NULL, screen, &dest);
}
 
I've got to dash now, but just a couple of things from a quick scan:

You're using the float "v" in main() without initialising it - that's a bad idea as you can't guarantee it's going to contain any value straight off.

You're not using double buffering. Even if the image was moving, you'd get tearing. Init the screen with: SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE | SDL_DOUBLEBUF); then in the Flip function, do an SDL_Flip(); after updating the rectangle.

Hope that helps, I'll come back later and give it a proper look :)
 
Woo! Fixed by doing:

float v=0.0;

Something as simple as that.
I guess I've got a looong way to go yet.
If you can spot other bad programming practicies please let me know.

Thanks fishy.
 
Just two quick things and a question:

Initialise varibles before you use them (As you just found out ;) )
NEVER put code in header files. Function prototypes and definitions are fine but not actual code as the compiler will assume it's inline.

Are you using C or C++?
 
Normally the compiler doesn't assume code in header files is inline unless you actually tell it that. However, with standard functions (like what is shown here), if you include the .h file in two or more files, you'll get multiple declaration errors. You can get round this by making the functions static, but that will put a copy of the function into every file that #include's it.

Much better to keep the code in the .c file unless it's meant to be inlined.

Also, if a function is not meant to be called from any other file, make it static to avoid pulluting the global namespace.
 
Are you using C or C++?
C++

I'm using the Dev C++ IDE plus SDL package.

Is it best to learn C or C++ for GP2X development?

I have placed the functions in a separate *.cpp file but I get lots of

[Linker] Undefined reference to screen

... plus all of the other globals.

I'm not sure how to cross-refence all this stuff.
Maybe I've got the #includes in the wrong place?


MAIN.CPP
Code:
#include <cmath>
#include "Blitz.h"
//#include "Blitz.cpp"

using namespace std;

//       blitz example #1

int main(int argc, char *argv[]){
    Graphics(320, 240, 0);
    SetTitle("Load/Display image");

    SDL_Surface *image=LoadBMP("testimage.bmp");
    SDL_Surface *brick=LoadBMP("brick.bmp");
    
    float v=0.0;
    while (!AppClosed()){
//          Cls();
          TileImage(brick);
          DrawImage(image,60+int(sin(v)*40.0),60+int(cos(v)*30.0));
          v+=0.009;
          Flip();
    }
    FreeImage(image);
    End();
}



BLITZ.H
Code:
#include <SDL/SDL.h>
  
// globals
extern SDL_Surface *screen; // main screen
extern int gfxW;         // graphics width
extern int gfxH;         // graphics height
extern Uint8 *inkeys;

// functions
void LockScreen();
void UnLockScreen();
void End();
bool AppClosed(); 
void Graphics(int width, int height, bool full);
void SetTitle(char *text);
void Flip();
void Cls(int r=0,int g=0,int b=0);
void Plot(int x, int y, int r=255, int g=255, int b=255);
SDL_Surface *LoadBMP(char *file);
void DrawImage(SDL_Surface *img,int x,int y);
void TileImage(SDL_Surface *img);
void FreeImage(SDL_Surface *img);



BLITZ.CPP
Code:
// functions

#include "Blitz.h"

void LockScreen(){
     if (SDL_MUSTLOCK(screen)){
        if (SDL_LockSurface(screen)<0) return;
     }
}

void UnLockScreen(){
    if(SDL_MUSTLOCK(screen)){
    SDL_UnlockSurface(screen);
    }
}

void End(){
    SDL_Quit();
}

bool AppClosed(){
    SDL_Event event;
    if(!SDL_PollEvent(&event)) return 0;
    inkeys = SDL_GetKeyState(NULL);
    if(inkeys[SDLK_ESCAPE]) return 1;
    if(event.type == SDL_QUIT) return 1;
    return 0;
} 

void Graphics(int width, int height, bool full)
{
    gfxW = width;
    gfxH = height;

    if(SDL_Init(SDL_INIT_VIDEO) < 0){
       printf("Unable to init SDL: %s\n", SDL_GetError());
       SDL_Quit();
    }
    if(!full==0){
        screen = SDL_SetVideoMode(width,height,32,SDL_SWSURFACE|SDL_FULLSCREEN);
        //LockScreen();
    }
    else{
        screen = SDL_SetVideoMode(width,height,32,SDL_HWSURFACE|SDL_HWPALETTE);
    }
    if(screen == NULL)
    {
        printf("Unable to set video: %s\n", SDL_GetError());
        SDL_Quit();
    }
}

void SetTitle(char *text){
     SDL_WM_SetCaption(text, NULL);
}

void Flip(){
    SDL_UpdateRect(screen, 0, 0, 0, 0);
    SDL_Delay(1);
}

void Cls(int r,int g,int b){
    SDL_FillRect(screen, NULL, 65536 * r + 256 * g + b);
}

void Plot(int x, int y, int r, int g, int b){
    Uint32 colorSDL = SDL_MapRGB(screen->format, r, g, b);
    Uint32 *bufp;
    bufp = (Uint32 *)screen->pixels + (y % gfxH) * screen->pitch / 4 + x % gfxW;
    *bufp = colorSDL;
}

SDL_Surface *LoadBMP(char *file){
            SDL_Surface *img = SDL_LoadBMP(file);
            if ( img == NULL ){
               fprintf(stderr, "Error loading BMP %s: %s\n", file, SDL_GetError());
            }
            return img;
}

void DrawImage(SDL_Surface *img,int x,int y){     
     SDL_Rect dest;
     dest.x = x;
     dest.y = y;
     dest.w = img->w;
     dest.h = img->h;
     SDL_BlitSurface(img, NULL, screen, &dest);
}

void TileImage(SDL_Surface *img){
     SDL_Rect dest;
     dest.x=0; dest.y=0;
     dest.w = img->w; dest.h = img->h;
     while(dest.y < gfxH){
             while(dest.x < gfxW){
                     SDL_BlitSurface(img, NULL, screen, &dest);
                     dest.x+=img->w;
             };
             dest.x=0; dest.y+=img->h;
     };
}

void FreeImage(SDL_Surface *img){
     SDL_FreeSurface(img);
}
 
It seems that you have "extern SDL_Surface *screen;" but you don't actually define 'screen' in a C file.

You should have:

extern SDL_Surface *screen;

in the .h file, and:

SDL_Surface *screen;

in exactly one C file.
 
fishybawb posted on Oct 29 2005 at 03:18 PM said:
You're not using double buffering. Even if the image was moving, you'd get tearing. Init the screen with: SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE | SDL_DOUBLEBUF); then in the Flip function, do an SDL_Flip(); after updating the rectangle.
On a software surface all SDL_Flip does is call SDL_UpdateRect(screen, 0, 0, 0, 0); ;). SDL_DOUBLEBUF is for hardware surfaces only.
 
Last edited by a moderator:
woogal posted on Oct 29 2005 at 06:25 PM said:
On a software surface all SDL_Flip does is call SDL_UpdateRect(screen, 0, 0, 0, 0); ;). SDL_DOUBLEBUF is for hardware surfaces only.

D'oh! You're absolutely right of course, my bad! :)
 
Last edited by a moderator:
It seems that you have "extern SDL_Surface *screen;" but you don't actually define 'screen' in a C file
Ahh I see. I assumed these 'globals' were being defined in the Blitz.h file.
Righty dokee, I have now added this to the Blitz.cpp file and everything is good to go:
Code:
// globals
SDL_Surface *screen; // main screen
int gfxW;         // graphics width
int gfxH;         // graphics height
Uint8 *inkeys;

Thanks Squidge. Onwards and upwards.
 
You better learn to make a habit of using fixed point math instead of floating point. Like DS using ARM9, floating point math on ARM processor is such a luxury that you can't really afford.
 
codeninja posted on Oct 29 2005 at 01:33 PM said:
You better learn to make a habit of using fixed point math instead of floating point. Like DS using ARM9, floating point math on ARM processor is such a luxury that you can't really afford.

Doesn't one of the two processors have floating point support, though?
 
Last edited by a moderator:
Let him worry about fixed-point later; while learnign, stick to basics :)

As to above.. an #include just means read that named file in; so if you include a file A into B and C, its copied to both, leading to duplicate definitions. An #include is just for declarations (externs, or typedefs, or enums, or struct naming, etc. Never any real code or physical declarations.) (Until you get to C++ templates, or C with inlines, and such. But avoid that for now :)

Good luck and ncie going,

jeff
 
Ravnos posted on Oct 29 2005 at 12:43 PM said:
codeninja posted on Oct 29 2005 at 01:33 PM said:
You better learn to make a habit of using fixed point math instead of floating point.  Like DS using ARM9, floating point math on ARM processor is such a luxury that you can't really afford.

Doesn't one of the two processors have floating point support, though?

ARM9 supports floating point, but the processing time makes it all useless.
 
Last edited by a moderator:
codeninja posted on Oct 29 2005 at 10:23 PM said:
Ravnos posted on Oct 29 2005 at 12:43 PM said:
codeninja posted on Oct 29 2005 at 01:33 PM said:
You better learn to make a habit of using fixed point math instead of floating point. Like DS using ARM9, floating point math on ARM processor is such a luxury that you can't really afford.

Doesn't one of the two processors have floating point support, though?

ARM9 supports floating point, but the processing time makes it all useless.

Directly in the instruction set?

There almost always a FPU could be emulated by an exceptions.

If Arm9 does indeed have a opcodes for float maths then it's somewhat more advanced than I thought.

But to the "point" it's not that hard to do floatpoint using just intengers. There is one issue thought what must be handled manually.
 
Last edited by a moderator:
codeninja posted on Oct 29 2005 at 09:23 PM said:
ARM9 supports floating point, but the processing time makes it all useless.

ARM9 doesn't support floating point in any shape or form, but GCC can emulate them using integers. DJW managed to even get some arm assembler fp stuff in a recent GCC4 build, so floating point stuff should be pretty nippy in that version (although of course no where near as fastest as native support).
 
Last edited by a moderator:
It's been a while since I coded for a living, but from what I remember.

It's fairly normal to put get and set operations in headers, as well as statics.

Something I picked up from the code I worked with. Is this a bad habit?
 
Ok.. I think I was getting confused with the way MVC++ handles code in class definitions.. Inline functions should be REALLY short, one or two lines at most so GETS and SETS which are one liners should be fine...
 
Back
Top