sdl_ttf Corrupted message

closed account (DEhqDjzh)
hi, the message should say "current inited object count:" but it looks like this :
http://i.hizliresim.com/vPXgn4.jpg
here is the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 void displaytext(const char * a, SDL_Renderer * sr, int x, int y)
{
	if (TTF_Init() == -1)
	{
		printf("TTF_Init: %s\n", TTF_GetError());
		system("pause");
	}


	TTF_Font* Sans = TTF_OpenFont("FreeSans.ttf", 24); 
	if (!Sans) {
		printf("TTF_OpenFont: %s\n", TTF_GetError());
		
	}

	SDL_Color White = { 255, 255, 255 }; 

	SDL_Surface* surfaceMessage = TTF_RenderText_Solid(Sans, a, White); 

	SDL_Texture* Message = SDL_CreateTextureFromSurface(sr, surfaceMessage); 

	SDL_Rect Message_rect; 
	Message_rect.x = x; 
	Message_rect.y = y; 
	Message_rect.w = 100; 
	Message_rect.h = 70; 


						
	SDL_RenderCopy(sr, Message, NULL, &Message_rect); 

													 
}
What happens if you change line 25 and 26 to
1
2
Message_rect.w = surfaceMessage->w; 
Message_rect.h = surfaceMessage->h; 
?
closed account (DEhqDjzh)
@Peter87 It worked! now, how can I shrink the size of the text?
The second argument to TTF_OpenFont specifies the font size.

1
2
TTF_Font* Sans = TTF_OpenFont("FreeSans.ttf", 24); 
                                              ^
closed account (DEhqDjzh)
Thanks solved :)
I just noticed that the function has a memory leak. If you call it over and over again you will eventually run out of memory.

The TTF_Font that you get from TTF_OpenFont needs to be destroyed using TTF_CloseFont when you are done using it.
The SDL_Surface that you get from TTF_RenderText_Solid needs to be destroyed using SDL_FreeSurface when you are done using it.
The SDL_Texture that you get from SDL_CreateTextureFromSurface needs to be destroyed using SDL_DestroyTexture when you are done using it.


1
2
3
TTF_CloseFont(Sans);
SDL_FreeSurface(surfaceMessage);
SDL_DestroyTexture(Message);


Note that these things you are doing is quite expensive so if you care about performance you might want to reuse them instead of creating new ones each time. The text probably doesn't change each frame so you might want to keep the SDL_Texture around so that it can be reused. If the text changes from time to time, or you have multiple texts all using the same font and size, you might also want to reuse the TTF_Font but this will probably have a smaller impact overall. The SDL_Surface can probably not be reused in any useful way.
Last edited on
For those interested, here's a piece that uses SDL to discuss using C++11 to make memory safe this sort of thing:

https://swarminglogic.com/jotting/2015_05_smartwrappers
I see someone already fixed your problem, but there's another huge problem with this code: you're allocating resources and never freeing them. Further, you don't want to init the TTF system and load your font every single time you want to display a message, this is extremely inefficient considering in a game this is something that could happen tens of times per frame times 60 frames per second is hundreds of redundant calls to these functions a second. I would separate this into two functions. Note this is a very C-like way of doing this, someone else posted some C++ wrappers that would do this in a more C++-like way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bool init_ttf(const char* font_filename, int font_size, TTF_Font** font) {
  if(TTF_Init()) {
    goto error;
  }

  *font = TTF_OpenFont(font_filename, font_size);
  if(nullptr == *font) {
    goto error;
  }

  return true;

error:
  log_error(TTF_GetError());
  TTF_CloseFont(*font);
  *font = nullptr;

  TTF_Quit();

  return false;
}


This function initializes the TTF library and loads a font at a specific size for you. You want to keep this around to pass to the second function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
bool display_text(const char* message, SDL_Renderer* renderer, TTF_Font* font, int x, int y, SDL_Color color) {
  bool success = false;
  SDL_Surface* message_surface{nullptr};
  SDL_Texture* message_texture{nullptr};

  message_surface = TTF_RenderText_Solid(font, message, color);
  if(nullptr == message_surface) {
    log_error(TTF_GetError());
    goto done;
  }

  message_texture = SDL_CreateSurfaceFromTexture(renderer, message_surface);
  if(nullptr == message_texture) {
    log_error(SDL_GetError());
    goto done;
  }

  SDL_Rect dest_rect{x, y, message_surface->w, message_surface->h};
  if(SDL_RenderCopy(renderer, message_texture, NULL, &dest_rect)) {
    log_error(SDL_GetError());
    goto done;
  }

  success = true;

done:
  SDL_DestroyTexture(message_texture);
  SDL_FreeSurface(message_surface);
  return success;
}


Every function that allocates a resource and does not return that resource should free those resources. Every time. Without exception. As I mentioned above this is a very C-like way of doing this, so you may not want to use my method of doing this, but my point is that there is no code path that does not free resources. If there is an error, everything gets freed first. If there is success, it also gets freed.

You should also work on your variable names. What are a and sr? It's obvious (somewhat) looking at the parameter list, but I'm 10 lines down and I can't remember what sr is. Just call it renderer, it's just a few extra keystrokes.
Topic archived. No new replies allowed.