SDL_ttf textures in vector affects other's destination rectangle - c++

I was following Lazy Foo' tutorial to create text using ttf font, and everything was fine, but I needed to create several text lines in several different places with different font size and color, so I decided to use vector. Here is my code of TextTexture (mostly copy of Lazy Foo tutorial):
#ifndef TEXT_TEXTURE_HPP
#define TEXT_TEXTURE_HPP
#include "graphics.hpp"
#include "vector2.hpp"
#include <SDL2/SDL_ttf.h>
#include <string>
class TextTexture {
public:
TextTexture(
Graphics& graphics,
TTF_Font* font,
std::string textureText,
SDL_Color textColor,
Vector2 coordinates
);
~TextTexture();
void draw( Graphics& graphics );
private:
SDL_Texture* mTexture;
int mWidth;
int mHeight;
int mX;
int mY;
};
#endif // TEXT_TEXTURE_HPP
And .cpp file for it:
#include "text_texture.hpp"
#include "vector2.hpp"
#include <iostream>
#include <unistd.h>
TextTexture::TextTexture (
Graphics& graphics,
TTF_Font* font,
std::string textureText,
SDL_Color textColor,
Vector2 coordinates
) :
mTexture(NULL),
mWidth(0),
mHeight(0),
mX(0),
mY(0)
{
//Render temp surface
SDL_Surface* tempSurface = TTF_RenderUTF8_Blended (font, textureText.c_str(), textColor);
if ( tempSurface == NULL ) {
std::cout << "Unable to render text surface! SDL_ttf Error: " << TTF_GetError() << std::endl;
} else {
this -> mTexture = SDL_CreateTextureFromSurface(graphics.getRenderer(), tempSurface);
if ( this -> mTexture == NULL ) {
std::cout << "Unable to create texture from rendered text! SDL Error: " << SDL_GetError() << std::endl;
} else {
//Get image dimensions
mWidth = tempSurface -> w;
mHeight = tempSurface -> h;
// Get coordinates
this -> mX = coordinates.getX();
this -> mY = coordinates.getY();
}
SDL_FreeSurface (tempSurface);
tempSurface = NULL;
}
}
TextTexture::~TextTexture() {
//Free texture if it exists
if ( mTexture != NULL ) {
SDL_DestroyTexture( mTexture );
}
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
// FIXME somewhy affects previous dest rects
void TextTexture::draw (Graphics& graphics) {
//Set rendering space and render to screen
SDL_Rect destinationRectangle = { mX, mY, this -> mWidth, this -> mHeight };
//Render to screen
graphics.blitSurface( mTexture, NULL, &destinationRectangle );
}
I created simple Text Manager to handle vector of texts:
#ifndef TEXT_MANAGER_HPP
#define TEXT_MANAGER_HPP
#include "graphics.hpp"
#include "text_texture.hpp"
#include "vector2.hpp"
#include <string>
#include <vector>
enum fontSize {
SMALL = 16,
NORMAL = 32,
BIG = 48,
TITLE = 72
};
enum fontColor {
WHITE,
ORANGE,
BLACK
};
class TextManager {
public:
TextManager(Graphics& graphics);
~TextManager();
void addText(std::string, fontSize, fontColor, Vector2);
void draw();
void clearText();
private:
Graphics& graphics;
std::vector <TextTexture> gText;
};
#endif // TEXT_MANAGER_HPP
and .cpp file:
#include "text_manager.hpp"
#include <iostream>
TextManager::TextManager(Graphics& graphics) :
graphics(graphics)
{}
TextManager::~TextManager() {}
void TextManager::addText(std::string text, fontSize size, fontColor color, Vector2 coordinates) {
TTF_Font* tempFont = TTF_OpenFont( "resources/fonts/pixel.ttf", fontSize::TITLE );
SDL_Color tempColor = { 255, 255, 255 };
// Switch removed for shorter code
this -> gText.emplace_back(graphics, tempFont, text, tempColor, coordinates);
TTF_CloseFont(tempFont);
tempFont = NULL;
}
// FIXME
void TextManager::draw() {
std::vector<TextTexture>::iterator it;
for(it = gText.begin(); it != gText.end(); ++it) {
it -> draw(graphics);
}
}
void TextManager::clearText() {
gText.clear();
}
But when I start the application, I see something like this:
Second string is printed, but font and bonding rectangle of first line is saved, hovewer
Later I added input handler that added second line of text after pressing a button, and when there is only one line of text, everything fine, but when you add second, something weird is beginning - sometimes first text disappears, sometimes 'both' of them is shoved. As I understand, second surface of text somehow affects first one, by copying it texture on the place of the first's destination.
Here is my graphics.blitSurface, if it will help:
void Graphics::blitSurface(SDL_Texture* texture, SDL_Rect* sourceRectangle, SDL_Rect* destinationRectangle)
{
SDL_RenderCopy ( this -> _renderer, texture, sourceRectangle, destinationRectangle );
}
Where is my mistake? Sorry for bad english, I hope you will get my problem.

I figured it out somehow randomly. The thing is that when I adding object to vector, it's calls a destructor.
Here is why:
Why does my class's destructor get called when I add instances to a vector?

Related

Rendering text with SDL2, problems updating texture / output

I have recently started using SDL2 in a C++ project, which is mainly used as a training project so I can learn using SDL2.
One of the things I tried, was to write a simple label class. The Idea is that the label is created with given position and dimensions at start. Then when I call my 'setText()' function, the text would be rendered and shown on window. At first I used this approach:
// get a surface from given text
m_surf = TTF_RenderText_Solid(m_font, txt.c_str(), fgCol);
// get a texture from the previous surface
m_texture = SDL_CreateTextureFromSurface(r, m_surf);
// render it in 'r' which is the window renderer
SDL_RenderCopy(r, m_texture, NULL, &rect);
This works for me. So I thought to remove the overhead of creating textures every time text changes, then destroy them, and use SDL_UpdateTexture().
Well, this never worked! It always produces a corrupt output on screen, even though the call is successful:
// Once at ctor create a texture
m_texture = SDL_CreateTexture(r, SDL_PIXELFORMAT_RGBA32,SDL_TEXTUREACCESS_STATIC, rect.w, rect.h);
// ...
// later update when setText() is called get a surface from given text and update texture
m_surf = TTF_RenderText_Solid(m_font, txt.c_str(), fgCol);
rc = SDL_UpdateTexture(m_texture, NULL, m_surf->pixels, m_surf->pitch);
My first thought was that it's something wrong with the pixel formatting... so I also used a format convert before updating:
m_surf = SDL_ConvertSurfaceFormat(ts, SDL_PIXELFORMAT_RGBA32, 0);
where 'ts' is a temp surface where the text was rendered, and constant SDL_PIXELFORMAT_RGBA32 is same as the one I used to create the m_texture.
here is what I get on window when using 'SDL_UpdateTexture()'
Any Ideas ?
Thank you,
Alex
Code Snip:
I have written a compact piece of code that is related to reproduce problem
// label class declaration
class label
{
friend class panel;
public:
label(SDL_Window* const w, TTF_Font* const fnt, SDL_Rect rect);
~label();
int draw(SDL_Rect& rect);
int draw(SDL_Rect& rect,const std::string& txt, SDL_Color fgCol, int quality);
private:
std::string m_txt;
TTF_Font* const m_font = nullptr;
SDL_Surface *m_surf = nullptr;
SDL_Texture *m_texture = nullptr;
SDL_Rect m_rect{0,0,0,0};
SDL_Renderer *m_ren;
SDL_Window *m_wnd;
Uint32 m_pixForm;
};
// label class constructor
label::label(SDL_Window* const w, TTF_Font* const fnt, SDL_Rect rect):m_wnd(w),m_font(fnt),m_surf (nullptr), m_rect(rect)
{
// save window info locally for label object
m_ren =SDL_GetRenderer(m_wnd);
m_pixForm =SDL_GetWindowPixelFormat(m_wnd);
m_texture = SDL_CreateTexture(m_ren, m_pixForm,SDL_TEXTUREACCESS_STATIC, rect.w, rect.h);
m_surf = nullptr;
std::cout << "PixelFormat " << m_pixForm << " : " << SDL_GetPixelFormatName(m_pixForm) << std::endl;
}
// label class methods to render/draw text on screen
int label::setText(const std::string& txt, SDL_Color fgCol, int quality=0)
{
int w,h;
SDL_Surface *ts;
if(m_surf!=nullptr)SDL_FreeSurface(m_surf);
switch(quality)
{
case 1:
{
ts = TTF_RenderText_Shaded(m_font, txt.c_str(), fgCol, SDL_Color{0,0,0,0});
break;
}
case 2:
{
ts = TTF_RenderText_Blended(m_font,txt.c_str(), fgCol);
break;
}
default:
{
ts = TTF_RenderText_Solid(m_font, txt.c_str(), fgCol);
break;
}
}
std::cout << "Before pixFormat ts " << SDL_GetPixelFormatName(ts->format->format)<< std::endl;
m_surf = SDL_ConvertSurfaceFormat(ts, m_pixForm, 0);
std::cout << "After pixFormat surf : " << SDL_GetPixelFormatName(m_surf->format->format) << " ts " << SDL_GetPixelFormatName(ts->format->format)<< std::endl;
SDL_FreeSurface(ts);
TTF_SizeText(m_font, txt.c_str(), &w, &h);
std::cout << "Set text '" << txt << "' w: " << w << " h: " << h << std::endl;
}
int label::draw(SDL_Rect& rect)
{
// HERE is the one that draw the noise on screen!
{
int rc;
rc = SDL_UpdateTexture(m_texture, NULL, m_surf->pixels, m_surf->pitch);
if(rc)
{
std::cout << "Error updating texture " << rc <<std::endl;
return(rc);
}
}
// if it is replaced with the following it works:
/*
{
if(m_texture!=nullptr)SDL_DestroyTexture(m_texture);
m_texture = SDL_CreateTextureFromSurface(r, m_surf);
}
*/
SDL_RenderCopy(m_ren, m_texture, NULL, &rect);
}
int label::draw(SDL_Rect& rect,const std::string& txt, SDL_Color fgCol, int q)
{
setText(txt,fgCol,q);
draw(rect);
}
// main functiom. Init SDL, create window, create label and draw it:
int main( int argc, char * argv[] )
{
SDL_Window *wnd ;
SDL_Renderer *wrend;
int i;
wnd = SDL_CreateWindow("TestWin",SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,500,300,0);
wrend = SDL_CreateRenderer(wnd,-1,SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawBlendMode(wrend,SDL_BLENDMODE_ADD);
SDL_SetRenderDrawColor(wrend,0,0,0,255);
SDL_RenderClear(wrend);
SDL_Color fcol{255,255,0,128};
SDL_Rect lblBox;
lblBox.h = 120;
lblBox.w = 280;
lblBox.x = 1;
lblBox.y = 1;
label lbl(wnd, getCurrentFont(), lblBox); // create a label (getCurrentFont returns a valid TTF_Font pointer)
lbl.draw(lblBox,std::string("Text Test"), fcol, 2);
SDL_RenderPresent(wrend);
SDL_ShowWindow(wnd);
// .. more code here
}
I tested your code on MacOS Catalina and last version of SDL2 and SDL2_ttf and had segmentation fault.
After debugging I found that in label::setText() you use a quality parameter and if you pass quality=2 (to use the function TTF_RenderText_Blended()), you will end up with a segmentation fault or garbage pixels.
But functions TTF_RenderText_Shaded() and TTF_RenderText_Solid() work well, I think this is directly linked to the fact that with TTF_RenderText_Blended() you have transparency in your surface.
Edit:
After digging a bit more I solved the segmentation fault I had previously by replacing the NULL value for the rect in line :
rc = SDL_UpdateTexture(m_texture, NULL, m_surf->pixels, m_surf->pitch);
by the size of m_surf:
SDL_Rect SurfRect;
SurfRect.x = 0;
SurfRect.y = 0;
SurfRect.w = m_surf->w;
SurfRect.h = m_surf->h;
...
rc = SDL_UpdateTexture(m_texture, SurfRect, m_surf->pixels, m_surf->pitch);
Edit 2 :
I directly look into the source file of the SDL2 to understand what was the difference between my tests and the code done internally by the function SDL_CreateTexture() and you have to add these lines :
int rc = SDL_UpdateTexture(m_texture, &SurfRect, m_surf->pixels, m_surf->pitch);
{
Uint8 r, g, b, a;
SDL_BlendMode blendMode;
SDL_GetSurfaceColorMod(m_surf, &r, &g, &b);
SDL_SetTextureColorMod(m_texture, r, g, b);
SDL_GetSurfaceAlphaMod(m_surf, &a);
SDL_SetTextureAlphaMod(m_texture, a);
if (SDL_HasColorKey(m_surf)) {
/* We converted to a texture with alpha format */
SDL_SetTextureBlendMode(m_texture, SDL_BLENDMODE_BLEND);
} else {
SDL_GetSurfaceBlendMode(m_surf, &blendMode);
SDL_SetTextureBlendMode(m_texture, blendMode);
}
}
Find here my raw debug file (this isn't pretty)

Garbage values when accessing SDL_Rect members from an array?

I've been following LazyFoo's SDL tutorials (and also adding my own organization and coding style). When I got to his animation tutorial I decided to make a separate class to store the variables and methods related to the animation algorithm, rather than having global variables. He uses an array of SDL_Rects to define the boundaries of different sprites on a sprite sheet, so I used an SDL_Rect pointer to store the array in my custom class. When I compiled everything I didn't see an animation, when I compiled the original source code I did. When I started debugging things, I found that when I was rendering the sprites, the rects were actually full of garbage, even though when I initialize them the rects are just fine. I've tried to simplify the problem so many times, but every approach I take to recreate the bug in a simpler environment actually works as expected! So with that in mind I apologize for the large amount of code, because I can't seem to reduce the problem.
texture.h
#ifndef TEXTURE_H
#define TEXTURE_H
#include <SDL2/SDL.h>
#include <string>
class Animation {
public:
Animation(SDL_Renderer* renderer);
~Animation();
void load(std::string path, int frames, SDL_Rect* clips),
free(),
render(int x, int y),
next_frame();
private:
SDL_Renderer* _renderer=NULL;
SDL_Rect* _clips=NULL;
SDL_Texture* _texture=NULL;
int _frame=0, _frames=0, _width=0, _height=0;
};
#endif
texture.cpp
#include <stdio.h>
#include <SDL2/SDL_image.h>
#include "texture.h"
#include "error.h"
Animation::Animation(SDL_Renderer* renderer) {
_renderer = renderer;
}
Animation::~Animation() {
free();
_renderer = NULL;
}
void Animation::load(std::string path, int frames, SDL_Rect* clips) {
free();
SDL_Texture* texture = NULL;
SDL_Surface* surface = IMG_Load(path.c_str());
if (!surface)
throw ErrorIMG("Could not load image "+path);
SDL_SetColorKey(surface, SDL_TRUE,
SDL_MapRGB(surface->format, 0, 0xFF, 0xFF));
texture = SDL_CreateTextureFromSurface(_renderer, surface);
if (!texture)
throw ErrorSDL("Could not create texture from image "+path);
_width = surface->w;
_height = surface->h;
SDL_FreeSurface(surface);
_frames = frames;
_clips = clips;
printf("clips[%d]: w: %d h: %d\n", 0, _clips[0].w, _clips[0].h);
}
void Animation::free() {
if (_texture) {
SDL_DestroyTexture(_texture);
_texture = NULL;
_clips = NULL;
_frames = 0;
_frame = 0;
_width = 0;
_height = 0;
}
}
void Animation::render(int x, int y) {
SDL_Rect crect = _clips[_frame/4];
printf("in render (clips[%d]): w: %d, h: %d\n", _frame/4, crect.w, crect.h);
SDL_Rect render_space = {x, y, crect.w, crect.h};
SDL_RenderCopy(_renderer, _texture, &_clips[_frame], &render_space);
}
void Animation::next_frame() {
SDL_Rect crect = _clips[_frame/4];
printf("in next frame (clips[%d]): w: %d, h: %d\n", _frame/4, crect.w, crect.h);
++_frame;
if (_frame/4 >= _frames)
_frame = 0;
}
game.h
#ifndef GAME_H
#define GAME_H
#include "texture.h"
class Game {
public:
Game();
~Game();
void main();
private:
void load_media();
SDL_Window* _window=NULL;
SDL_Renderer* _renderer=NULL;
Animation* _anim=NULL;
const int SCREEN_WIDTH=640, SCREEN_HEIGHT=480;
};
#endif
game.cpp
#include <SDL2/SDL_image.h>
#include "game.h"
#include "error.h"
void Game::main() {
load_media();
bool has_quit = false;
SDL_Event event;
while (!has_quit) {
while (SDL_PollEvent(&event))
if (event.type == SDL_QUIT)
has_quit = true;
SDL_SetRenderDrawColor(_renderer, 0xff, 0xff, 0xff, 0xff);
SDL_RenderClear(_renderer);
_anim->render(100, 100);
_anim->next_frame();
SDL_RenderPresent(_renderer);
}
}
Game::Game() {
if (SDL_Init(SDL_INIT_VIDEO))
throw ErrorSDL("SDL could not initialize");
_window = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH,
SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (!_window)
throw ErrorSDL("Window could not be created");
Uint32 render_flags = SDL_RENDERER_ACCELERATED;
render_flags |= SDL_RENDERER_PRESENTVSYNC;
_renderer = SDL_CreateRenderer(_window, -1, render_flags);
if (!_renderer)
throw ErrorSDL("Renderer could not be created");
SDL_SetRenderDrawColor(_renderer, 0xff, 0xff, 0xff, 0xff);
if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG))
throw ErrorIMG("SDL_image could not initialize");
}
Game::~Game() {
delete _anim;
SDL_DestroyRenderer(_renderer);
SDL_DestroyWindow(_window);
_renderer = NULL;
_window = NULL;
IMG_Quit();
SDL_Quit();
}
void Game::load_media() {
const int nclips = 4;
SDL_Rect clips[nclips];
for (int i=0; i < nclips; i++) {
clips[i].x = i*64;
clips[i].y = 0;
clips[i].w = 64;
clips[i].h = 164;
}
_anim = new Animation(_renderer);
_anim->load("sheet.png", nclips, &clips[0]);
}
You're storing a pointer to a temporary. The SDL_Rect* clips pointer that you pass to Animation::load is assigned to the member _clips used after the function returns. For this to work correctly, the data that is pointed to needs to live for as long as the Animation class is using it. The problem arises here:
void Game::load_media() {
const int nclips = 4;
SDL_Rect clips[nclips];
...
_anim->load("sheet.png", nclips, &clips[0]);
}
In this piece of code, clips is a local variable. That means it gets destroyed at the end of load_media(), and the memory contents at that location will become garbage.
There are a number of ways you could fix this. A simple one would be to use std::vector<SDL_Rect> instead of SDL_Rect*. std::vector can safely be copied and manages its internals for you. Your new code could look like:
class Animation {
...
std::vector<SDL_Rect> _clips;
...
}
void Animation::load(std::string path, int frames, std::vector<SDL_Rect> clips) {
...
_clips = clips;
...
}
void Game::load_media() {
const int nclips = 4;
std::vector<SDL_Rect> clips;
clips.resize(nclips);
...
_anim->load("sheet.png", nclips, clips);
}
And dont forget to #include <vector>. Documentation for std::vector is here. Note that std::vector has a size() method that can probably replace frames everywhere it appears.
The stack-allocated Game::load_media()::clips array disappears when it goes out of scope. Make a copy in Animation::load() instead of only storing a pointer.

Custom font class crashes game

I'm using C++ with the SDL2 library to create a game. I'm using the SDL_ttf extension to be able to use ttf fonts and I'm trying to create my own class that would be more effective for multiple texts on the screen. The code I currently have starts out good, then crashes after about 15 seconds of running. I added more text and now it crashes after about 5 or 7 seconds. I'm looking for advice on how to solve this problem. my full Font class is as follows:
Font.h
#pragma once
#include "Graphics.h"
#include <string>
class Font
{
public:
Font(std::string path, SDL_Renderer* renderer);
~Font();
void FreeText();
void LoadText(int size, RGB_COLOR color, std::string text);
void Draw(int x, int y, Graphics& gfx, int size, RGB_COLOR color, std::string text);
private:
int width,height;
TTF_Font* font;
SDL_Texture* mTexture;
SDL_Renderer* renderer;
std::string path;
};
Font.cpp
#include "Font.h"
Font::Font(std::string path, SDL_Renderer* renderer)
:
font(NULL),
mTexture(NULL),
renderer(renderer),
path(path)
{
printf("Font con..\n");
}
Font::~Font()
{
}
void Font::LoadText(int size, RGB_COLOR color, std::string text)
{
font = TTF_OpenFont(path.c_str(), size);
SDL_Color c = {color.RED, color.GREEN, color.BLUE};
SDL_Surface* loadedSurface = TTF_RenderText_Solid(font, text.c_str(), c);
mTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
width = loadedSurface->w;
height = loadedSurface->h;
SDL_FreeSurface(loadedSurface);
}
void Font::FreeText()
{
SDL_DestroyTexture(mTexture);
mTexture = NULL;
}
void Font::Draw(int x, int y, Graphics& gfx, int size, RGB_COLOR color, std::string text)
{
FreeText();
LoadText(size, color, text);
SDL_Rect rect = {x, y, width * gfx.GetGameDims().SCALE, height * gfx.GetGameDims().SCALE};
gfx.DrawTexture(mTexture, NULL, &rect);
}
My Graphics class just handles the actual drawing as well as dimensions of the game (screen size, tile size, color struct, gamestates, etc) So when I'm calling gfx.Draw it calls SDL_RenderCopy function.
Within my Game class I have a pointer to my Font class. (its called in my Game constructor) Then font->Draw() is called every frame; which destroys the original SDL_Texture, Loads the new text, then renders it on the screen.
My ultimate goal is to have my font class set up to where I choose the color and size from my draw function. Not sure what to check from this point on..
Any suggestions? Ideas?
This is what I get (which is what I want) but then it crashes.
I've managed to get it working. After searching a little more on SDL_ttf, I realized that in my FreeFont() function I was clearing out the SDL_Texture, however I did nothing with the TTF_Font.
Adding these lines in that function did the trick:
TTF_CloseFont(font);
font = NULL;

Displaying a PNG in SDL?

I am trying to get a knight on a horse (inauspiciously named "guy") to run across the screen. The knight currently exists in my directory as 2 .png files, to simulate some poorly animated galloping. I was able to get him to appear when he was a .bmp, but I would like to utilize the transparency of png files - I've also tried and failed with opening tif files. How can I alter my code in order to get him to appear from a .png loaded into SDL correctly?
Here is my .cpp file:
#include "SDL/SDL.h"
#include <iostream>
#include "source_sdl.h"
# include <string>
using namespace std;
int source_sdl( int argc, char* args[] ) {
int switch = 1;
int running = 1;
// surface & rect declarations
SDL_Surface* ground = NULL;
SDL_Surface* guy = NULL;
SDL_Surface* guy2 = NULL;
SDL_Rect guylocationRect;
SDL_Rect groundlocationRect;
// initialize SDL & the screen
SDL_Init( SDL_INIT_EVERYTHING );
screen = SDL_SetVideoMode( 875, 625, 32, SDL_SWSURFACE );
// open .png files
SDL_RWops* guy_rwop;
SDL_RWops* guy2_rwop;
guy_rwop = SDL_RWFromFile("tiffKnight.png", "rb");
guy2_rwop = SDL_RWFromFile("tiffKnight2.png", "rb");
guy = IMG_LoadPNG_RW(guy_rwop);
guy2 = IMG_LoadPNG_RW(guy2_rwop);
guylocationRect.x = 300;
guylocationRect.y = 300;
groundlocationRect.x = 300;
groundlocationRect.y = 300;
SDL_Event occur;
// animation loop (currently endless)
while (running == 1){
SDL_Flip( screen );
SDL_Delay( 300 );
if (gallop > 89) gallop=0;
// draw the ground
for( int yu = 0; yu<35; yu++){
groundlocationRect.x=25*yu;
groundlocationRect.y=5*25;
SDL_BlitSurface( ground, NULL, screen, &groundlocationRect );
}
// draw the gallopping
guylocationRect.x=10*gallop;
guylocationRect.y=5*25;
if( switch ){
SDL_BlitSurface( guy, NULL, screen, &guylocationRect );
}else{
SDL_BlitSurface( guy2, NULL, screen, &guylocationRect );
}
gallop++;
switch = (switch+1)%2;
for(int u = 6; u < 25; u++){
for(int yu = 0; yu < 35; yu++){
groundlocationRect.x = 25*yu;
groundlocationRect.y = 25*u;
SDL_BlitSurface( ground, NULL, screen, &groundlocationRect );
}
}
}
SDL_FreeSurface( guy );
SDL_FreeSurface( guy2 );
SDL_FreeSurface( ground );
}
As I currently have it, the knight does not appear and I receive no errors (a consequence of the SDL screen being open?) Fail checks such as
if(!guy) {
cout << "IMG_LoadPNG_RW: %s\n" << IMG_GetError();
}
Have also yielded no results. my .h file is simply:
#include "SDL/SDL.h"
#include <iostream>
using namespace std;
int source_sdl( int argc, char* args[] );
And my main.cpp:
#include "SDL/SDL.h"
#include <iostream>
#include "source_sdl.h"
using namespace std;
int main( int argc, char* args[] ){
source_sdl( argc, args );
}
If you really want to stick with SDL in C++, I suggest you to use the SDL_image library and use a function like :
SDL_Surface * load_image(std::string const & filename)
{
SDL_Surface * img = NULL;
SDL_Surface * tmp = IMG_Load(filename.c_str());
if (tmp)
{
img = SDL_DisplayFormatAlpha(tmp);
SDL_FreeSurface(tmp);
}
return img;
}
An example of a more modern and safe approach would looke like this:
using surface_ptr = std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)>;
surface_ptr load_image (std::string const & filename)
{
surface_ptr img { nullptr, &SDL_FreeSurface };
surface_ptr tmp { IMG_Load(filename.c_str()), &SDL_FreeSurface };
if (tmp)
img.reset(SDL_DisplayFormatAlpha(tmp.get()));
return img;
}
Or better, use an existing C++ Binding like libSDL2pp (I have nothing to do with them).

