The SDL forums have moved to discourse.libsdl.org.
This is just a read-only archive of the previous forums, to keep old links working.


SDL Forum Index
SDL
Simple Directmedia Layer Forums
RWops - error with the TTF_OpenFontRW...
djkarstenv


Joined: 29 Sep 2011
Posts: 34
Hi all,

I hope I can explain this properly, but I have noticed an issue with the RWops function TTF_OpenFontRW, and that error can only be explained as follows :

I have created a routine that writes and reads all images, sounds and fonts into my own custom built resource file. When loading these resources again from my resource file, I use RWops. So, before using RWops I create a buffer in memory like this :

char* Buffer = (char*)malloc(Size);

This allocates a block of memory, with the size according to the resource I want to load.

Then I use RWops to load this buffer into the RWops struct :

SDL_RWops* RW = SDL_RWFromMem(Buffer, Size);

Now I use individual RWops calls to load the appropriate resource and point to it :

Fonts : TTF_Font* fnt = TTF_OpenFontRW(RW, 1, Size);
Images : SDL_Surface* img = SDL_LoadBMP_RW(RW, 1);
Sounds : Mix_Chunk* snd = Mix_LoadWAV_RW(RW, 1);


Having specified the "1" as an argument, I know these RW structs will release from memory automatically, so thats ok. Note : These are not all called at once, I have only written them together to show examples.

Now I can call free(Buffer) and this will free the memory chunk, and later when I'm done with the resource I call either SDL_FreeSurface() or TTF_CloseFont() or Mix_FreeChunk() etc...

BUT...

For the TTF version, when I call free(Buffer) before TTF_CloseFont(), the buffer is freed and it also releases the memory that TTF's fnt pointer is pointing to. With the other 2 resources this isn't the case, so I am guessing it's an issue with TTF_OpenFontRW.

This may sound terribly confusing, but if you do grasp it and have an idea, please let me know or better yet, if you coded any parts of TTF_OpenFontRW() then I might have spotted an error!

Smile
riksweeney


Joined: 17 Jan 2012
Posts: 38
I have exactly the same problem, freeing the buffer causes my game to crash, so I have to leave it allocated:
Code:

unsigned long size;
unsigned char *buffer;
SDL_RWops *rw;
TTF_Font *font;

buffer = uncompressFileRW(name, &size);

rw = SDL_RWFromMem(buffer, size);

font = TTF_OpenFontRW(rw, TRUE, fontSize);

/*free(buffer);*/

return font;

It's not a massive problem, since I only ever open the font once and the memory is freed when the program closes, but it does look like a bug in SDL_TTF's RWops.
djkarstenv


Joined: 29 Sep 2011
Posts: 34
Okay good, so it's not just me, I didn't expect anyone else to come across this error, it was a shot in the dark haha

Anyways thanks for your feedback. It took me hours to figure out why my game was crashing, then I spotted it. You're right, it's no big deal to leave it allocated, my games usually only use one or two fonts max.

By the way, when you state font = TTF_OpenFontRW(rw, TRUE, fontSize); , the TRUE argument will release the rw struct from memory automatically. When exactly does it get released, after this call or when u call CloseFont()? The documentation only says it gets released, but they dont say when, do u perhaps know?

Thanks

Smile
riksweeney


Joined: 17 Jan 2012
Posts: 38
I think it gets released at the end of the function call, but I'd have to check the source code to be certain.
djkarstenv


Joined: 29 Sep 2011
Posts: 34
okay, thanks Smile
J3dz


Joined: 21 Jul 2012
Posts: 1
Location: Germany
In 'TTF_Font* TTF_OpenFontRW( SDL_RWops *src, int freesrc, int ptsize )' you have set the freesrc parameter to 1. This sets the TTF_Font->freesrc flag and is checked when calling the 'void TTF_CloseFont( TTF_Font* font )' function. By calling 'SDL_RWclose( font->src );' the TTF_CloseFont function releases the memory for the internal SDL_RWops structure. Without that (freesrc=1), you have to call SDL_RWclose yourself ( SDL_RWclose( RW ); in your example ).

Functions like SDL_Surface * SDL_LoadBMP_RW (SDL_RWops *src, int freesrc) are different to the TTF_OpenFontRW by design. The image loading function is allocating the surface, checks about formats and palettes, etc. and then copies the image data to the surface. After that the source SDL_RWops is released by the SDL_LoadBMP_RW function itself, when called with a freesrc parameter that evaluates to true:


Code:

======== Load Bitmap RW ============
// note: freesrc = 1

char *imgbuffer =  (char*)malloc(DataSize);                // alloc buffer.
imgbuffer = LoadImageData(...);                            // load image.
SDL_RWops* RW = SDL_RWFromMem(imgbuffer, DataSize);        // create SDL internal storage struct.
SDL_Surface* img = SDL_LoadBMP_RW(RW, 1);                  // create surface.
// your SDL_RWops* RW is RELEASED from mem by calling
//   if ( freesrc && src ) {
//      SDL_RWclose(src);
//   }
// in the SDL_LoadBMP_RW function.
// With freesrc = 0 call SDL_RWclose(RW) here, or later, when finished using the SDL_RWops data.

free(imgbuffer);                                           // release load buffer.
// you release the image raw data buffer from memory as all data is copied into the surface and the only one
// holding a reference to it, SDL_RWops* RW is now obsolete.

...
DoSomeFunkyPainting(img);
...

SDL_FreeSurface(img);                                      // all painting done, release surface.
// your img SDL_Surface is RELEASED from mem



Now take a look at the differences in TTF_OpenFontRW:

Code:

======= Open Font RW =============
// note: freesrc = 1

char *fontbuffer =  (char*)malloc(DataSize);
fontbuffer = LoadFontData(...);
SDL_RWops* RW = SDL_RWFromMem(imgbuffer, DataSize);
TTF_Font* font = TTF_OpenFontRW(RW, 1, FontSize);
// your SDL_RWops* RW is NOT released from mem! TTF_OpenFontRW stores a reference to your SDL_RWops* RW buffer,
// while the RW itself holds the pointer to your fontbuffer.
//    font->src = src;
// calling free(fontbuffer) here is destroying your font data :P

...
WriteFooBarToScreen(surface, position, font);
...

TTF_CloseFont(font);
// your font TTF_Font is RELEASED from mem
// your SDL_RWops* RW is RELEASED from mem by calling SDL_RWclose( font->src );! With freesrc = 0 call SDL_RWclose(RW) yourself.
free(fontbuffer);
// your buffer is RELEASED from mem


I hope, this helps you to better understand whats going on, "under the hood".

Jedzia
djkarstenv


Joined: 29 Sep 2011
Posts: 34
Thanks Jedzia!

This does help understand the workings behind the scenes a little, and I now can see the differences a little clearer.

Looking at this block of code :

Quote:
...
WriteFooBarToScreen(surface, position, font);
...

TTF_CloseFont(font);
free(fontbuffer);


the font buffer has to be freed after using the font for drawing text as with the image version :

Quote:
free(imgbuffer);
...
DoSomeFunkyPainting(img);
...

SDL_FreeSurface(img);


the image buffer can be freed before using the SDL_Surface pointer for drawing images.

Now the problem I was having is that all the resource loading was coded in one library file, so i needed some way of passing the buffer pointer to the main program so that (in the case of TTF_Font) i can free the buffer later. I found a solution and I made my own buffer reference that then gets used in the main program to release the buffer data, else I have memory leaks.

Your code is quite clear and I will use it for future reference - thanks again!

Smile