[SDL] Problem Displaying Surfaces!

Started by
11 comments, last by Juanu 18 years, 7 months ago
Hi. First of all i will introduce myself. My name is Juan and I'm From Argentina. I'm 21 years old. I'm a programer and recently started with C++ as well as with SDL. I'm just starting a small project with a friend and wrote a basic engine that displays Mouse-Cursor position, Sprite position and moves the sprite on the screen as well as animates it. The problem y that, I run the program and it goes well, as it shuld But my friend, who uses the same Compiler and has extacly all the same configurations as I, is having problems. He can barely see the sprite (A ball in ths case). The didn't happened to him at first, before animating the ball, but it did when he tried to run it on FullScreen. Now that i added the animation to the spriters it hjappens to him even in Windowed Mode. Please, I'll show you the code and could you tel me whats goind on? Thanx Juan

#include <tchar.h>
#include <stdlib.h>
#include "SDL.h"
#include "SDL_Image.h"
#include "SDL_ttf.h"
//Constants for window resolution and BPP
#include "definiciones.h" 
//Function to draw the sprite on the surface
#include "dibujar.h"

//Mouse position
char chrMousePos[50];
//Sprite Position
char chrSpritePos[50];
//Sprite position X Axis
int SprPosX = 200;
//Sprite position Y Axis
int SprPosY = 200;
//Time from the SDL Timer
int Tiempo = 0;
//Last loop time 
int TiempoAnterior= 0;
//Elapsed time between loops
int TiempoTrans = 0;
//Saves the time to know if it has to change frames
int MSs = 0;
//Frames per second
const int FPS = 16;
//X axis of Sprite's Rect
int frameX = 0;
//Actual Frame
int frame = 0;
//Amount of frames
const int MAX_FRAMES = 7;

//Sprite Width
const int ANCHO_SPRITE = 82;
//Spriter Height
const int ALTO_SPRITE = 82;

