Sign in to follow this  

Beginner needs help (SDL_Mixer & SDL_ttf)

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, This is my first post on gamedev.net so please be gentle with me :) Apologies for the length of this post, I've tried to be as informative on my problems as possible. I'm a beginner C++ programmer who's decided to dive in and get his feet wet with SDL after reading about half of Michael Dawson's excellent book, Beginning C++ Game Programming. I'm using Dev-C++ as my compiler (running on Windows XP), and as well as C++ & SDL I'm using SDL_mixer, SDL_ttf & SDL_gfx. I've found it pretty hard going so far but have managed to get a quick & dirty simple Pong game going. However, I've hit upon a couple of snags which I need a little help with: 1: SDL_mixer problems- I'm using SDL_mixer to provide my background music and for sound effects when the ball bounces off the walls & paddles. I've got it all working and have set the music to loop infinitely, but when the music finishes and returns to the start I get a little gap. The music I'm using was written to loop perfectly and does so when I play it outside of my program, so how can I get rid of this? I'm guessing it might have something to do with the chunksize? When I initialise SDL_mixer the code I'm using is Mix_OpenAudio( 44100, AUDIO_S16, 2, 2048 ); and the music is .ogg format if that makes any difference. The command to play the music (Mix_PlayMusic( music, -1 );) is outside my while(gameRunning) main game loop. I've also got a minor problem with panning- I've set the sounds which play when the ball bounces off the left/right paddles to pan to the corresponding left & right. It works, but occasionally the panning glitches and momentarily (literally for milliseconds) plays the sound in the centre. I have all four sound effects I'm using set to different channels. Are these problems symptomatic of SDL_mixer itself or is it something I'm doing wrong, which is fixable? Should I try using a different sound library instead? 2. SDL_ttf problem- how do I go about using SDL_ttf to render my score integers? I have my scores as integer variables which increment when the ball goes off the side of the screen. I can get SDL_ttf to draw to the screen when it's got a const char* passed to TTF_RenderText_Solid(), but trying to get the int in there produces the compile error "invalid conversion from `int' to `const char*'". I'd guess I'd have to convert the int somehow but if it needs to be const, how can it be changed when the score updates? Sorry, I don't think I'm explaining myself very well so please bear in mind that I'm a beginner and this has me totally stumped. If anyone can help with either of the above then I would be very appreciative. I can provide some more info/code if necessary. Cheers!

Share this post


Link to post
Share on other sites
Cheers for your prompt response, hadn't come across sprintf before so I'll look it up and do a bit of research.

However, since then I've come across a much more serious problem. The section of code which writes the word "pong" at the top of the screen (which will display the score when I work out how to do it) causes the amount of memory my game uses to continuously go up by 2MB per second, according to Windows Task Manager.

I know it's just this little section, as when commented out the bug goes away. I've got it towards the end of my while(gameRunning) loop, after the part where I use SDL_gfx to render the bat/ball etc and just before SDL_Flip(screen);



//draw word pong at top
score = TTF_RenderText_Blended (font, "PONG", textColor);

SDL_Rect offset;

//Get offsets
offset.x = BOUNDARY_TOP_LEFT;
offset.y = BOUNDARY_TOP_LEFT /2;
SDL_BlitSurface( score, NULL, screen, &offset );

SDL_Flip(screen);




How come it's using up so much memory, and what can I do?

Share this post


Link to post
Share on other sites
Because you're render the message surface every frame, you're creating a new surface every frame and not getting rid of it.

Render the message surface once, then just use it over and over. Then free it when you're done.

Share this post


Link to post
Share on other sites
You don't have to, but it is A LOT easier to make a function on your own to display text. A simple function I use looks like this:



void DrawText(SDL_Surface* screen, const char* theText, int size, int x, int y, int r, int g, int b)
{
//Font variable
TTF_Font *text = TTF_OpenFont("Font/KABELU.TTF", size);
if(text==NULL)
{
fprintf(stderr, "Could not load the font entitled KABELU");
}
//Color variable for the text
SDL_Color textColor = {r, g, b};
//create a surface, and name it message
SDL_Surface* message = TTF_RenderText_Solid(text, theText, textColor);
//font rect
SDL_Rect font = {x, y, 0, 0};
SDL_BlitSurface(message, NULL, screen, &font);
SDL_FreeSurface(message);
TTF_CloseFont(text);
}



Hope that helps.

Chad.

Share this post


Link to post
Share on other sites
Quote:
Original post by Chad Smith
You don't have to, but it is A LOT easier to make a function on your own to display text. A simple function I use looks like this:



void DrawText(SDL_Surface* screen, const char* theText, int size, int x, int y, int r, int g, int b)
{
//Font variable
TTF_Font *text = TTF_OpenFont("Font/KABELU.TTF", size);
if(text==NULL)
{
fprintf(stderr, "Could not load the font entitled KABELU");
}
//Color variable for the text
SDL_Color textColor = {r, g, b};
//create a surface, and name it message
SDL_Surface* message = TTF_RenderText_Solid(text, theText, textColor);
//font rect
SDL_Rect font = {x, y, 0, 0};
SDL_BlitSurface(message, NULL, screen, &font);
SDL_FreeSurface(message);
TTF_CloseFont(text);
}



Hope that helps.

Chad.


Oh God.....

You have any idea how much CPU you're wasting with that?

Share this post


Link to post
Share on other sites
Quote:
Original post by Chad Smith
You don't have to, but it is A LOT easier to make a function on your own to display text. A simple function I use looks like this:



void DrawText(SDL_Surface* screen, const char* theText, int size, int x, int y, int r, int g, int b)
{
//Font variable
TTF_Font *text = TTF_OpenFont("Font/KABELU.TTF", size);
if(text==NULL)
{
fprintf(stderr, "Could not load the font entitled KABELU");
}
//Color variable for the text
SDL_Color textColor = {r, g, b};
//create a surface, and name it message
SDL_Surface* message = TTF_RenderText_Solid(text, theText, textColor);
//font rect
SDL_Rect font = {x, y, 0, 0};
SDL_BlitSurface(message, NULL, screen, &font);
SDL_FreeSurface(message);
TTF_CloseFont(text);
}



Hope that helps.

Chad.


Sir, please don't.... With that every frame you are:

    1. Loading a font
    2. Loading a surface FROM that font
    3. Blitting the surface
    4. Freeing the surface
    5. Freeing the font

This would lower the framerate plus waste CPU... But then again, if you have 1GB/2GB of ram and a blazing fast computer and you really wouldn't care-less, then go for it....

Don't take this the wrong way... I'm just trying to say that this isn't really an efficient way... I'm sorry if it sounds harsh or anything.

Share this post


Link to post
Share on other sites
That is a good idea, but you load the font from the disk each time you call it. That is extremely inefficient.

Here is a more efficient solution.

class FontWriter
{
private:
TTF_Font* font;

public:
FontWriter(const std::string& filename, int size)
{
font = TTF_OpenFont(filename.c_str(), size);
// You should hanle errors here
}

~FontWriter( )
{
if(font)
{
TTF_CloseFont(font);
font = NULL;
}
}

void Write(const std::string& text, int x, int y, int r, int g, int b)
{
SDL_Color text_color = {r, g, b};

SDL_Surface* message = TTF_RenderText_Solid(font, text.c_str(), textColor);

SDL_Rect dest = {x, y, 0, 0};

SDL_BlitSurface(message, NULL, SDL_GetVideoSurface(), &dest);

SDL_FreeSurface(message);
}
};




Then you can use it like so:

FontWriter arial12("Fonts/Arial.ttf", 12);
arial12.Write("Hello", 0, 0, 255, 0, 0);

Share this post


Link to post
Share on other sites
Quote:
Original post by Simian Man
That is a good idea, but you load the font from the disk each time you call it. That is extremely inefficient.

Here is a more efficient solution.
*** Source Snippet Removed ***

Then you can use it like so:

FontWriter arial12("Fonts/Arial.ttf", 12);
arial12.Write("Hello", 0, 0, 255, 0, 0);


That's great and all, but there is even a better way:

class FontWriter {
SDL_Surface *pText;
TTF_Font *pFont;

void Blit(...);
void ChangeText(char const*const text);
};


In change text you would assign the surface a new one with new text... And the blit just blits it to a position... This is a better solution because for example, if you have a huge menu that just says: "Press SPACE to continue...", and doesn't change, then you will NOT want a new surface being created.

Share this post


Link to post
Share on other sites
You are right. The way I use SDL_ttf is to render all of the letters to a surface once and then get textures for individual letters off that (using OpenGL).

The time needed to create the surface is still probably .0001 times that needed to load the font off disk though.

A "ChangeText" method is a good idea, but then you need one object of this class for every text you put on the screen (And thus different copies of the font), or call ChangeText for each one, which eliminates the benefits.

Share this post


Link to post
Share on other sites
Lazy Foo: cheers for your surface rendering tip, that's so obvious I can't believe I didn't see it! I guess I'm not very used to SDL at present as I've only been doing it for a couple of days. Anyway, my memory problem is now solved. You're wicked-cool, as are your tutorials [cool]

Everyone else: I'm currently working on injecting a little artificial intelligence (or rather, artificial stupidy) into my enemy bat so he's not totally unbeatable, but as soon as I'm done with that I'm going to take your suggestions on board and hopefully solve my scoreboard issue. The response has been absolutely wonderful- you all have my eternal gratitude, and with any luck I may well have a complete (if very simple) game to show you within a few days!

By the way, if anyone wants to advise me on my SDL_mixer/sound library issues then I'll be your best friend [smile]

Cheers,

S

Share this post


Link to post
Share on other sites
Quote:
Original post by agi_shi
Quote:
Original post by Chad Smith
You don't have to, but it is A LOT easier to make a function on your own to display text. A simple function I use looks like this:



void DrawText(SDL_Surface* screen, const char* theText, int size, int x, int y, int r, int g, int b)
{
//Font variable
TTF_Font *text = TTF_OpenFont("Font/KABELU.TTF", size);
if(text==NULL)
{
fprintf(stderr, "Could not load the font entitled KABELU");
}
//Color variable for the text
SDL_Color textColor = {r, g, b};
//create a surface, and name it message
SDL_Surface* message = TTF_RenderText_Solid(text, theText, textColor);
//font rect
SDL_Rect font = {x, y, 0, 0};
SDL_BlitSurface(message, NULL, screen, &font);
SDL_FreeSurface(message);
TTF_CloseFont(text);
}



Hope that helps.

Chad.


Sir, please don't.... With that every frame you are:

    1. Loading a font
    2. Loading a surface FROM that font
    3. Blitting the surface
    4. Freeing the surface
    5. Freeing the font

This would lower the framerate plus waste CPU... But then again, if you have 1GB/2GB of ram and a blazing fast computer and you really wouldn't care-less, then go for it....

Don't take this the wrong way... I'm just trying to say that this isn't really an efficient way... I'm sorry if it sounds harsh or anything.



True, I guess with my gig of RAM, and fast computer I wasn't thinking about that. I knew about that all along but just didn't think about some stuff. lol. When I release my game, I will be changing that, for other people.

Chad.

Share this post


Link to post
Share on other sites

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

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this