• 13
• 18
• 19
• 27
• 10

# Splitting files?

This topic is 4653 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi everyone, I have been trying to setup a very basic project where all of my graphics functions are contained in a seperate file (graphics.h/.cpp). Now the only I problem I have is I'm getting the following errors:
graphics.cpp:19: error: exit' undeclared (first use this function)
graphics.cpp:19: error: (Each undeclared identifier is reported only once for each function it appears in.)
graphics.cpp:22: error: atexit' undeclared (first use this function)

Is there something wrong with my files? When I put the code back in to the main cpp file it works fine. :/ Here is what I've got so far. globals.h
/*--------------------------------------------------------------+
| Project: Side Scroller					|
| File: globals.h						|
+--------------------------------------------------------------*/

#pragma once

/*  Defines  */

#define TITLE_STRING "Side Scroller"
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define BPP 32
#define SCREEN_FLAGS SDL_SWSURFACE

/*  Global Variables  */

SDL_Surface *g_image;
SDL_Surface *g_screen;
SDL_Event g_event;


graphics.h
/*--------------------------------------------------------------+
| Project: Side Scroller					|
| File: graphics.h						|
+--------------------------------------------------------------*/

#ifndef GRAPHICS_H
#define GRAPHICS_H

bool graphics_init(int w, int h, bool fullscreen);
void graphics_shutdown();
void graphics_setresolution(int w, int h, bool fullscreen);

class sprite
{
public:
sprite();
~sprite();

bool init(char *dir, SDL_Surface *screen);

void draw();
void clearBG();
void updateBG();

float getX(){return m_x;};
float getY(){return m_y;};
float getW(){return m_w;};
float getH(){return m_h;};

void setX (float x);
void setY (float y);
void setW (float w);
void setH (float h);

void setPos (float x, float y);

private:
SDL_Surface *m_image;
SDL_Surface *m_back;
SDL_Surface *m_screen;

float m_x;
float m_y;
float m_oldx;
float m_oldy;
float m_w;
float m_h;
};

#endif


graphics.cpp
/*--------------------------------------------------------------+
| Project: Side Scroller					|
| File: graphics.cpp						|
+--------------------------------------------------------------*/

/*  Includes  */
#include "SDL/SDL.h"
#include "graphics.h"
#include "globals.h"

bool graphics_init(int w, int h, bool fullscreen)
{
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
{
printf("Unable to init SDL: %s\n", SDL_GetError());
exit(1);
}

atexit(SDL_Quit);

if(fullscreen)
g_screen = SDL_SetVideoMode(w, h, BPP, SCREEN_FLAGS | SDL_FULLSCREEN);
else
g_screen = SDL_SetVideoMode(w, h, BPP, SCREEN_FLAGS);

if(g_screen == NULL)
{
printf("Unable to set 640 x 480 video: %s\n", SDL_GetError());
exit(1);
}

SDL_WM_SetCaption(TITLE_STRING, 0);
SDL_ShowCursor(0);
};

void graphics_shutdown()
{
SDL_FreeSurface(g_image);
SDL_FreeSurface(g_screen);

SDL_Quit();
}

void graphics_setresolution(int w, int h, bool fullscreen)
{
//
};

sprite::~sprite()
{
SDL_FreeSurface(m_image);
}

bool sprite::init(char *dir, SDL_Surface *screen)
{
SDL_Surface *temp;

if((temp = SDL_LoadBMP(dir)) == NULL) return false;

SDL_SetColorKey(temp, SDL_SRCCOLORKEY, SDL_MapRGB(temp->format, 0, 255, 0));

m_image = SDL_DisplayFormat(temp);

SDL_FreeSurface(temp);

m_screen = screen;

m_w = m_image->w;
m_h = m_image->h;

return true;
}

void sprite::draw()
{
SDL_Rect dest;
dest.x = (int)m_x; dest.y = (int)m_y;
SDL_BlitSurface(m_image, NULL, m_screen, &dest);
}