exc_bad_access error xcode5 c++ sdl2

I've been toying with this code a guy on youtube attached to one of his tutorial videos... I've run into a few problems that I cant seem to get past... The current one is this 'EXC_BAD_ACCESS' error... From what I've researched briefly online these errors occur when you improperly use the stack and allocate memory to things that no longer exist or something like that... I just can't pinpoint what I'm doing wrong exactly... I've seen some troubleshooting done -- but nothing for xcode 5 yet
The error shows up in a class called 'cSprite.cpp':
// ~~~~~~~~~~~~~~~~~~~ cSprite.cpp ~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "stdafx.h"
#include "cSprite.h"
//#include "gMain.h"
//#include <SDL2/SDL_main.h>
//#include <SDL2/SDL.h>
//#include "cSDL_Setup.h"
using namespace std;
void draw(SDL_Renderer, SDL_Texture, SDL_Rect);
cSprite::cSprite(SDL_Renderer* passed_renderer, string filePath, int x, int y, int w, int h)
{
renderer = passed_renderer;
//... image
image = NULL;
image = IMG_LoadTexture(renderer,filePath.c_str());
// image error message
if (image == NULL)
{
cout<<"Couldnt load image..."<<filePath.c_str()<<endl;
}
//image dimensions
rect->x = x; // ***** Error: Thread 1:EXC_BAD_ACCESS(code=EXC_1386_GPFLT)
rect->y = y;
rect->w = w;
rect->h = h;
};
cSprite::~cSprite(void)
{
SDL_DestroyTexture(image);
}
//get methods
//SDL_Rect* cSprite::getRect()
//{
// return rect;
//}
//get methods
//SDL_Texture* cSprite::getImage()
//{
// return image;
//}
void cSprite::draw()
{
SDL_RenderCopy(renderer, image, NULL, rect);
}
... the line 'rect->x = x;'
gets the error I put beside it...but idk what else could be causing it... I was hoping someone could explain why EXC_BAD_ACCESS errors even occur... and/or where in the rest of my code it could be coming from...
here's my 3 other .cpp files
....
// ~~~~~~~~~~~~~~~~~~~~~~~~ gMain.cpp ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <iostream>
#include "stdafx.h"
#include "gMain.h"
using namespace std;
gMain::gMain(int passed_screenWidth, int passed_screenHeight)
{
screenWidth = passed_screenWidth;
screenHeight = passed_screenHeight;
// quit boolean
quit = false;
// create instance of cSDL class
csdl_setup = new cSDL_Setup(&quit, screenWidth, screenHeight);
grass = new cSprite(csdl_setup->getRenderer(), "/Users/jamesbryant/Desktop/nuGame/nuGame/images.jpeg", screenWidth, screenHeight, screenWidth, screenHeight);
bruce_Lee = new cSprite(csdl_setup->getRenderer(), "/Users/jamesbryant/Desktop/nuGame/nuGame/lee.bmp", 300, 300, 200, 200);
}
gMain::~gMain(void)
{
}
void gMain::gameLoop(void)
{
// game loop logic
while (!&quit && csdl_setup->getMainEvent() ->type != SDL_QUIT)
{
csdl_setup->begin();
grass->draw();
bruce_Lee->draw();
csdl_setup->end();
}
}
....
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cSDL_Setup.cpp ~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "stdafx.h"
#include "cSDL_Setup.h"
//#include "gMain.h"
using namespace std;
cSDL_Setup::cSDL_Setup(bool* quit, int screenWidth, int screenHeight)
{
// create window
window = NULL;
window = SDL_CreateWindow("rWDY_pWDR", 400, 400, screenWidth, screenHeight, SDL_WINDOW_RESIZABLE);
// if window couldnt be created...
if (window == NULL)
{
cout<<"Window couldnt be created..."<<endl;
*quit = true;
//exit(0);
}
//create renderer
renderer = NULL;
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// initialize images
mainEvent = new SDL_Event();
}
cSDL_Setup::~cSDL_Setup(void)
{
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
delete mainEvent;
}
//get methods
SDL_Renderer* cSDL_Setup::getRenderer()
{
return renderer;
}
SDL_Event* cSDL_Setup::getMainEvent()
{
return mainEvent;
}
void cSDL_Setup::begin()
{
SDL_PollEvent(mainEvent);
SDL_RenderClear(renderer);
}
void cSDL_Setup::end()
{
SDL_RenderPresent(renderer);
}
....
// ~~~~~~~~~~~~~~~~~~~~~~~~~~ firstGame.cpp ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "stdafx.h"
#include "cSDL_Setup.h"
//#include "gMain.h"
using namespace std;
cSDL_Setup::cSDL_Setup(bool* quit, int screenWidth, int screenHeight)
{
// create window
window = NULL;
window = SDL_CreateWindow("rWDY_pWDR", 400, 400, screenWidth, screenHeight, SDL_WINDOW_RESIZABLE);
// if window couldnt be created...
if (window == NULL)
{
cout<<"Window couldnt be created..."<<endl;
*quit = true;
//exit(0);
}
//create renderer
renderer = NULL;
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// initialize images
mainEvent = new SDL_Event();
}
cSDL_Setup::~cSDL_Setup(void)
{
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
delete mainEvent;
}
//get methods
SDL_Renderer* cSDL_Setup::getRenderer()
{
return renderer;
}
SDL_Event* cSDL_Setup::getMainEvent()
{
return mainEvent;
}
void cSDL_Setup::begin()
{
SDL_PollEvent(mainEvent);
SDL_RenderClear(renderer);
}
void cSDL_Setup::end()
{
SDL_RenderPresent(renderer);
}
... here's what my cSprite.h file looks like right now:
#ifndef __game__cSprite__
#define __game__cSprite__
#pragma once
#include <iostream>
#include <SDL2/SDL_main.h>
#include <SDL2/SDL.h>
using namespace std;
class cSprite
{
public:
cSprite(SDL_Renderer* passed_renderer, string filePath, int x, int y, int w, int h);
~cSprite(void);
void draw();
private:
SDL_Texture* image = NULL;
SDL_Rect* rect = NULL;
SDL_Renderer* renderer = NULL;
};
#endif /* defined(__game__cSprite__) */
You didn't post your header for cSprite. However, I imagine that rect is an SDL_Rect*.
The function getting the error is cSprite::cSprite(), ie. the constructor. One of its duties is to initialize all of the class members to reasonable values.
However, I do not see any code that initializes rect to point to anything. The error you're currently getting suggests you're dereferencing a bum pointer, and that's consistent with this observation.
You either need to allocate an SDL_Rect to assign to rect, or you should change rect to just be SDL_Rect, not SDL_Rect*. If you make the latter change, then you will also need to change all of your rect-> to rect., and pass a pointer to rect in the SDL calls that require it (ie. SDL_RenderCopy(renderer, image, NULL, &rect);)