Skip to main content
GameDev.net gamedev.net
🔒 Locked

Help using multiple header and implementation files in SDL

Started by ISDCaptain01 Oct 31, 2012 at 6:59 AM 14 replies 3.7k views
Original Post
ISDCaptain01
ISDCaptain01
Okay so im following Lazy Foo's sdl tutorial number 9:

http://lazyfoo.net/SDL_tutorials/lesson09/index.php

He writes his whole class and function within one .cpp file

I took a different path and made a header file and an implementation file for the button class

The problem im getting is when im making the function in the implementation files, they use global variables from the
main file, and it gives me a red squiggle line saying the variable is unidentified, but its not.

im attaching my project for all of you to see and help me

ignore the lesson09.cpp file. im just using that as a guide to write my own code.
alvaro
alvaro
I didn't read your code, but your problem seems to have nothing to do with SDL. The way you use global variables in programs with multiple modules is this:
* Put a declaration for the variable in a header file, using the keyword "extern" (e.g. extern int global_integer;').
* Include that header file whenever some part of the code needs access to the variable.
* Put a definition (with an optional initialization) in one of the .cpp files (e.g.,
int global_integer = 5;').

You could also try to work around the issue by eliminating the need for global variables, which is almost always possible and a good idea.
ISDCaptain01
ISDCaptain01
This is my main file

[source lang="cpp"]/The headers
#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"
#include
#include "Button.h"
//the screen attributes
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

//the button states in the sprite sheet
int const CLIP_MOUSEOVER = 0;
int const CLIP_MOUSEOUT = 1;
int const CLIP_MOUSEDOWN = 2;
int const CLIP_MOUSEUP = 3;

//the surfaces
SDL_Surface* buttonSheet = NULL;
SDL_Surface* screen = NULL;

//the sdl event structure
SDL_Event event;

//the clip regions of the sprite
SDL_Rect clips[4];

//the load image function
SDL_Surface *load_image(std::string filename)
{
SDL_Surface *loadedImage = NULL;
SDL_Surface *optimizedImage = NULL;

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

if(loadedImage != NULL)
{
optimizedImage = SDL_DisplayFormat(loadedImage);
SDL_FreeSurface(loadedImage);
//if the surface was optimized
if(optimizedImage != NULL)
{
//color key surface
SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY,SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF ) );
}
}
return optimizedImage;
}

//the apply surface function
void apply_surface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip = NULL)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;

SDL_BlitSurface(source,clip,destination, &offset);
}

//the function the sets the clips of the source surface
void set_clips()
{
clips[CLIP_MOUSEOVER].x = 0;
clips[CLIP_MOUSEOVER].y = 0;
clips[CLIP_MOUSEOVER].w = 320;
clips[CLIP_MOUSEOVER].h = 240;

clips[CLIP_MOUSEOUT].x = 320;
clips[CLIP_MOUSEOUT].y = 0;
clips[CLIP_MOUSEOUT].w = 320;
clips[CLIP_MOUSEOUT].h = 240;

clips[CLIP_MOUSEDOWN].x = 0;
clips[CLIP_MOUSEDOWN].y = 240;
clips[CLIP_MOUSEDOWN].w = 320;
clips[CLIP_MOUSEDOWN].h = 240;

clips[CLIP_MOUSEUP].x = 320;
clips[CLIP_MOUSEUP].y = 240;
clips[CLIP_MOUSEUP].w = 320;
clips[CLIP_MOUSEUP].h = 240;
}

[/source]

this is my button.cpp
[source lang="cpp"]#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"
#include
#include "Button.h"

Button::Button(int x, int y, int w, int h)
{
//set the buttons attributes
box.x = x;
box.y = y;
box.w = w;
box.h = h;

//set the default sprite
clip = &clips[ CLIP_MOUSEOUT ];
}

void Button::handle_events()
{
}[/source]

this is my button.h
[source lang="cpp"]#pragma once
#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"