void sprite::clearBG()
{
SDL_Rect dest;
dest.x = (int)m_oldx;
dest.y = (int)m_oldy;
dest.w = (int)m_w;
dest.h = (int)m_h;
SDL_BlitSurface(m_back, NULL, m_screen, &dest);
}

void sprite::updateBG()
{
SDL_Rect srcrect;
srcrect.w = (int)m_w;
srcrect.h = (int)m_h;
srcrect.x = (int)m_x;
srcrect.y = (int)m_y;
m_oldx = m_x;
m_oldy = m_y;
SDL_BlitSurface(m_screen, &srcrect, m_back, NULL);
}

void sprite::setX (float x)
{
m_x = x;
}

void sprite::setY (float y)
{
m_y = y;
}

void sprite::setW (float w)
{
m_w = w;
}

void sprite::setH (float h)
{
m_h = h;
}

void sprite::setPos (float x, float y)
{
m_x = x;
m_y = y;
}

{
m_x += x;
}

{
m_y += y;
}


main.cpp
/*--------------------------------------------------------------+
| Project: Side Scroller					|
| File: main.cpp						|
+--------------------------------------------------------------*/

/*  Includes  */
#include "SDL/SDL.h"
#include <string>
#include <stdio.h>
#include "globals.h"
#include "graphics.h"

/*  Namespace  */
using namespace std;

/*  Forward Declarations  */
void init();
void game();
void shutdown();

void DrawBackground();
void ClearScreen();

/*  Functions  */
int main(int argc, char **argv)
{
init();

int done=0;

while(done == 0)
{
while(SDL_PollEvent(&g_event))
{
if(g_event.type == SDL_QUIT) {done = 1;}

if(g_event.type == SDL_KEYDOWN)
{
if(g_event.key.keysym.sym == SDLK_ESCAPE ) {done = 1;}
}
}
game();
}

shutdown();

return 0;
}

void init()
{
graphics_init(SCREEN_WIDTH, SCREEN_HEIGHT, false);

}

void shutdown()
{
graphics_shutdown();
}

void game()
{
ClearScreen();
DrawBackground();

SDL_UpdateRect(g_screen, 0, 0, 0, 0);
}

void DrawBackground()
{
SDL_Rect source = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
SDL_Rect destination = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};

SDL_BlitSurface(g_image, &source, g_screen, &destination);
}

void ClearScreen()
{
SDL_FillRect(g_screen, 0, 0);
}


Can anyone shed any light on this please? As well as any other tips I might need to know before proceeding with this 'structure'? Eventually the "ClearScreen" and "DrawBackground" functions will go into the Graphics files as well. Thanks as always,

##### Share on other sites
You have to include stdlib.h in your graphic.cpp file for exit() and atexit().

##### Share on other sites
Quote:
 Original post by cignox1You have to include stdlib.h in your graphic.cpp file for exit() and atexit().

Or, considering that you're using C++ and not C, try #include <cstdlib> instead (and also #include <cstdio> instead of #include <stdio.h> in your main.cpp file as well).

##### Share on other sites
You have usnig namespace std; in main.cpp but you're not using anything from that namespace. You're using #pragma once in one header and normal include guards in the others, thats just strange. It doesnt appear to me that you have any idea what you're doing. It really doesnt look like you have done anything here but copy and paste from other places with a few modifications that stand out because they're either very strange just obviously useless. Maybe you should hit the books on c++ before you proceed to programming games. Please don't take offence, I can see that you're trying quite hard. I just think you may need to slow down or you might end up either getting so far ahead of yourself that you feel hopeless and give up, or before you get taught c++ from this board(neither of which are good things :D). For your convenience I will present you with some links I found useful when I started programming in c++.

http://www.cplusplus.com/doc/tutorial/
http://www.cprogramming.com/tutorial.html