int main(int argc, _TCHAR* argv[])
{
	if (SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ) != 0 )
	{
        fprintf(stderr,"Error al inicializar SDL: %s\n", SDL_GetError());
		return 1;
	} 

	 if ( TTF_Init() < 0 )
	 {
	         fprintf(stderr,"Error al inicializar SDL_ttf: %s\n", SDL_GetError());
		 return 1;
	 }

	atexit(SDL_Quit);

        //Main Screen Surface
	SDL_Surface* pantalla = SDL_SetVideoMode ( VENTANA_ANCHO, VENTANA_ALTO, 0, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_NOFRAME );
	
	
	if (pantalla == NULL)
	{
		fprintf(stderr,"No se puedo establecer el modo de video: %s\n", SDL_GetError());
		return 1;
	}


	//Sprite Surface
	SDL_Surface* sprite = IMG_Load("data/gfx/bolita.png");
	
	if (sprite == NULL)
	{
		fprintf(stderr,"No se pudo cargar %s: %s\n", "bolita.png", SDL_GetError());
		return 1;
	}

	SDL_SetColorKey( sprite, SDL_SRCCOLORKEY, SDL_MapRGB(sprite->format, 255, 0, 255 ) );

	//Font
	TTF_Font* fuente = TTF_OpenFont("data/fonts/ARIAL.TTF", 14);
	if (fuente == NULL)
	{
		fprintf(stderr,"No se pudo cargar %s: %s\n", "ARIAL.TTF", SDL_GetError());
		return 1;
	}

	//ForeColor
	SDL_Color fuenteColor = { 255, 255, 255 };

	//Surface for the mouse position information
	SDL_Surface* textoSupPosMouse = TTF_RenderText_Solid(fuente, "",  fuenteColor);

	//Surface for Sprite position information
	SDL_Surface* textoSupPosSprite = TTF_RenderText_Solid(fuente, "", fuenteColor);

	//Position for mouse coords information
	SDL_Rect textoUbicaPosMouse = { 0, 0, 0, 0 };

	//Position for sprite coords information
	SDL_Rect textoUbicaPosSprite = {0, 16, 0, 0};

	//Font style
	TTF_SetFontStyle( fuente, TTF_STYLE_ITALIC );

	SDL_WM_SetCaption( VENTANA_TITULO, 0 );

	//KeyPress
	bool TeclaPress[323] = {false} ;

	//Event
         SDL_Event evento;

	//Loop Flag
         bool blnEjecutar = true;

	//Main loop	while ( blnEjecutar )
	{
	

		SDL_FillRect( pantalla, NULL, SDL_MapRGB( pantalla->format, 0, 0, 0 ) );


		if ( SDL_PollEvent( &evento ) )
		{

			if ( evento.type == SDL_QUIT )
			{
				blnEjecutar = false;
			}

			if ( evento.type == SDL_KEYDOWN )
				TeclaPress[evento.key.keysym.sym] = true;


			if ( evento.type == SDL_KEYUP )
	            TeclaPress[evento.key.keysym.sym] = false;


			if ( evento.type == SDL_MOUSEMOTION )
			{

				sprintf(chrMousePos,"Mouse: %d , %d", evento.motion.x, evento.motion.y);
			}

		}					

		if( TeclaPress[SDLK_ESCAPE] )
			blnEjecutar = false;


		if( TeclaPress[SDLK_LEFT] )
		{
			if ( SprPosX <= 0 )
				SprPosX = 0;
			else
			{
				SprPosX -= 2;

				if ( MSs >= ( 1000 / FPS ) )
				{

					MSs = 0;
					

					if ( frame <= 0 )
						frame = 7;
					else
						frame--;
				
					frameX = ANCHO_SPRITE * frame;

				}
				else
		 			MSs += TiempoTrans;
			}
		}
	

		if( TeclaPress[SDLK_RIGHT] )
		{
			if ( ( SprPosX + ANCHO_SPRITE ) >= VENTANA_ANCHO )
				SprPosX = VENTANA_ANCHO - ANCHO_SPRITE;
			else
			{
				SprPosX += 2;

			if ( MSs >= ( 1000 / FPS ) )
			{
				MSs = 0;
				

				if ( frame >= 7 )
					frame = 0;
				else
					frame++;

				frameX = ANCHO_SPRITE * frame;
			}
			else
		 		MSs += TiempoTrans;
			}
		}

		if( TeclaPress[SDLK_UP] )
		{
			if ( SprPosY <= 0 )
				SprPosY = 0;
			else
				SprPosY -= 2;
		}


		if( TeclaPress[SDLK_DOWN] )
		{	if ( ( SprPosY + ALTO_SPRITE ) >= VENTANA_ALTO )
				SprPosY = VENTANA_ALTO - ALTO_SPRITE;
			else
				SprPosY += 2;
		}



		


		Tiempo = SDL_GetTicks();
		TiempoTrans = Tiempo - TiempoAnterior;
		TiempoAnterior = Tiempo;
	



		textoSupPosMouse = TTF_RenderText_Solid( fuente, chrMousePos,  fuenteColor );
			

		sprintf(chrSpritePos,"Sprite: %d , %d", SprPosX, SprPosY);

		textoSupPosSprite = TTF_RenderText_Solid( fuente, chrSpritePos,  fuenteColor );


		SDL_BlitSurface( textoSupPosMouse, NULL, pantalla, &textoUbicaPosMouse );


		SDL_BlitSurface( textoSupPosSprite, NULL, pantalla, &textoUbicaPosSprite );


		dibujaSprite(sprite,pantalla,frameX,0,SprPosX,SprPosY,ANCHO_SPRITE,ALTO_SPRITE);


		SDL_Flip( pantalla );

	}

And this is the "dibujaSprite" function. (drawSprite)