class Button
{
public:
//the constructor that initializes the variables
Button(int x, int y, int w, int h);

//handles events and sets the buttons sprite region
void handle_events();

//shows the button on the screen
void show();


private:
//the attributes of the button
SDL_Rect box;
// the part of the button sprite sheet that will be shown
SDL_Rect *clip;
};
[/source]
ISDCaptain01
ISDCaptain01
the problem occurs in button.cpp

clip = &clips[ CLIP_MOUSEOUT ];

it says &clips is undefined. What gives? its in the main file as a global. What to do?
oler1s
oler1s
In button.cpp, where do you declare clips?

> its in the main file as a global.

Yes. But the issue is in button.cpp, right? Where did you declare clips in button.cpp?
alvaro
alvaro
What part of my answer is not clear to you? Follow my advice and you'll be fine. If you have a global variable defined in main.cpp, you should probably have a main.hpp with the corresponding "extern" declaration, and button.cpp should include it.
ISDCaptain01
ISDCaptain01
I thought if a variable is global, any part of the program could read it. After searching around apparently thats not the case.
How would I go about making this main.hpp file? Would it be okay if i just make externs in the button.h file?
oler1s
oler1s
> I thought if a variable is global, any part of the program could read it.

C++ source files are compiled independently. That's why you need to declare something that was not defined earlier within the source file, that you are compiling.

> How would I go about making this main.hpp file?

How do you make any file?

> Would it be okay if i just make externs in the button.h file?

So declarations for globals in the main.cpp file are declared in button.h file. Do you find this to be logical code organization?
ISDCaptain01
ISDCaptain01

> I thought if a variable is global, any part of the program could read it.

C++ source files are compiled independently. That's why you need to declare something that was not defined earlier within the source file, that you are compiling.

> How would I go about making this main.hpp file?

How do you make any file?

> Would it be okay if i just make externs in the button.h file?

So declarations for globals in the main.cpp file are declared in button.h file. Do you find this to be logical code organization?


i know how to make a .cpp file and .h file. What would I choose in visual c++ for an .hpp file.
Also can you give me a code example(preferebly from my main.cpp) showing how its done?
ISDCaptain01
ISDCaptain01
check out my code so far

main.h:
[source lang="cpp"]//The headers
#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"
#include

//global variables from main are inserted here
extern int const CLIP_MOUSEOVER;
extern int const CLIP_MOUSEOUT;
extern int const CLIP_MOUSEDOWN;
extern int const CLIP_MOUSEUP;
extern SDL_Event event;
extern SDL_Rect clips[4];
extern SDL_Surface* buttonSheet;
extern SDL_Surface* screen;

//global functions are inserted here

extern SDL_Surface *load_image(std::string filename);
extern void apply_surface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip = NULL);
extern void set_clips();[/source]

main.cpp:
[source lang="cpp"]
//The headers
#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"
#include
#include "Button.h"
#include "main.h"

//the screen attributes
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

//the button states in the sprite sheet
int const CLIP_MOUSEOVER = 0;
int const CLIP_MOUSEOUT = 1;
int const CLIP_MOUSEDOWN = 2;
int const CLIP_MOUSEUP = 3;

//the surfaces
SDL_Surface* buttonSheet = NULL;
SDL_Surface* screen = NULL;

//the sdl event structure
SDL_Event event;

//the clip regions of the sprite
SDL_Rect clips[4];

//the load image function
SDL_Surface *load_image(std::string filename)
{
SDL_Surface *loadedImage = NULL;
SDL_Surface *optimizedImage = NULL;

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

if(loadedImage != NULL)
{
optimizedImage = SDL_DisplayFormat(loadedImage);
SDL_FreeSurface(loadedImage);
//if the surface was optimized
if(optimizedImage != NULL)
{
//color key surface
SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY,SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF ) );
}
}
return optimizedImage;
}

//the apply surface function
void apply_surface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip = NULL)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;

SDL_BlitSurface(source,clip,destination, &offset);
}