Quote:
 Originally from CProgramming.comWhile reading a tutorial or a book, it is often helpful to type - not copy and paste (even if you can!) - the code into the compiler and run it. Typing it yourself will help you to get used to the typical typing errors that cause problems and it will force you to pay attention to the details of programming syntax. Typing your program will also familiarize you with the general structure of programs and with the use of common commands. After running an example program - and after making certain that you understand how it works - you should experiment with it: play with the program and test your own ideas. By seeing which modifications cause problems and which sections of the code are most important to the function of the program, you should learn quite a bit about programming.

There are many more great links out there and its definatly worth the time it takes to thoroughly learn your language of choice. Attempting to Write a game before completly knowing your language is like trying to write a book without knowing english, sure it's possible but you'll never fully get your ideas across if you're constantly referring to the dictionary!

##### Share on other sites
Thank you for the replies guys.

Chad, you are correct in that I am only starting out and don't entirely know what I'm doing. The namespace was being used for some other code that was removed previously and I left that in by mistake. Also as for inclusion guards, I had absolutely no idea about them at all, until last night. Your post has given me a heap to think about, and I realised how litle I actually know, but I am happy with my progress so far. I am starting a course next year in C++ and game design so this is all just trying to learn as much as I can until then.

Anyway I appreciate the links, and the pointers, am making some more headway now. Have learnt a heck of a lot about inclusion and the proper workings of global variables. Have learnt about the 'pragma' directives and all about the #ifndef, #define and #endif commands.

Will post back if I run in to more trouble, which is bound to happen soon. :)

Cheers,

##### Share on other sites

#define SCREEN_FLAGS SDL_SWSURFACE...if(fullscreen)   g_screen = SDL_SetVideoMode(w, h, BPP, SCREEN_FLAGS | SDL_FULLSCREEN);else   g_screen = SDL_SetVideoMode(w, h, BPP, SCREEN_FLAGS);

Can be:
int SCREEN_FLAGS = SDL_SWSURFACE;...if(fullscreen)   SCREEN_FLAGS |= SDL_FULLSCREEN;g_screen = SDL_SetVideoMode(w, h, BPP, SCREEN_FLAGS);

Reason being is that what's the point of keeping the screen flags if you are not storing the real flags? Later on if you want to toggle fullscreen, you can simply do a SCREEN_FLAGS ^= SDL_FULLSCREEN; to remove out the flag for full screen and change it and you can do a if( SCREEN_FLAGS & SDL_FULLSCREEN ) to test for if fullscreen is enabled. Moreso, if you set the flags to SDL_HWSURFACE, and it doesn't work, you will want to then try SDL_SWSURFACE, and if FULLSCREEN fails, you will want to try without it.

SDL_FreeSurface(g_screen);

YOu never want to call free surface on your main screen surface that you call SDL_SetVideoMode with!

void init(){		graphics_init(SCREEN_WIDTH, SCREEN_HEIGHT, false);		g_image = SDL_LoadBMP("background.bmp");}

You should add some error checking in main.cpp.
int main(int argc, char **argv){   if( !init() )      return -1;...int init(){	   graphics_init(SCREEN_WIDTH, SCREEN_HEIGHT, false);   g_image = SDL_LoadBMP("background.bmp");   if( !g_image )   {      cout << "Background could not be found!";      return false;   }   return true;}

Usually you will want an initialize function that returns a value based on the success or failure of the setup code. It is very important when you add a lot more to your program.

bool graphics_init(int w, int h, bool fullscreen)

Good use of return value, but you don't actually use it! Since you simply exit (which is what you should do if SDL can't be initialized) you will want to change it to void.
void graphics_init(int w, int h, bool fullscreen)

SDL_UpdateRect(g_screen, 0, 0, 0, 0);

Should preferably be
SDL_Flip(g_screen);

Because if you decide to use double buffering down the line, SDL_Flip is what you must use. However, when you don't use double buffering, it calls SDL_UpdateRect(Screen,0,0,0,0); automatically, so it's a 2 for 1 deal [wink]

Just a few suggestions [smile]

##### Share on other sites
Hi Drew, thank you heaps. Helpful as always.

Now some comments from me. :)

