Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am having a lot of trouble with my header files and the compilation. I have everything linked with header guards but for some reason I am still getting a lot of multiple definition errors. I'm also look for help on better way to organize code. Whatever help is appreciated!
This is the out output of my console when I do the g++ call:
g++ main.cpp close.cpp init.cpp load_media.cpp texture.cpp -w -lSDL2 -lSDL2_image -lSDL2_mixer -lSDL2_ttf -o run
/tmp/cc3oNgPs.o:(.bss+0x0): multiple definition of `g_font'
/tmp/ccg0hCKW.o:(.bss+0x0): first defined here
/tmp/cc3oNgPs.o:(.bss+0x8): multiple definition of `g_window'
/tmp/ccg0hCKW.o:(.bss+0x8): first defined here
/tmp/cc3oNgPs.o:(.bss+0x10): multiple definition of `g_renderer'
/tmp/ccg0hCKW.o:(.bss+0x10): first defined here
/tmp/cc3oNgPs.o:(.bss+0x20): multiple definition of `g_text_texture'
/tmp/ccg0hCKW.o:(.bss+0x20): first defined here
/tmp/ccIgzhbZ.o:(.bss+0x0): multiple definition of `g_font'
/tmp/ccg0hCKW.o:(.bss+0x0): first defined here
/tmp/ccIgzhbZ.o:(.bss+0x8): multiple definition of `g_window'
/tmp/ccg0hCKW.o:(.bss+0x8): first defined here
/tmp/ccIgzhbZ.o:(.bss+0x10): multiple definition of `g_renderer'
/tmp/ccg0hCKW.o:(.bss+0x10): first defined here
/tmp/ccIgzhbZ.o:(.bss+0x20): multiple definition of `g_text_texture'
/tmp/ccg0hCKW.o:(.bss+0x20): first defined here
/tmp/ccQs9gPv.o:(.bss+0x0): multiple definition of `g_font'
/tmp/ccg0hCKW.o:(.bss+0x0): first defined here
/tmp/ccQs9gPv.o:(.bss+0x8): multiple definition of `g_window'
/tmp/ccg0hCKW.o:(.bss+0x8): first defined here
/tmp/ccQs9gPv.o:(.bss+0x10): multiple definition of `g_renderer'
/tmp/ccg0hCKW.o:(.bss+0x10): first defined here
/tmp/ccQs9gPv.o:(.bss+0x20): multiple definition of `g_text_texture'
/tmp/ccg0hCKW.o:(.bss+0x20): first defined here
/tmp/ccxzUgM2.o:(.bss+0x0): multiple definition of `g_font'
/tmp/ccg0hCKW.o:(.bss+0x0): first defined here
/tmp/ccxzUgM2.o:(.bss+0x8): multiple definition of `g_window'
/tmp/ccg0hCKW.o:(.bss+0x8): first defined here
/tmp/ccxzUgM2.o:(.bss+0x10): multiple definition of `g_renderer'
/tmp/ccg0hCKW.o:(.bss+0x10): first defined here
/tmp/ccxzUgM2.o:(.bss+0x20): multiple definition of `g_text_texture'
/tmp/ccg0hCKW.o:(.bss+0x20): first defined here
collect2: error: ld returned 1 exit status
here are my 2 header files:
isolation.h
//include //include guard
#ifndef ISOLATION_H
#define ISOLATION_H
//include dependencies
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <string>
//include headers
#include "texture.h"
//Screen dimension constants
const int SCREEN_WIDTH = 1280;
const int SCREEN_HEIGHT = 800;
//forward delcarlation
//class Texture;
//start up SDL create window
bool init();
//load all media
bool load_media();
//free all and shut down SDL
void close();
//load global front
TTF_Font* g_font = NULL;
//window
SDL_Window* g_window = NULL;
//renderer
SDL_Renderer* g_renderer = NULL;
//load jpeg + font
//Texture background_texture;
//rendered font texture
Texture g_text_texture;
#endif
texture.h
//include guard
#ifndef TEXTURE_H
#define TEXTURE_H
//include dependencies
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <string>
//include headers
//#include "isolation.h"
class Texture {
public:
//initializes variables
Texture();
//deallocates memory
~Texture();
//load image from path
bool load_from_file( std::string path );
//create image from font string
bool load_from_rendered_text( std::string textureText, SDL_Color text_color );
//deallocates texture
void free();
//set color modulation
void set_color( Uint8 red, Uint8 green, Uint8 blue );
//set blend mode
void set_blend_mode( SDL_BlendMode blending );
//set alpha
void set_alpha( Uint8 alpha );
//render texture at point
void render( int x, int y, SDL_Rect* clip = NULL, double angle = 0.0, SDL_Point* center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE ) const;
//get image dimensions
int get_width() const;
int get_height() const;
private:
//texture pointer
SDL_Texture* m_texture;
//dimensions
int m_width;
int m_height;
};
#endif
init.cpp
#include "isolation.h"
//#include "texture.h"
bool init() {
//initialization flag
bool success = true;
//initialize SDL
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
printf( "SDL could not initialized. SDL Error: %s\n", SDL_GetError() );
success = false;
}
else {
//set texture filtering linear
if ( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) ) {
printf( "Warning: Linear filtering not enabled\n" );
}
//create window
g_window = SDL_CreateWindow( "Isolation", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if ( g_window == NULL ) {
printf( "Window could not be created. SDL Error: %s\n", SDL_GetError() );
success = false;
}
else {
//create vsynced renderer
g_renderer = SDL_CreateRenderer( g_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
if ( g_renderer == NULL ) {
printf( "Renderer could not be created. SDL Error: %s\n", SDL_GetError() );
success = false;
}
else {
//initialize renderer color
SDL_SetRenderDrawColor (g_renderer, 0xFF, 0xFF, 0xFF, 0xFF );
//initialize JPEG loading
int img_flags = IMG_INIT_JPG;
if ( !( IMG_Init( img_flags ) & img_flags ) ) {
printf( "SDL_image could not be initialize. SDL_image Error: %s\n", IMG_GetError() );
success = false;
}
//initialize SDL_ttf
if (TTF_Init() == -1 ) {
printf( "SDL_ttf could not be initialize. SDL_ttf Error: %s\n", TTF_GetError() );
}
}
}
}
return success;
}
load_media.cpp
#include "isolation.h"
//s#include "texture.h"
bool load_media() {
bool success = true;
//load background img
//if( !background_texture.load_from_file( "img/vancouver.jpg" ) ) {
// printf( "Failed to load background texture!\n" );
// success = false;
//}
//open font
g_font = TTF_OpenFont( "lazy.ttf", 28 );
if ( g_font == NULL ) {
printf( "Failed to load lazy font. SDL_ttf Error: %s\n", TTF_GetError() );
success = false;
}
else {
//render texture
SDL_Color text_color = { 0, 0, 0 };
if ( !g_text_texture.load_from_rendered_text( "hello from the other side ", text_color ) ) {
printf( "Failed to render text texture\n" );
success = false;
}
}
return success;
}
close.cpp
#include "isolation.h"
//#include "texture.h"
void close() {
//free loaded text
g_text_texture.free();
//free font
TTF_CloseFont( g_font );
g_font = NULL;
//destroy window
SDL_DestroyWindow( g_window );
SDL_DestroyRenderer( g_renderer );
g_window = NULL;
g_renderer = NULL;
//quit SDL subsystems
TTF_Quit();
IMG_Quit();
SDL_Quit();
}
main.cpp
#include "isolation.h"
//#include "texture.h"
int main( int argc, char* args[] ) {
//start up SDL
if ( !init() ) {
printf( "Failed to initialize.\n" );
}
else {
//load media
if ( !load_media() ) {
printf( "Failed to load media.\n" );
}
else{
//main loop flag
bool quit = false;
//event handler
SDL_Event e;
//while running
while ( !quit ) {
//handle events on queue
while ( SDL_PollEvent( &e ) != 0 ) {
//user quit
if ( e.type == SDL_QUIT ) {
quit = true;
}
}
//clear screen
SDL_SetRenderDrawColor( g_renderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( g_renderer );
//render frame
g_text_texture.render( ( SCREEN_WIDTH - g_text_texture.get_width() ) / 2, ( SCREEN_HEIGHT - g_text_texture.get_height() ) / 2 );
//update screen
SDL_RenderPresent( g_renderer );
}
}
}
//free memory and close SDL
close();
return 0;
}
Do not mix declaration with definition/instantiation in a .h file. Your are instantiating g_font, g_window and g_renderer in isolation.h file. The correct is instantiating only once, usually, in a .cpp
To solve your problem, change isolation.h to declare those variables as external linkage:
//load global front
extern TTF_Font* g_font;
//window
extern SDL_Window* g_window;
//renderer
extern SDL_Renderer* g_renderer;
and instantiate them only once in an appropriate .cpp file, for example, init.cpp
Related
I have been trying to make a simple game in SDL. I Found that keeping every thing in on file was getting messy so i moved some functions into their own file and set up a global header file to store all the global things i would use. but from there it has been all errors!
Files:
-Main.cpp
-Makefile
-Assets/
-Player.bmp
-Build/
-build.deb
-Modules/
-Global.h
-HandleKeys.cpp
-HandleKeys.h
Main.cpp:
#include <stdio.h>
#include "Modules/Global.h"
#include "Modules/HandleKeys.h"
//Starts up SDL and creates window
bool init();
//Loads media
bool loadMedia();
extern int SCREEN_WIDTH = 640;
extern int SCREEN_HEIGHT = 480;
//Frees media and shuts down SDL
void close();
//Loads individual image
SDL_Surface* loadSurface( std::string path );
//The window we'll be rendering to
SDL_Window* gWindow = NULL;
//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;
//The images that correspond to a keypress
SDL_Surface* Entity[ KEY_PRESS_SURFACE_TOTAL ];
//Current displayed image
SDL_Surface* gCurrentSurface = NULL;
int PlayerX;
int PlayerY;
bool init()
{
//Initialization flag
bool success = true;
//Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "SDL could not initialize! SDL Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//Create window
gWindow = SDL_CreateWindow( title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if( gWindow == NULL )
{
printf( "Window could not be created! SDL Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//Get window surface
gScreenSurface = SDL_GetWindowSurface( gWindow );
}
}
return success;
}
string get(list<string> _list, int _i){
list<string>::iterator it = _list.begin();
for(int i=0; i<_i; i++){
++it;
}
return *it;
}
bool loadMedia()
{
//Loading success flag
bool success = true;
for( int i = 0; i <= KEY_PRESS_SURFACE_TOTAL; ++i )
{
if (i != KEY_PRESS_SURFACE_TOTAL){
Entity[ PLAYER_SURFACE ] = loadSurface( get(EntityPaths, i) );
}
}
return success;
}
void close()
{
//Deallocate surfaces
for( int i = 0; i < KEY_PRESS_SURFACE_TOTAL; ++i )
{
SDL_FreeSurface( Entity[ i ] );
Entity[ i ] = NULL;
}
//Destroy window
SDL_DestroyWindow( gWindow );
gWindow = NULL;
//Quit SDL subsystems
SDL_Quit();
}
SDL_Surface* loadSurface( std::string path )
{
//Load image at specified path
SDL_Surface* loadedSurface = SDL_LoadBMP( path.c_str() );
if( loadedSurface == NULL )
{
printf( "Unable to load image %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
}
return loadedSurface;
}
int main( int argc, char* args[] )
{
//Start up SDL and create window
if( !init() )
{
printf( "Failed to initialize!\n" );
}
else
{
//Load media
if( !loadMedia() )
{
printf( "Failed to load media!\n" );
}
else
{
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
//Set default current surface
gCurrentSurface = Entity[ PLAYER_SURFACE ];
//While application is running
while( !quit )
{
//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
HandelKey(e);
}
SDL_Rect rect;
rect.x = PlayerX;
rect.y = PlayerY;
rect.w = 0;
rect.h = 0;
//Apply the current image
SDL_BlitSurface( gCurrentSurface, NULL, gScreenSurface, &rect );
//Update the surface
SDL_UpdateWindowSurface( gWindow );
}
}
}
//Free resources and close SDL
close();
return 0;
}
Makefile:
#OBJS specifies which files to compile as part of the project
OBJS = Main.cpp
#MODS specifies which Modules to Compile.
#NOTE: only add .cpp files, no .h files!
MODS = Modules/HandleKeys.cpp
#CC specifies which compiler we're using
CC = g++
#COMPILER_FLAGS specifies the additional compilation options we're using
# -w suppresses all warnings
COMPILER_FLAGS = -w
#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lSDL2
#OBJ_NAME specifies the name of our exectuable
OBJ_NAME = Build/build.deb
#This is the target that compiles our executable
all : $(OBJS)
$(CC) $(OBJS) $(MODS) $(COMPILER_FLAGS) $(LINKER_FLAGS) -o $(OBJ_NAME)
Global.h
#ifndef __GLOBAL_H__
#define __GLOBAL_H__
//Included by all files!
#include <SDL2/SDL.h>
#include <string>
#include <list>
using namespace std;
extern int SCREEN_WIDTH = 640;
extern int SCREEN_HEIGHT = 480;
extern char* title = "Top Down";
enum Entity
{
PLAYER_SURFACE,
KEY_PRESS_SURFACE_TOTAL
};
extern list<string> EntityPaths
{
"Assets/Player.bmp",
};
//Starts up SDL and creates window
extern bool init();
//Loads media
extern bool loadMedia();
//Frees media and shuts down SDL
extern void close();
//Loads individual image
extern SDL_Surface* loadSurface( std::string path );
//The window we'll be rendering to
extern SDL_Window* gWindow;
//The surface contained by the window
extern SDL_Surface* gScreenSurface;
//The images that correspond to a keypress
extern SDL_Surface* Entity[ KEY_PRESS_SURFACE_TOTAL ];
//Current displayed image
extern SDL_Surface* gCurrentSurface;
extern int PlayerX;
extern int PlayerY;
extern const int PlayerSpeed;
#endif
HandleKeys.cpp:
#include "Global.h"
#include "HandleKeys.h"
void HandleKey(SDL_Event e){
if( e.type == SDL_KEYDOWN )
{
//Select surfaces based on key press
switch( e.key.keysym.sym )
{
case SDLK_UP:
PlayerY -= PlayerSpeed;
break;
case SDLK_DOWN:
PlayerY += PlayerSpeed;
break;
case SDLK_LEFT:
PlayerX -= PlayerSpeed;
break;
case SDLK_RIGHT:
PlayerX += PlayerSpeed;
break;
}
}
}
HandleKeys.h:
#ifndef __HANDLEKEYS_H__
#define __HANDLEKEYS_H__
extern void HandelKey(SDL_Event e);
#endif
Make file output:
g++ Main.cpp Modules/HandleKeys.cpp -w -lSDL2 -o Build/build.deb
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o:(.data+0x0): multiple definition of `SCREEN_WIDTH'; /tmp/ccdTvusg.o:(.data+0x0): first defined here
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o:(.data+0x4): multiple definition of `SCREEN_HEIGHT'; /tmp/ccdTvusg.o:(.data+0x4): first defined here
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o:(.data.rel.local+0x0): multiple definition of `title'; /tmp/ccdTvusg.o:(.data.rel.local+0x0): first defined here
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o:(.bss+0x0): multiple definition of `EntityPaths[abi:cxx11]'; /tmp/ccdTvusg.o:(.bss+0x0): first defined here
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o: warning: relocation against `PlayerSpeed' in read-only section `.text'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccdTvusg.o: in function `main':
Main.cpp:(.text+0x3e0): undefined reference to `HandelKey(SDL_Event)'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccvPJ1dy.o: in function `HandleKey(SDL_Event)':
HandleKeys.cpp:(.text+0x49): undefined reference to `PlayerSpeed'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: HandleKeys.cpp:(.text+0x5f): undefined reference to `PlayerSpeed'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: HandleKeys.cpp:(.text+0x75): undefined reference to `PlayerSpeed'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: HandleKeys.cpp:(.text+0x8b): undefined reference to `PlayerSpeed'
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
make: *** [Makefile:23: all] Error 1
i have messed around with using the "extern" parameter but nothing relay works, i have also messed around with how i define things in both global.h and main.cpp.
I am on pop OS (a Ubuntu based Linux distro).
Edit: I added the wrong main.cpp (I Had another open in my vscode workspace!)
Edit2: I now have a new error:
/usr/lib/gcc/x86_64-unknown-linux-gnu/12.1.0/../../../../x86_64-unknown-linux-gnu/bin/ld: /tmp/ccwvE6bo.o: in function `main':
Main.cpp:(.text+0x3e0): undefined reference to `HandelKey(SDL_Event)'
collect2: error: ld returned 1 exit status
make: *** [Makefile:23: all] Error 1
The lines
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
in Main.cpp and the lines
extern int SCREEN_WIDTH = 640;
extern int SCREEN_HEIGHT = 480;
in Global.h are definitions. A declaration with an initializer is always a definition.
By defining the same variable in more than one translation unit (i.e. .cpp file), you are violating the one-definition rule.
I suggest that you change
extern int SCREEN_WIDTH = 640;
extern int SCREEN_HEIGHT = 480;
in Global.h to the following:
extern const int SCREEN_WIDTH;
extern const int SCREEN_HEIGHT;
That way, it is only a declaration and no longer a definition.
You have a similar problem with title defined in Global.h:
extern char* title = "Top Down";
This line is a definition.
Header files should generally only contain declarations of variables, not definitions, because otherwise, if the header files is included by more than one translation unit, it will violate the one-definition rule.
Therefore, I suggest that you change this line to a declaration:
extern const char* title;
In one of the translation units, for example Main.cpp, you should then provide the definition:
const char* title = "Top Down";
The variable EntityPaths has a similar problem:
extern list<string> EntityPaths
{
"Assets/Player.bmp",
};
This is a definition. You should not define it in the header file. Instead, you should only provide a declaration:
extern list<string> EntityPaths;
You should define it in exactly one translation unit, for example in Main.cpp.
In Global.h, you have declared PlayerSpeed:
extern const int PlayerSpeed;
However, you did not define it anywhere. I suggest that you add
const int PlayerSpeed;
to Main.cpp.
The line
extern void HandelKey(SDL_Event e);
in HandleKeys.h has a typo. It should be HandleKey, not HandelKey.
This question already has answers here:
Why does the order of '-l' option in gcc matter? [duplicate]
(3 answers)
Closed 5 years ago.
I have just started to use C++ and SDL, and I have begun to create a basic Breakout clone to get my head around the semantics. To modularise what I have so far, I have created two header files core.h and paddle.h.
I am having difficulty with correctly including SDL with these modules. Initially, the project compiled when all I had was the main file breakout.cpp, paddle.h and paddle.cpp. At this stage, the 'Core' class was located in breakout.cpp, and as soon as I migrated it into its own file, the compiler started to get upset.
As it stands, it's a very simple set up that can be illustrated as follows:
breakout ---> core ---> paddle
Which leads me to believe that I am making a rookie oversight. Or that I'm linking the files incorrectly in Makefile.
Here is the code:
breakout.cpp
#include "SDL2/SDL.h"
#include "SDL2/SDL_image.h"
#include <stdio.h>
#include <string>
#include "core.h"
int main(int argc, char* args[]) {
Core gCore;
gCore.runGame();
return 0;
}
core.h
#pragma once
#include "paddle.h"
class Core {
public:
Core();
~Core();
void runGame();
private:
static const int SCREEN_WIDTH = 640, SCREEN_HEIGHT = 480;
SDL_Window* gWindow;
SDL_Renderer* gRenderer;
Paddle* p1;
void render();
};
paddle.h
#pragma once
#include <string>
class Paddle {
friend class Core;
public:
Paddle( SDL_Renderer* gRenderer );
~Paddle();
void free();
private:
static const int VELOCITY = 5;
int xPos, yPos, pWidth, pHeight;
SDL_Texture* pSprite;
SDL_Rect* pRect;
bool loadFromFile( SDL_Renderer* gRenderer, std::string path );
int getXPos(); int getYPos();
int getWidth(); int getHeight();
};
core.cpp
#include "SDL2/SDL.h"
#include "SDL2/SDL_image.h"
#include <stdio.h>
#include "paddle.h"
#include "core.h"
Core::Core() {
// Set up SDL
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
printf( "SDL could not initialise! SDL Error: %s\n", SDL_GetError() );
}
else {
if ( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) ) {
printf( "Warning: Linear texture filtering not enabled!" );
}
else {
gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT,
SDL_WINDOW_SHOWN );
if ( gWindow == NULL ) {
printf( "Could not create window. SDL Error: %s\n", SDL_GetError() );
}
else {
gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
if ( gRenderer == NULL ) {
printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
}
else {
// Initialise renderer colour
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
// Initialise PNG loading
int imgFlags = IMG_INIT_PNG;
if ( !( IMG_Init( imgFlags ) & imgFlags ) ) {
printf( "SDL_image could not be initialised! SDL_image Error: %s\n", IMG_GetError() );
}
}
}
}
}
}
Core::~Core() {
SDL_DestroyRenderer( gRenderer ); gRenderer = NULL;
SDL_DestroyWindow( gWindow ); gWindow = NULL;
// Quit SDL subsystems
IMG_Quit();
SDL_Quit();
}
void Core::runGame() {
// Main loop flag
bool quit = false;
// Event handler
SDL_Event e;
// p1 = new Paddle( gRenderer );
while ( !quit ) {
while( SDL_PollEvent( &e ) != 0 ) {
//User requests quit
if( e.type == SDL_QUIT ) {
quit = true;
}
}
// Clear screen
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );
// Render game assets
render();
// Update screen
SDL_RenderPresent( gRenderer );
}
}
void Core::render() {
// Set rendering space and render to screen
SDL_Rect pRenderQuad = { p1->xPos, p1->yPos, p1->pWidth, p1->pHeight };
// Render to screen
SDL_RenderCopy( gRenderer, p1->pSprite, NULL, &pRenderQuad );
}
paddle.cpp
#include "SDL2/SDL.h"
#include "SDL2/SDL_image.h"
#include <stdio.h>
#include <string>
#include "paddle.h"
Paddle::Paddle(SDL_Renderer* gRenderer) {
xPos = 300; yPos = 400;
pWidth = 0; pHeight = 0;
loadFromFile( gRenderer, "paddle.png" );
}
Paddle::~Paddle() {
free();
}
bool Paddle::loadFromFile(SDL_Renderer* gRenderer, std::string path) {
// Get rid of preexisting texture
free();
SDL_Texture* nTexture = NULL;
SDL_Surface* lSurface = IMG_Load( path.c_str() );
if ( lSurface == NULL ) { printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() ); }
else {
nTexture = SDL_CreateTextureFromSurface( gRenderer, lSurface );
if ( nTexture == NULL ) { printf( "Unable to load texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() ); }
else {
pWidth = lSurface->w;
pHeight = lSurface->h;
}
SDL_FreeSurface( lSurface ); // Surface no longer needed
}
pSprite = nTexture;
return pSprite != NULL;
}
void Paddle::free() {
if ( pSprite != NULL ) {
SDL_DestroyTexture( pSprite );
pWidth = 0; pHeight = 0;
}
}
// Getter methods
int Paddle::getXPos() { return xPos; } int Paddle::getYPos() { return yPos; }
int Paddle::getWidth() { return pWidth; } int Paddle::getHeight() { return pHeight; }
And I have also included the Makefile, as there could easily be something wrong there too.
Makefile
OBJS = breakout.cpp
DEPS = paddle.h core.h
CC = g++
COMPILER_FLAGS = -w
LINKER_FLAGS = -lSDL2 -lSDL2_image
OBJ_NAME = breakout
%.o: %.cpp $(DEPS)
$(CC) -c -o $# $< $(COMPILER_FLAGS)
all : $(OBJS)
$(CC) $(OBJS) $(COMPILER_FLAGS) $(LINKER_FLAGS) paddle.cpp core.cpp -o $(OBJ_NAME)
Error log
g++ breakout.cpp -w -lSDL2 -lSDL2_image paddle.cpp core.cpp -o breakout
/tmp/cc0H2fKM.o: In function `Paddle::loadFromFile(SDL_Renderer*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
paddle.cpp:(.text+0x111): undefined reference to `IMG_Load'
paddle.cpp:(.text+0x121): undefined reference to `SDL_GetError'
paddle.cpp:(.text+0x15a): undefined reference to `SDL_CreateTextureFromSurface'
paddle.cpp:(.text+0x16a): undefined reference to `SDL_GetError'
paddle.cpp:(.text+0x1b8): undefined reference to `SDL_FreeSurface'
/tmp/cc0H2fKM.o: In function `Paddle::free()':
paddle.cpp:(.text+0x203): undefined reference to `SDL_DestroyTexture'
/tmp/ccDHGaLY.o: In function `Core::Core()':
core.cpp:(.text+0x12): undefined reference to `SDL_Init'
core.cpp:(.text+0x1e): undefined reference to `SDL_GetError'
core.cpp:(.text+0x44): undefined reference to `SDL_SetHint'
core.cpp:(.text+0x86): undefined reference to `SDL_CreateWindow'
core.cpp:(.text+0xa1): undefined reference to `SDL_GetError'
core.cpp:(.text+0xd1): undefined reference to `SDL_CreateRenderer'
core.cpp:(.text+0xee): undefined reference to `SDL_GetError'
core.cpp:(.text+0x127): undefined reference to `SDL_SetRenderDrawColor'
core.cpp:(.text+0x138): undefined reference to `IMG_Init'
core.cpp:(.text+0x149): undefined reference to `SDL_GetError'
/tmp/ccDHGaLY.o: In function `Core::~Core()':
core.cpp:(.text+0x17a): undefined reference to `SDL_DestroyRenderer'
core.cpp:(.text+0x195): undefined reference to `SDL_DestroyWindow'
core.cpp:(.text+0x1a5): undefined reference to `IMG_Quit'
core.cpp:(.text+0x1aa): undefined reference to `SDL_Quit'
/tmp/ccDHGaLY.o: In function `Core::runGame()':
core.cpp:(.text+0x1ea): undefined reference to `SDL_PollEvent'
core.cpp:(.text+0x218): undefined reference to `SDL_SetRenderDrawColor'
core.cpp:(.text+0x228): undefined reference to `SDL_RenderClear'
core.cpp:(.text+0x244): undefined reference to `SDL_RenderPresent'
/tmp/ccDHGaLY.o: In function `Core::render()':
core.cpp:(.text+0x2d1): undefined reference to `SDL_RenderCopy'
collect2: ld returned 1 exit status
make: *** [all] Error 1
I'd would really appreciate your support on not just the problem at hand. But also if any general suggestions about my code can be made.
Thanks
The order of the flags on your compiler switch matter.
Libraries to be passed to the linker should be last.
And using a -w makes no sense as it's usually -W (capital) followed by some kind of directive, such as -Werror -Wall etc.
Suggesto: remove -w flag and move the -l switches to the end.
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?
I am currently attempting to write a very simple 2d game engine using SDL in order to help myself get more comfortable with coding. Unfortunately, I made the mistake of starting with a single source file, and now that my code is getting bigger, I am trying to split the existing code (which works fine before the split) into multiple header and source files. The first major issue I've encountered is that when I try to define SCREEN_HEIGHT, SCREEN_WIDTH, Window, and Renderer in init.cpp after declaring them in init.h, I get error: 'blank' does not name a type (blank being Window, Renderer, etc.). I am also trying to make them global, which may be part of the issue. Included below is the relevant code (I took out all the stuff I think is irrelevant in this case). I suspect I'm just missing something really simple here, but I've been unable to find an existing answer online like I have with my previous problems.
main.cpp
#include "globals.h"
#include "texture.h"
....
globals.h
#ifndef GLOBALS
#define GLOBALS
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <stdio.h>
#include <string>
#endif //GLOBALS
texture.h
#ifndef TEXTURE
#define TEXTURE
#include "globals.h"
#include "init.h"
....
#endif // TEXTURE
texture.cpp
#include "texture.h"
....
init.h
#ifndef INIT
#define INIT
#include "globals.h"
//screen dimensions
int SCREEN_WIDTH;
int SCREEN_HEIGHT;
//initiates SDL and creates a window and renderer
bool init();
//the created window
SDL_Window* Window;
//the renderer that will be used
SDL_Renderer* Renderer;
#endif // INIT
init.cpp
#include "init.h"
SCREEN_WIDTH = 640;
SCREEN_HEIGHT = 480;
Window = NULL;
Renderer = NULL;
bool init()
{
bool success = true;
if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
printf( "SDL was unable to initialize! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1"))
{
printf( "Linear texture filtering not enabled!");
}
else
{
Window = SDL_CreateWindow( "Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if( Window == NULL)
{
printf( "Window could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
Renderer = SDL_CreateRenderer( Window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if( Renderer == NULL)
{
printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
SDL_SetRenderDrawColor( Renderer, 0xFF, 0xFF, 0xFF, 0xFF);
int PNGImage = IMG_INIT_PNG;
if( !(IMG_Init( PNGImage) & PNGImage))
{
printf( "Image loading not enabled! SDL_Image Error: %s\n", IMG_GetError());
success = false;
}
if( TTF_Init() == -1)
{
printf( "True type fonts not enabled! SDL_TTF Error: %s\n", TTF_GetError());
success = false;
}
}
}
}
}
return success;
}
I get the error in init.cpp at the top of the code before bool init()
Renderer = NULL; is an assignment statement, which you cannot have in global scope. You can only have declarations in global scope. Since you have already declared Renderer in your header file, you don't need to redeclare it either. Just set it to null within one of your initialization functions (e.g. your current init() function).
I am trying to render an image using SDL_image v2.0.0, in SDL2.
I have an image called Red.png in my res/img/ folder. When I try to load the texture, and use SDL_QueryTexture() it gets the size and everything just fine. But when it comes to rendering the actual image, Ive put a rectangle outline to know where the image is, but there is no image in the box.
The class I use to load and render the texture:
class LTexture
{
public:
~LTexture()
{
SDL_DestroyTexture(image_);
renderer_ = nullptr;
image_ = nullptr;
}
void init(SDL_Renderer* renderer)
{
printf("init texture\n");
renderer_ = renderer;
}
void loadBMP(std::string filename)
{
printf("load texture\n");
image_ = IMG_LoadTexture(renderer_, ("res/img/"+filename).c_str());
SDL_QueryTexture(image_, NULL, NULL, &imgrect.w, &imgrect.h);
}
void render(int x, int y)
{
imgrect.x = x;
imgrect.y = y;
SDL_SetRenderDrawColor(renderer_, 128, 128, 128, 255);
if (image_ != nullptr && renderer_ != nullptr)
{
printf("%i, %i\n", imgrect.x, imgrect.y);
SDL_RenderDrawRect(renderer_, &imgrect);
SDL_RenderCopy(renderer_, image_, &imgrect, &imgrect);
}
}
bool isLoaded()
{
return image_ != nullptr;
}
private:
SDL_Renderer* renderer_ = nullptr;
SDL_Texture* image_ = nullptr;
SDL_Rect imgrect;
};
I know it correctly gets the renderer and loads the image because the DrawRect function works, and if you didn't guess by the name, Red.png is a red rectangle.
Pass nullptr in for srcrect in your SDL_RenderCopy() call:
SDL_RenderCopy(renderer_, image_, nullptr, &imgrect);
Right now if x and/or y are larger than image_ SDL will clip srcrect to the extents of image_, end up with an empty rect, and do nothing.
Example:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <cstdlib>
#include <string>
class LTexture
{
public:
LTexture()
: renderer_( nullptr )
, image_( nullptr )
{ }
~LTexture()
{
SDL_DestroyTexture(image_);
renderer_ = nullptr;
image_ = nullptr;
}
void init(SDL_Renderer* renderer)
{
printf("init texture\n");
renderer_ = renderer;
}
void loadBMP(std::string filename)
{
printf("load texture\n");
image_ = IMG_LoadTexture(renderer_, filename.c_str());
SDL_QueryTexture(image_, NULL, NULL, &imgrect.w, &imgrect.h);
}
void render(int x, int y)
{
imgrect.x = x;
imgrect.y = y;
SDL_SetRenderDrawColor(renderer_, 128, 128, 128, 255);
if (image_ != nullptr && renderer_ != nullptr)
{
printf("%i, %i\n", imgrect.x, imgrect.y);
SDL_RenderDrawRect(renderer_, &imgrect);
SDL_RenderCopy(renderer_, image_, nullptr, &imgrect);
}
}
bool isLoaded()
{
return image_ != nullptr;
}
private:
SDL_Renderer* renderer_;
SDL_Texture* image_;
SDL_Rect imgrect;
};
int main( int argc, char** argv )
{
SDL_Init( SDL_INIT_EVERYTHING );
IMG_Init( IMG_INIT_PNG );
SDL_Window * window = SDL_CreateWindow
(
"SDL2",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
300, 300,
SDL_WINDOW_SHOWN
);
SDL_Renderer* renderer = SDL_CreateRenderer
(
window,
0,
SDL_RENDERER_ACCELERATED
);
LTexture tex;
tex.init( renderer );
tex.loadBMP( "red.png" );
bool running = true;
while( running )
{
SDL_Event ev;
while( SDL_PollEvent( &ev ) )
{
if ( ev.type == SDL_QUIT )
running = false;
}
SDL_SetRenderDrawColor( renderer, 0, 0, 0, 255 );
SDL_RenderFillRect( renderer, NULL );
tex.render( 50, 50 );
SDL_RenderPresent( renderer );
SDL_Delay( 33 );
}
SDL_DestroyRenderer( renderer );
SDL_DestroyWindow( window );
IMG_Quit();
SDL_Quit();
return 0;
}
red.png for reference:
I don't know if this is still actual, but I have problems using SDL_RENDERER_ACCELERATED flag (under Linuix Mint), when I use SW acceleration, SDL_Render* works.