//the function the sets the clips of the source surface
void set_clips()
{
clips[CLIP_MOUSEOVER].x = 0;
clips[CLIP_MOUSEOVER].y = 0;
clips[CLIP_MOUSEOVER].w = 320;
clips[CLIP_MOUSEOVER].h = 240;

clips[CLIP_MOUSEOUT].x = 320;
clips[CLIP_MOUSEOUT].y = 0;
clips[CLIP_MOUSEOUT].w = 320;
clips[CLIP_MOUSEOUT].h = 240;

clips[CLIP_MOUSEDOWN].x = 0;
clips[CLIP_MOUSEDOWN].y = 240;
clips[CLIP_MOUSEDOWN].w = 320;
clips[CLIP_MOUSEDOWN].h = 240;

clips[CLIP_MOUSEUP].x = 320;
clips[CLIP_MOUSEUP].y = 240;
clips[CLIP_MOUSEUP].w = 320;
clips[CLIP_MOUSEUP].h = 240;
}

int main(int argc, char* args[] )
{
//set the quit flag
bool quit = false;
//initialize everything
SDL_Init(SDL_INIT_EVERYTHING);
screen = SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,SDL_SWSURFACE);
SDL_WM_SetCaption("Button Test", NULL);

//loading the stuff
buttonSheet = load_image("button.png");
//clip the sprite sheet
set_clips();
//make a button object
Button myButton(170,120,320,240);
//while the user has not quit out yet
while(quit == false)
{
//check to see if there are any event polls to handle
if(SDL_PollEvent(&event))
{
//handle button events
myButton.handle_events();
//if the user has quit out of the window
if(event.type == SDL_QUIT)
{
//quit the program
quit = true;
}
}

//Fill the screen white
SDL_FillRect( screen, &screen->clip_rect, SDL_MapRGB( screen->format, 0xFF, 0xFF, 0xFF ) );
//show the button
myButton.show();
//update the screen
SDL_Flip(screen);
}
//start cleaning up;
SDL_FreeSurface(buttonSheet);
SDL_Quit();
return 0;
}[/source]

button.h
[source lang="cpp"]#pragma once
#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"
#include "main.h"






class Button
{
public:
//the constructor that initializes the variables
Button(int x, int y, int w, int h);

//handles events and sets the buttons sprite region
void handle_events();

//shows the button on the screen
void show();


private:
//the attributes of the button
SDL_Rect box;
// the part of the button sprite sheet that will be shown
SDL_Rect *clip;
};

[/source]

button.cpp
[source lang="cpp"]#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"
#include
#include "Button.h"

Button::Button(int x, int y, int w, int h)
{
//set the buttons attributes
box.x = x;
box.y = y;
box.w = w;
box.h = h;

//set the default sprite
clip = &clips[CLIP_MOUSEOUT];
}

void Button::handle_events()
{
//The mouse offsets
int x = 0, y = 0;

//If the mouse moved
if( event.type == SDL_MOUSEMOTION )
{
//Get the mouse offsets
x = event.motion.x;
y = event.motion.y;

//If the mouse is over the button
if( ( x > box.x ) && ( x < box.x + box.w ) && ( y > box.y ) && ( y < box.y + box.h ) )
{
//Set the button sprite
clip = &clips[CLIP_MOUSEOVER];
}
//If not
else
{
//Set the button sprite
clip = &clips[CLIP_MOUSEOUT];
}
}
//if the mouse button is pressed
if(event.type == SDL_MOUSEBUTTONDOWN)
{
//if the left button was pressed
if(event.button.button == SDL_BUTTON_LEFT)
{
//get the mouse offsets
x = event.motion.x;
y = event.motion.y;

//if the mouse is over the button
if((x > box.x)&&(x < box.x+box.w)&&(y > box.y)&&(y < box.y+box.h))
{
//set the button sprite
clip = &clip[CLIP_MOUSEDOWN];
}
}
}
//if a mouse button was released
if(event.type == SDL_MOUSEBUTTONUP)
{
//if the left button was released
if(event.button.button == SDL_BUTTON_LEFT)
{
//get the mouse offsets
x = event.motion.x;
y = event.motion.y;
//if the mouse is over the button
if((x > box.x)&&(x < box.x + box.w)&&(y > box.y)&&(y < box.y+box.h))
{
//set the button sprite
clip = &clip[CLIP_MOUSEUP];
}
}
}
}