Quote:
 Original post by Drew_Benton#define SCREEN_FLAGS SDL_SWSURFACE...if(fullscreen) g_screen = SDL_SetVideoMode(w, h, BPP, SCREEN_FLAGS | SDL_FULLSCREEN);else g_screen = SDL_SetVideoMode(w, h, BPP, SCREEN_FLAGS);Can be:int SCREEN_FLAGS = SDL_SWSURFACE;...if(fullscreen) SCREEN_FLAGS |= SDL_FULLSCREEN;g_screen = SDL_SetVideoMode(w, h, BPP, SCREEN_FLAGS);

Thanks, that makes sense, have changed my code to reflect this.

Quote:
 SDL_FreeSurface(g_screen);YOu never want to call free surface on your main screen surface that you call SDL_SetVideoMode with!

Sorry I don't understand. Will SDL_Quit() clear this surface automatically? Why do I not clear it when I am shutting down?

Quote:
 void init(){ graphics_init(SCREEN_WIDTH, SCREEN_HEIGHT, false); g_image = SDL_LoadBMP("background.bmp");}You should add some error checking in main.cpp.int main(int argc, char **argv){ if( !init() ) return -1;...int init(){ graphics_init(SCREEN_WIDTH, SCREEN_HEIGHT, false); g_image = SDL_LoadBMP("background.bmp"); if( !g_image ) { cout << "Background could not be found!"; return false; } return true;}Usually you will want an initialize function that returns a value based on the success or failure of the setup code. It is very important when you add a lot more to your program.bool graphics_init(int w, int h, bool fullscreen)Good use of return value, but you don't actually use it! Since you simply exit (which is what you should do if SDL can't be initialized) you will want to change it to void.void graphics_init(int w, int h, bool fullscreen)

Thank you, am going through and putting in some error checking now.

Quote:
 SDL_UpdateRect(g_screen, 0, 0, 0, 0);Should preferably beSDL_Flip(g_screen);Because if you decide to use double buffering down the line, SDL_Flip is what you must use. However, when you don't use double buffering, it calls SDL_UpdateRect(Screen,0,0,0,0); automatically, so it's a 2 for 1 deal [wink]

Ahhhhhhh, now that is a bonus. Changing now. Didn't realise this was the case.

Quote:
 Just a few suggestions [smile]

They were extremely helpful, and I appreciate you taking the time to give me some pointers.

Cheers,

##### Share on other sites
Quote:
 Original post by JWindebankSorry I don't understand. Will SDL_Quit() clear this surface automatically? Why do I not clear it when I am shutting down?

[smile] Yes, when you call SDL_Quit, SDL is deinitialized properly and the screen memory is taken care of. The basics of how it works is like this. The main screen is allocated by your call to SDL_SetVideoMode. However, a new SDL_Surface* is not made for the screen. I can't find the specific, but you will only need to call SDL_FreeSurface on surfaces that you create manually, or load with SDL_LoadBMP (or IMG_Load for SDL_Image). Here's the function SetVideoMode:

SDL_Surface * SDL_SetVideoMode (int width, int height, int bpp, Uint32 flags){	SDL_VideoDevice *video, *this;	SDL_Surface *prev_mode, *mode;	int video_w;	int video_h;	int video_bpp;	int is_opengl;	SDL_GrabMode saved_grab;	/* Start up the video driver, if necessary..	   WARNING: This is the only function protected this way!	 */	if ( ! current_video ) {		if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) < 0 ) {			return(NULL);		}	}	this = video = current_video;	/* Default to the current video bpp */	if ( bpp == 0 ) {		flags |= SDL_ANYFORMAT;		bpp = SDL_VideoSurface->format->BitsPerPixel;	}	/* Get a good video mode, the closest one possible */	video_w = width;	video_h = height;	video_bpp = bpp;	if ( ! SDL_GetVideoMode(&video_w, &video_h, &video_bpp, flags) ) {		return(NULL);	}	/* Check the requested flags */	/* There's no palette in > 8 bits-per-pixel mode */	if ( video_bpp > 8 ) {		flags &= ~SDL_HWPALETTE;	}#if 0	if ( (flags&SDL_FULLSCREEN) != SDL_FULLSCREEN ) {		/* There's no windowed double-buffering */		flags &= ~SDL_DOUBLEBUF;	}#endif	if ( (flags&SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {		/* Use hardware surfaces when double-buffering */		flags |= SDL_HWSURFACE;	}	is_opengl = ( ( flags & SDL_OPENGL ) == SDL_OPENGL );	if ( is_opengl ) {		/* These flags are for 2D video modes only */		flags &= ~(SDL_HWSURFACE|SDL_DOUBLEBUF);	}	/* Reset the keyboard here so event callbacks can run */	SDL_ResetKeyboard();	SDL_ResetMouse();	/* Clean up any previous video mode */	if ( SDL_PublicSurface != NULL ) {		SDL_PublicSurface = NULL;	}	if ( SDL_ShadowSurface != NULL ) {		SDL_Surface *ready_to_go;		ready_to_go = SDL_ShadowSurface;		SDL_ShadowSurface = NULL;		SDL_FreeSurface(ready_to_go);	}	if ( video->physpal ) {		free(video->physpal->colors);		free(video->physpal);		video->physpal = NULL;	}	if( video->gammacols) {		free(video->gammacols);		video->gammacols = NULL;	}	/* Save the previous grab state and turn off grab for mode switch */	saved_grab = SDL_WM_GrabInputOff();	/* Try to set the video mode, along with offset and clipping */	prev_mode = SDL_VideoSurface;	SDL_LockCursor();	SDL_VideoSurface = NULL;	/* In case it's freed by driver */	mode = video->SetVideoMode(this, prev_mode,video_w,video_h,video_bpp,flags);	if ( mode ) { /* Prevent resize events from mode change */	    SDL_PrivateResize(mode->w, mode->h);	    /* Sam - If we asked for OpenGL mode, and didn't get it, fail */	    if ( is_opengl && !(mode->flags & SDL_OPENGL) ) {		mode = NULL;		SDL_SetError("OpenGL not available");	    }	}	/*	 * rcg11292000	 * If you try to set an SDL_OPENGL surface, and fail to find a	 * matching  visual, then the next call to SDL_SetVideoMode()	 * will segfault, since  we no longer point to a dummy surface,	 * but rather NULL.	 * Sam 11/29/00	 * WARNING, we need to make sure that the previous mode hasn't	 * already been freed by the video driver.  What do we do in	 * that case?  Should we call SDL_VideoInit() again?	 */	SDL_VideoSurface = (mode != NULL) ? mode : prev_mode;	if ( (mode != NULL) && (!is_opengl) ) {		/* Sanity check */		if ( (mode->w < width) || (mode->h < height) ) {			SDL_SetError("Video mode smaller than requested");			return(NULL);		}		/* If we have a palettized surface, create a default palette */		if ( mode->format->palette ) {			SDL_PixelFormat *vf = mode->format;			SDL_DitherColors(vf->palette->colors, vf->BitsPerPixel);			video->SetColors(this, 0, vf->palette->ncolors,			                           vf->palette->colors);		}		/* Clear the surface to black */		video->offset_x = 0;		video->offset_y = 0;		mode->offset = 0;		SDL_SetClipRect(mode, NULL);		SDL_ClearSurface(mode);		/* Now adjust the offsets to match the desired mode */		video->offset_x = (mode->w-width)/2;		video->offset_y = (mode->h-height)/2;		mode->offset = video->offset_y*mode->pitch +				video->offset_x*mode->format->BytesPerPixel;#ifdef DEBUG_VIDEO  fprintf(stderr,	"Requested mode: %dx%dx%d, obtained mode %dx%dx%d (offset %d)\n",		width, height, bpp,		mode->w, mode->h, mode->format->BitsPerPixel, mode->offset);#endif		mode->w = width;		mode->h = height;		SDL_SetClipRect(mode, NULL);	}	SDL_ResetCursor();	SDL_UnlockCursor();	/* If we failed setting a video mode, return NULL... (Uh Oh!) */	if ( mode == NULL ) {		return(NULL);	}	/* If there is no window manager, set the SDL_NOFRAME flag */	if ( ! video->info.wm_available ) {		mode->flags |= SDL_NOFRAME;	}	/* Reset the mouse cursor and grab for new video mode */	SDL_SetCursor(NULL);	if ( video->UpdateMouse ) {		video->UpdateMouse(this);	}	SDL_WM_GrabInput(saved_grab);	SDL_GetRelativeMouseState(NULL, NULL); /* Clear first large delta */#ifdef HAVE_OPENGL	/* Load GL symbols (before MakeCurrent, where we need glGetString). */	if ( flags & (SDL_OPENGL | SDL_OPENGLBLIT) ) {#if (defined(macintosh) && !defined(__MWERKS__))#define __SDL_NOGETPROCADDR__#elif defined(__QNXNTO__) && (_NTO_VERSION < 630)#define __SDL_NOGETPROCADDR__#elif defined(__MINT__)#define __SDL_NOGETPROCADDR__#endif#ifdef __SDL_NOGETPROCADDR__    #define SDL_PROC(ret,func,params) video->func=func;#else    #define SDL_PROC(ret,func,params)     do {         video->func = SDL_GL_GetProcAddress(#func);         if ( ! video->func ) {             SDL_SetError("Couldn't load GL function: %s\n", #func);         return(NULL);         }     } while ( 0 );#endif /* __SDL_NOGETPROCADDR__ */#include "SDL_glfuncs.h"#undef SDL_PROC		}#endif /* HAVE_OPENGL */	/* If we're running OpenGL, make the context current */	if ( (video->screen->flags & SDL_OPENGL) &&	      video->GL_MakeCurrent ) {		if ( video->GL_MakeCurrent(this) < 0 ) {			return(NULL);		}	}	/* Set up a fake SDL surface for OpenGL "blitting" */	if ( (flags & SDL_OPENGLBLIT) == SDL_OPENGLBLIT ) {		/* Load GL functions for performing the texture updates */#ifdef HAVE_OPENGL		/* Create a software surface for blitting */#ifdef GL_VERSION_1_2		/* If the implementation either supports the packed pixels		   extension, or implements the core OpenGL 1.2 API, it will		   support the GL_UNSIGNED_SHORT_5_6_5 texture format.		 */		if ( (bpp == 16) &&		     (strstr((const char *)video->glGetString(GL_EXTENSIONS), "GL_EXT_packed_pixels") ||		     (atof((const char *)video->glGetString(GL_VERSION)) >= 1.2f))		   ) {			video->is_32bit = 0;			SDL_VideoSurface = SDL_CreateRGBSurface(				flags, 				width, 				height,  				16,				31 << 11,				63 << 5,				31,				0				);		}		else#endif /* OpenGL 1.2 */		{			video->is_32bit = 1;			SDL_VideoSurface = SDL_CreateRGBSurface(				flags, 				width, 				height, 				32, #if SDL_BYTEORDER == SDL_LIL_ENDIAN				0x000000FF,				0x0000FF00,				0x00FF0000,				0xFF000000#else				0xFF000000,				0x00FF0000,				0x0000FF00,				0x000000FF#endif				);		}		if ( ! SDL_VideoSurface ) {			return(NULL);		}		SDL_VideoSurface->flags = mode->flags | SDL_OPENGLBLIT;		/* Free the original video mode surface (is this safe?) */		SDL_FreeSurface(mode);		/* Set the surface completely opaque & white by default */		memset( SDL_VideoSurface->pixels, 255, SDL_VideoSurface->h * SDL_VideoSurface->pitch );		video->glGenTextures( 1, &video->texture );		video->glBindTexture( GL_TEXTURE_2D, video->texture );		video->glTexImage2D(			GL_TEXTURE_2D,			0,			video->is_32bit ? GL_RGBA : GL_RGB,			256,			256,			0,			video->is_32bit ? GL_RGBA : GL_RGB,#ifdef GL_VERSION_1_2			video->is_32bit ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT_5_6_5,#else			GL_UNSIGNED_BYTE,#endif			NULL);		video->UpdateRects = SDL_GL_UpdateRectsLock;#else		SDL_SetError("Somebody forgot to #define HAVE_OPENGL");		return(NULL);#endif	}	/* Create a shadow surface if necessary */	/* There are three conditions under which we create a shadow surface:		1.  We need a particular bits-per-pixel that we didn't get.		2.  We need a hardware palette and didn't get one.		3.  We need a software surface and got a hardware surface.	*/	if ( !(SDL_VideoSurface->flags & SDL_OPENGL) &&	     (	     (  !(flags&SDL_ANYFORMAT) &&			(SDL_VideoSurface->format->BitsPerPixel != bpp)) ||	     (   (flags&SDL_HWPALETTE) && 				!(SDL_VideoSurface->flags&SDL_HWPALETTE)) ||		/* If the surface is in hardware, video writes are visible		   as soon as they are performed, so we need to buffer them		 */	     (   ((flags&SDL_HWSURFACE) == SDL_SWSURFACE) &&				(SDL_VideoSurface->flags&SDL_HWSURFACE)) ||	     (   (flags&SDL_DOUBLEBUF) &&				(SDL_VideoSurface->flags&SDL_HWSURFACE) &&				!(SDL_VideoSurface->flags&SDL_DOUBLEBUF))	     ) ) {		SDL_CreateShadowSurface(bpp);		if ( SDL_ShadowSurface == NULL ) {			SDL_SetError("Couldn't create shadow surface");			return(NULL);		}		SDL_PublicSurface = SDL_ShadowSurface;	} else {		SDL_PublicSurface = SDL_VideoSurface;	}	video->info.vfmt = SDL_VideoSurface->format;	/* We're done! */	return(SDL_PublicSurface);}