//Receivs Sprite Surface, Screen Surface, SpriteSurface X, Y, Screen Surface X, Y and the Width and Height of the sprite.
void dibujaSprite(SDL_Surface* spriteSup, SDL_Surface* pantallaSup,
                  int spriteX, int spriteY, int pantallaX, int pantallaY,
				  int ancho, int alto)
{
   SDL_Rect spriteRect;
   spriteRect.x = spriteX;
   spriteRect.y = spriteY;
   spriteRect.w = ancho;
   spriteRect.h = alto;

   //Screen Rect
   SDL_Rect pantallaRect;
   pantallaRect.x = pantallaX;
   pantallaRect.y = pantallaY;
   pantallaRect.w = ancho;
   pantallaRect.h = alto;

   SDL_BlitSurface(spriteSup, &spriteRect, pantallaSup, &pantallaRect);
}

Any Ideas what the problem would be? Is it in the code? Bye!" Thanx!
Advertisement
Hi Juan!

Why don't you try the pre-compiled executable on your friend's computer and see what happens. Post back and then maybe we can try to have a look at your code.
Quote:
SDL_FillRect( pantalla, NULL, SDL_MapRGB( pantalla->format, 0, 0, 0 ) );

This is what is causing your problem.

You see, what's happening is that over and over again, you're clearing the screen and then blitting the sprite to it. What happens when the time after the screen is cleared, before the sprite is drawn, is longer than the time after the sprite is drawn, before the screen is cleared again? You see the cleared screen most of the time, and the sprite only some of the time.

This problem is solved by using a buffering system. The simplest method is to create another SDL_Surface that is compatible with the screen surface, and do your clearing and drawing to it. Then, after you're finished with all the drawing, you do a direct blit from the buffer surface to the screen surface. You don't have to worry about clearing the screen surface, because the pixels in the buffer surface have already been cleared and drawn, and will copy over the old pixels in the screen surface.

One other thing to think about sometime down the road is timing. Each computer will try to run your code as fast as possible, and faster computers will therefore run it faster than slower computers. This means that on a slower computer your sprite might move 60 pixels per second when you press the arrow key, and on a faster computer it might move 600 pixels per second. Read up on the relevant articles here at GameDev for more information on how to solve this -- also, the SDL documentation contains a simple example of how to solve it.

Cheers,
Twilight Dragon
{[JohnE, Chief Architect and Senior Programmer, Twilight Dragon Media{[+++{GCC/MinGW}+++{Code::Blocks IDE}+++{wxWidgets Cross-Platform Native UI Framework}+++
Thanx a lot!

I'll try it...

So you sayI do the fillrect on the backbuffer, then draw the sprite on that backbuffer too and then draw that surface entirely on the main surface???

Is that ok??

Thanx!
hey, I'm having a question..
What do you mean when you say

"create another SDL_Surface that is compatible with the screen surface"

What do ou mean
Make a SUrface with SetVideoMode exactly like the main surface?

Or how?

Example please???

Thanx a lot!

Are the Cone3D tutorial getting you down? Do you have a case of the Cone3D SDL tutorial bug? Well, look no further, Aaron Cox's Tutorials are here!

I find the Cone3D tutorials horribly written. Their solutions for problems are discusting and they don't explain what you need to know, and why. Start fresh with a better tutorial site and you'll start to grasp the concepts of SDL much better.
Rob Loach [Website] [Projects] [Contact]
Quote:Original post by Juanu
"create another SDL_Surface that is compatible with the screen surface"

Say SDL_Surface *screen is your screen surface, and SDL_Surface *todraw is the surface you are drawing, use

screen = SDL_DisplayFormat(todraw);

About the flickering, try using SDL_SWSURFACE|SDL_FULLSCREEN as your flags when you set up your screen.
FullScreen is better?

"About the flickering, try using SDL_SWSURFACE|SDL_FULLSCREEN as your flags when you set up your screen"


Shouldn't I use SDL_HWSURFACE? Since Memory video for games is faster???


No you can leave out the fullscreen. I remembered that in the Cone3D sprite tutorial, people had flickering problems. The one I posted earlier was the first solution. The other one you can try:

InitImages();
DrawBG();
SDL_Flip(screen);
DrawBG();

In your case, DrawBG() would be (I think)

SDL_FillRect( pantalla, NULL, SDL_MapRGB( pantalla->format, 0, 0, 0 ) );

This is so that both your buffers have the background image.

This topic is closed to new replies.

Advertisement