SDL_BlitSurface segmentation fault (surfaces aren't null)
- by Trollkemada
My app is crashing on SDL_BlitSurface() and i can't figure out why. I think it has something to do with my static object. If you read the code you'll why I think so.
This happens when the limits of the map are reached, i.e. (iwidth || jheight). This is the code:
Map.cpp (this render)
Tile const * Map::getTyle(int i, int j) const {
if (i >= 0 && j >= 0 && i < width && j < height) {
return data[i][j];
} else {
return &Tile::ERROR_TYLE; // This makes SDL_BlitSurface (called later) crash
//return new Tile(TileType::ERROR); // This works with not problem (but is memory leak, of course)
}
}
void Map::render(int x, int y, int width, int height) const {
//DEBUG("(Rendering...) x: "<<x<<", y: "<<y<<", width: "<<width<<", height: "<<height);
int firstI = x / TileType::PIXEL_PER_TILE;
int firstJ = y / TileType::PIXEL_PER_TILE;
int lastI = (x+width) / TileType::PIXEL_PER_TILE;
int lastJ = (y+height) / TileType::PIXEL_PER_TILE;
// The previous integer division rounds down when dealing with positive values, but it rounds up
// negative values. This is a fix for that (We need those values always rounded down)
if (firstI < 0) {
firstI--;
}
if (firstJ < 0) {
firstJ--;
}
const int firstX = x;
const int firstY = y;
SDL_Rect srcRect;
SDL_Rect dstRect;
for (int i=firstI; i <= lastI; i++) {
for (int j=firstJ; j <= lastJ; j++) {
if (i*TileType::PIXEL_PER_TILE < x) {
srcRect.x = x % TileType::PIXEL_PER_TILE;
srcRect.w = TileType::PIXEL_PER_TILE - (x % TileType::PIXEL_PER_TILE);
dstRect.x = i*TileType::PIXEL_PER_TILE + (x % TileType::PIXEL_PER_TILE) - firstX;
} else if (i*TileType::PIXEL_PER_TILE >= x + width) {
srcRect.x = 0;
srcRect.w = x % TileType::PIXEL_PER_TILE;
dstRect.x = i*TileType::PIXEL_PER_TILE - firstX;
} else {
srcRect.x = 0;
srcRect.w = TileType::PIXEL_PER_TILE;
dstRect.x = i*TileType::PIXEL_PER_TILE - firstX;
}
if (j*TileType::PIXEL_PER_TILE < y) {
srcRect.y = 0;
srcRect.h = TileType::PIXEL_PER_TILE - (y % TileType::PIXEL_PER_TILE);
dstRect.y = j*TileType::PIXEL_PER_TILE + (y % TileType::PIXEL_PER_TILE) - firstY;
} else if (j*TileType::PIXEL_PER_TILE >= y + height) {
srcRect.y = y % TileType::PIXEL_PER_TILE;
srcRect.h = y % TileType::PIXEL_PER_TILE;
dstRect.y = j*TileType::PIXEL_PER_TILE - firstY;
} else {
srcRect.y = 0;
srcRect.h = TileType::PIXEL_PER_TILE;
dstRect.y = j*TileType::PIXEL_PER_TILE - firstY;
}
SDL::YtoSDL(dstRect.y, srcRect.h);
SDL_BlitSurface(getTyle(i,j)->getType()->getSurface(), &srcRect, SDL::getScreen(), &dstRect); // <-- Crash HERE
/*DEBUG("i = "<<i<<", j = "<<j);
DEBUG("srcRect.x = "<<srcRect.x<<", srcRect.y = "<<srcRect.y<<", srcRect.w = "<<srcRect.w<<", srcRect.h = "<<srcRect.h);
DEBUG("dstRect.x = "<<dstRect.x<<", dstRect.y = "<<dstRect.y);*/
}
}
}
Tile.h
#ifndef TILE_H
#define TILE_H
#include "TileType.h"
class Tile {
private:
TileType const * type;
public:
static const Tile ERROR_TYLE;
Tile(TileType const * t);
~Tile();
TileType const * getType() const;
};
#endif
Tile.cpp
#include "Tile.h"
const Tile Tile::ERROR_TYLE(TileType::ERROR);
Tile::Tile(TileType const * t) : type(t) {}
Tile::~Tile() {}
TileType const * Tile::getType() const {
return type;
}
TileType.h
#ifndef TILETYPE_H
#define TILETYPE_H
#include "SDL.h"
#include "DEBUG.h"
class TileType {
protected:
TileType();
~TileType();
public:
static const int PIXEL_PER_TILE = 30;
static const TileType * ERROR;
static const TileType * AIR;
static const TileType * SOLID;
virtual SDL_Surface * getSurface() const = 0;
virtual bool isSolid(int x, int y) const = 0;
};
#endif
ErrorTyle.h
#ifndef ERRORTILE_H
#define ERRORTILE_H
#include "TileType.h"
class ErrorTile : public TileType {
friend class TileType;
private:
ErrorTile();
mutable SDL_Surface * surface;
static const char * FILE_PATH;
public:
SDL_Surface * getSurface() const;
bool isSolid(int x, int y) const ;
};
#endif
ErrorTyle.cpp
(The surface can't be loaded when building the object, because it is a static object and SDL_Init() needs to be called first)
#include "ErrorTile.h"
const char * ErrorTile::FILE_PATH = ("C:\\error.bmp");
ErrorTile::ErrorTile() : TileType(), surface(NULL) {}
SDL_Surface * ErrorTile::getSurface() const {
if (surface == NULL) {
if (SDL::isOn()) {
surface = SDL::loadAndOptimice(ErrorTile::FILE_PATH);
if (surface->w != TileType::PIXEL_PER_TILE || surface->h != TileType::PIXEL_PER_TILE) {
WARNING("Bad tile surface size");
}
} else {
ERROR("Trying to load a surface, but SDL is not on");
}
}
if (surface == NULL) { // This if doesn't get called, so surface != NULL
ERROR("WTF? Can't load surface :\\");
}
return surface;
}
bool ErrorTile::isSolid(int x, int y) const {
return true;
}