Next is the code for SDL_VideoQuit, which is called by SDL_Quit.

/* * Clean up the video subsystem */void SDL_VideoQuit (void){	SDL_Surface *ready_to_go;	if ( current_video ) {		SDL_VideoDevice *video = current_video;		SDL_VideoDevice *this  = current_video;		/* Halt event processing before doing anything else */		SDL_StopEventLoop();		/* Clean up allocated window manager items */		if ( SDL_PublicSurface ) {			SDL_PublicSurface = NULL;		}		SDL_CursorQuit();		/* Just in case... */		SDL_WM_GrabInputOff();		/* Clean up the system video */		video->VideoQuit(this);		/* Free any lingering surfaces */		ready_to_go = SDL_ShadowSurface;		SDL_ShadowSurface = NULL;		SDL_FreeSurface(ready_to_go);		if ( SDL_VideoSurface != NULL ) {			ready_to_go = SDL_VideoSurface;			SDL_VideoSurface = NULL;			SDL_FreeSurface(ready_to_go);		}		SDL_PublicSurface = NULL;		/* Clean up miscellaneous memory */		if ( video->physpal ) {			free(video->physpal->colors);			free(video->physpal);			video->physpal = NULL;		}		if ( video->gammacols ) {			free(video->gammacols);			video->gammacols = NULL;		}		if ( video->gamma ) {			free(video->gamma);			video->gamma = NULL;		}		if ( video->wm_title != NULL ) {			free(video->wm_title);			video->wm_title = NULL;		}		if ( video->wm_icon != NULL ) {			free(video->wm_icon);			video->wm_icon = NULL;		}		/* Finish cleaning up video subsystem */		video->free(this);		current_video = NULL;	}	return;}

It's a lot of mess, but if you look though it some, you will see how the surfaces are all handeled internally, which is why you do not need to call FreeSurface on the main screen.