Sign in to follow this  
Sethcran

SDL Why would a blit fail?

Recommended Posts

So, continuing on my current project ( I'm still a newbie :( ), I've run into a small snag, and I'm not quite sure what is causing it. I have an assertion in part of my code that calls the SDL_BlitSurface function, and it is failing ( meaning it is returning -1 ) but I can't seem to find a set of causes for this in the SDL documentation. What is happening is that i'm trying to blit a small ball to the screen, and it works perfectly on the first frame, but after the first frame, the blit fails. Just looking for some input as to what might be the cause of this so that I can go about fixing it. I did check to make sure the appropriate variables didn't go out of scope, but they are all private members of an object still in scope. I checked that no memory was getting deleted when it shouldn't be, and am quite sure that is not the case. Here is the code leading to and causing the problem.
The actual assertion failure occurs within the Apply function when BlitSurface is called.

void Driver::Render()
{
	SDL_FillRect( screen.GetSurface(), NULL, SDL_MapRGB( screen.GetSurface()->format, 0xFF, 0xFF, 0xFF ) );

	if ( ball != NULL )
	{
		BallInfo info = ball->GetInfo();
		screen.Apply( info.x, info.y, ball->GetImage().GetSurface(), NULL );
	}

	SDL_Flip( screen.GetSurface() );
}



void Surface::Apply( int x, int y, SDL_Surface* source, SDL_Rect* clip )
{
	/* Applies a surface source another labeled destination at the x,y coordinates
	passed in. */

	SDL_Rect offset;
	offset.x = x;
	offset.y = y;
	assert ( SDL_BlitSurface( source, clip, surface, &offset ) != -1 );
}	


Surface Ball::GetImage()
{
	return ballImage;
}



SDL_Surface* Surface::GetSurface()
{
	return surface;
}

And then my header files so far if it helps:
#ifndef BALL_H
#define BALL_H

#include <string>
#include "surface.h"

const int BALL_WIDTH = 10;
const int BALL_HEIGHT = 10;
const int DEFAULT_X = 305;
const int DEFAULT_Y = 400;

const std::string BALL_LOCATION = "images\\ball.png";

struct BallInfo
{
	int x, y;				// Position variables.
	int vx, vy;				// Velocity variables.
};

class Ball
{
public:
	Ball( int startingx = DEFAULT_X, int startingy = DEFAULT_Y );
	BallInfo GetInfo();	
	Surface GetImage();
	void ChangeVelocity( int velx, int vely );

private:
	BallInfo info;
	Surface ballImage;		// Holds the image of the ball ball.png.

};

#endif




#ifndef DRIVER_H
#define DRIVER_H

#include "surface.h"
#include "ball.h"
#include <string>

const int SCREEN_WIDTH = 600;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

const std::string FONT_LOCATION = "data\\Calibri.ttf";
const int FONT_SIZE = 18;

class Driver
{
public:
	Driver();
	~Driver();
	void Events();
	void Logic();
	void Render();
	bool Quit();

private:
	void ProcessKeyEvents( SDL_Event* input );
	void SetNewGame();
	bool quit;
	SDL_Color textColor;
	Surface screen;
	Surface font;
	Ball* ball;

};
#endif




#ifndef SURFACE_H
#define SURFACE_H

#include <string>
#include "SDL.h"
#include "SDL_ttf.h"

const int RED = 255, GREEN = 0, BLUE = 0, ALPHA = 0;		// Color to render text, currently red.
const Uint8 CCRED = 255, CCGREEN = 255, CCBLUE = 255;		// Color to be transparent in images, currently White.

class Surface
{
public:
	Surface();
	Surface( std::string fileName );				// Load image surface.
	Surface( std::string fileName, int size );		// Load font surface.
	~Surface();
	void Apply( int x, int y, SDL_Surface* source, SDL_Rect* clip );
	SDL_Surface* GetSurface();
	void SetSurface( SDL_Surface* s );
	TTF_Font* GetFont();

private:
	SDL_Surface* surface;
	TTF_Font* font;
	SDL_Color textColor;

};
#endif

Share this post


Link to post
Share on other sites
First off, never use assert() for errors that could conceivably occur when you release your program. Use some other form of error handling for those kind of errors.

Remember what an assertion means: at this point in the program I know this statement should be true. Not: I would like this statement to be true.

Another issue is that your function Ball::GetImage() returns a surface by value. Because your Surface class does not respect the rule of three this won't work.

If you aren't prepared to provide your own copy constructor and assignment operator, then you can use the following method to prevent accidental copies being made of your class:

class noncopyable
{
protected:
noncopyable(){}
private:
// These are declared private and are deliberately not implemented.
// Do NOT try to copy instances of classes derived from noncopyable.
noncopyable(const noncopyable &);
noncopyable &operator=(const noncopyable &);
};

class Surface : noncopyable
{
// as before
};


For some interesting discussion recently on implementing a wrapper over SDL surfaces, read this thread.

The main reasons that SDL_BlitSurface() fails (in my experience) are if you try to blit a NULL pointer or if video memory is lost (when working with hardware surfaces).

That said, your Surface class isn't as encapsulated as it could be. Consider if you made a function Surface::FillRect(int r, int g, int b), and if Surface::Apply's third parameter was a Surface reference, not a raw SDL_Surface pointer.

If you did this, you could remove the function GetSurface() and SetSurface(), which I don't think you should have.

I think you should move the font stuff out of the surface class into a separate class. E.g:

class Font : noncopyable
{
public:
Font(const std::string &filename, int pointsize);
~Font();

SDL_Surface render(const std::string &text, const SDL_Color &colour);
private:
// whatever
};

class Surface : noncopyable
{
public:
Surface(const std::string &filename);
Surface(Font &font, const std::string &text, const SDL_Color &colour)
{
// use font.render(text,colour) to generate the surface.
}

// the rest as before...

private:
// ...
};

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this