void Button::show()
{
//show the button
apply_surface(box.x,box.y,buttonSheet,screen, clip);
}








[/source]


my problem is that im getting this eror now:
1>------ Build started: Project: sdl_test, Configuration: Debug Win32 ------
1> main.cpp
1>c:\users\aasim\desktop\sdl_test\sdl_test\main.h(20): error C2572: 'apply_surface' : redefinition of default parameter : parameter 5
1> c:\users\aasim\desktop\sdl_test\sdl_test\main.h(20) : see declaration of 'apply_surface'
1>c:\users\aasim\desktop\sdl_test\sdl_test\main.cpp(56): error C2572: 'apply_surface' : redefinition of default parameter : parameter 5
1> c:\users\aasim\desktop\sdl_test\sdl_test\main.h(20) : see declaration of 'apply_surface'
1> Button.cpp
1> Generating Code...
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
SiCrane
SiCrane
Why doesn't main.h have include guards or pragma once?
rip-off
rip-off
Default parameters should be specified once, most sensibly in the declaration (otherwise other files don't know about the default). Specifying them multiple times could result in them not matching one another, with confusing results.

Functions are implicitly "extern", so you don't need to use that keyword in your function declarations. As an exception to the rules alvaro listed, const values are implicitly "static" or file local, so you can actually define them in a header file.

We can reduce the usage of global variables by using parameters. For example, instead of having a global event that must be populated before calling Button::handle_events() (a hidden dependency), we can change the function to void Button::handle_event(SDL_Event event).

Likewise, Button::show() could become Button::show(SDL_Surface *screen, SDL_Surface *buttonSheet), though we can also use SDL's function SDL_GetVideoSurface() and avoid keeping track of the "screen" ourselves.

Applying these techniques, we can remove all the global variables (note: global constants are generally fine).
ISDCaptain01
ISDCaptain01
okay after including #pragma onnce i get one error now

1>------ Build started: Project: sdl_test, Configuration: Debug Win32 ------
1> main.cpp
1>c:\users\aasim\desktop\sdl_test\sdl_test\main.cpp(56): error C2572: 'apply_surface' : redefinition of default parameter : parameter 5
1> c:\users\aasim\desktop\sdl_test\sdl_test\main.h(21) : see declaration of 'apply_surface'
1> Generating Code...
1> Compiling...
1> Button.cpp
1> Generating Code...
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
ISDCaptain01
ISDCaptain01

Default parameters should be specified once, most sensibly in the declaration (otherwise other files don't know about the default). Specifying them multiple times could result in them not matching one another, with confusing results.

Functions are implicitly "extern", so you don't need to use that keyword in your function declarations. As an exception to the rules alvaro listed, const values are implicitly "static" or file local, so you can actually define them in a header file.

We can reduce the usage of global variables by using parameters. For example, instead of having a global event that must be populated before calling Button::handle_events() (a hidden dependency), we can change the function to void Button::handle_event(SDL_Event event).

Likewise, Button::show() could become Button::show(SDL_Surface *screen, SDL_Surface *buttonSheet), though we can also use SDL's function SDL_GetVideoSurface() and avoid keeping track of the "screen" ourselves.

Applying these techniques, we can remove all the global variables (note: global constants are generally fine).


not sure what your trying to say. Where should i define then? the main.h or main.cpp? I already defined appl_surface in main.cpp
rip-off
rip-off
The default value for the "clip" parameter should be in the declaration in main.h:

void apply_surface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip = NULL)


It should not appear in the definition in main.cpp:

void apply_surface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip)
{
// ...
}
ISDCaptain01
ISDCaptain01
Thanks a bunch! It worked! Now im gonna add this project as reference in my personal folder. Just incase i need to mess around with externs again.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.