Another SDL Error

Started by
1 comment, last by Dante12129 11 years, 1 month ago

I am having an error putting a background onto a screen with SDL. I have a screen class and an image class, and the screen class has a function that repeats a background across the screen. Since this function takes a pointer, I have a function in the image class that gets the pointer to the stored SDL_Surface for the image. This function always fails and returns three. Here's my code:

Screen.hpp


#ifndef SCREEN_HPP_INCLUDED
#define SCREEN_HPP_INCLUDED

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

namespace myeng
{
    class Screen final //This class doesn't need to be derived from
    {
        public:
            //Constructor and destructor
            Screen(int height, int width, std::string caption);
            ~Screen();

            //Functions to get the width, height, and depth of the screen
            int getScreen_Width();
            int getScreen_Height();
            int getScreen_Depth();

            //Function to get screen_ptr
            SDL_Surface* getScreen_Ptr();

            //Function to flip the screen
            int Screen_Flip();

            //Function to put something on the screen
            int Screen_Put(int x, int y, SDL_Surface* source);

            //Functions for backgrounds
            int Screen_RepBack(int height, int width, SDL_Surface* source);

        private:
            //Constants
            int SCREEN_WIDTH;
            int SCREEN_HEIGHT;
            int SCREEN_DEPTH;

            //Other variables
            std::string screen_name;

            //Surfaces
            SDL_Surface* screen_ptr = nullptr; //Creates the main surface for the screen
    };
}

#endif // SCREEN_HPP_INCLUDED

Screen.cpp


#include <iostream>
#include "Screen.hpp"

//Cosntructor and destructor
myeng::Screen::Screen(int height, int width, std::string caption)
{
    SCREEN_WIDTH = width;
    SCREEN_HEIGHT = height;
    SCREEN_DEPTH = 32;
    screen_ptr = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, SDL_SWSURFACE);
    SDL_WM_SetCaption(caption.c_str(), caption.c_str());
}
myeng::Screen::~Screen()
{
}

//Functions to get width, height, and depth of the screen
int myeng::Screen::getScreen_Width()
{
    return SCREEN_WIDTH;
}
int myeng::Screen::getScreen_Height()
{
    return SCREEN_HEIGHT;
}
int myeng::Screen::getScreen_Depth()
{
    return SCREEN_DEPTH;
}

//Function to get screen_ptr
SDL_Surface* myeng::Screen::getScreen_Ptr()
{
    return screen_ptr;
}

//Function to flip the screen
int myeng::Screen::Screen_Flip()
{
    if(SDL_Flip(screen_ptr) != 0)
    {
        std::cerr << "Failed to flip screen. Error" << SDL_GetError() << "\n";
        return 1;
    }
    else
    {
        return 0;
    }
}

//Function to put something on the Screen
int myeng::Screen::Screen_Put(int x, int y, SDL_Surface* source)
{
    //Create a rectangle to store the offsets of the source
    SDL_Rect offset;

    //Set the offsets
    offset.x = x;
    offset.y = y;

    //Apply the source to the screen
    if(SDL_BlitSurface(source, nullptr, screen_ptr, &offset) != 0)
    {
        std::cerr << "Failed to blit the surface. Error " << SDL_GetError();
        return 1;
    }
    else
    {
        return 0;
    }
}

//Functions for backgrounds
int myeng::Screen::Screen_RepBack(int height, int width, SDL_Surface* source)
{
    int columns = SCREEN_HEIGHT / height;
    int rows = SCREEN_WIDTH / width;

    if((SCREEN_HEIGHT % height != 0) || (SCREEN_WIDTH % width != 0))
    {
        std::cerr << "Background cannot be repeated over the screen \n";
        return 1;
    }
    else
    {
        for(int i = 0; i < columns; i++)
        {
            for(int j = 0; j < rows; j++)
            {
                Screen_Put(j*width, i*height, source);
            }
        }
    }
    return 0;
}

Image.hpp


#ifndef IMAGE_HPP_INCLUDED
#define IMAGE_HPP_INCLUDED

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

namespace myeng
{
    class Image
    {
      public:
        //Constructor and destructor
        Image(int height, int width, std::string filename);
        ~Image();

        //Functions to get member variables
        SDL_Surface* getImg_Surface();
        int getImage_Width();
        int getImage_Height();
        bool getTransparency();
        bool getOptimized();

        //Functions for loading images
        int Image_Load(int height, int width, std::string filename);

        //Functions to change images
        int Image_MakeTransparent();


      private:
        //Constants
        int IMAGE_WIDTH;
        int IMAGE_HEIGHT;

        //Image Info
        bool is_transparent;
        bool is_optimized;

        //Surfaces
        SDL_Surface* img_surface = nullptr;
    };
}

#endif // IMAGE_HPP_INCLUDED

Image.cpp


#include <iostream>
#include "Image.hpp"

//Constructor and destructor
myeng::Image::Image(int height, int width, std::string filename)
{
    is_transparent = false;
    is_optimized = false;
    Image_Load(height, width, filename);
    IMAGE_HEIGHT = height;
    IMAGE_WIDTH = width;
}
myeng::Image::~Image()
{
    SDL_FreeSurface(img_surface);
}

//Functions to get member variables
SDL_Surface* myeng::Image::getImg_Surface()
{
    return img_surface;
}
int myeng::Image::getImage_Width()
{
    return IMAGE_WIDTH;
}
int myeng::Image::getImage_Height()
{
    return IMAGE_HEIGHT;
}
bool myeng::Image::getTransparency()
{
    return is_transparent;
}
bool myeng::Image::getOptimized()
{
    return is_optimized;
}

//Functions for loading images
int myeng::Image::Image_Load(int height, int width, std::string filename)
{
    //The image that's loaded
    SDL_Surface* loadedImage = nullptr;

    //The optimized image that will be used
    SDL_Surface* optimizedImage = nullptr;

    //Load the image
    loadedImage = IMG_Load(filename.c_str());

    //If the image loaded
    if(loadedImage != nullptr)
    {
        //Log the image loading
        std::cout << "Successfully loaded: " << filename << "\n";

        //Create an optimized image
        optimizedImage = SDL_DisplayFormat(loadedImage);

        //Free the old image
        SDL_FreeSurface(loadedImage);

        //Specify the image as optimized
        is_optimized = true;
    }
    else
    {
        //Log the failure and make sure the image is specified as not optimized
        std::cerr << "Failed to load: " << filename;
        is_optimized = false;
        return 1;
    }

    //Return the optimized image
    img_surface = optimizedImage;
    SDL_FreeSurface(optimizedImage);
    return 0;
}

//Functions to change images
int myeng::Image::Image_MakeTransparent()
{
    //Check to see if the image is already transparent
    if(is_transparent == false)
    {
        //Creates the color that will be transparent
        Uint32 colorkey = SDL_MapRGB(img_surface->format, 0xED, 0x0B, 0xB5);

        //Set the transparency
        if(SDL_SetColorKey(img_surface, SDL_SRCCOLORKEY, colorkey) != 0)
        {
            std::cerr << "Error making image transparent. Error: " << SDL_GetError() << "\n";
            return 1;
        }
        else
        {
            //Set the transparency flag to true
            is_transparent = true;
            return 0;
        }
    }
    else
    {
        //Report that the image is already transparent
        std::cout << "Image is already transparent. \n";
        return 2;
    }
}

main.cpp


#include <iostream>
#include "Screen.hpp"
#include "Image.hpp"
int main ( int argc, char* argv[] )
{
if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
std::cerr << "Failed to inialize SDL. Error: " << SDL_GetError() << "\n";
return 1;
}
myeng::Screen main_screen(600, 600, "Test");
myeng::Image background(200, 200, "Background.png");
main_screen.Screen_RepBack(200, 200, background.getImg_Surface());
if(main_screen.Screen_Flip() != 0)
{
std::cerr << "Error flipping screen at line " << __LINE__ << "\n";
}
std::cout << main_screen.getScreen_Width() << "\n";
std::cout << main_screen.getScreen_Height() << "\n";
std::cout << main_screen.getScreen_Depth() << "\n";
SDL_Delay(1000);
SDL_Quit();
return 0;
}

I am compiling the Screen and Image stuff into a .dll and linking my test program to it. When I use a normal SDL_Surface* and load an image for that, it works fine. But if I try to use the Image and getImg_Surface, even making a new surface inbetween, it doesn't work and will just flash the screen before crashing and saying it returns three.

The debugger (gdb through C::B) says that the surfaces in the main_screen and background objects' internal surfaces aren't null and all the flags show that they loaded properly. It also says I'm getting a segmentation fault from SDL_GetRGB when it tries to apply the background.

Advertisement
When you free optimizedImage, you free the surface that img_surface points to, because they are the same at that point. After that, you are using an surface that has been freed, which is an error.

That was my problem, I just set it to nullptr between assigning it to img_surface and freeing it.

This topic is closed to new replies.

Advertisement