I have the following font object and when I declare some empty font objects in another object I get this seg fault. Do you see what I may be doing wrong with this and why it seg faults only when I create fonts that are unused? Other fonts that are declared and rendered don’t have the problem. The problem only happens when I add a Font object as part of a member that doesn’t get used at all. I would expect to be able to create an empty font object.
#ifndef FONT_H
#define FONT_H
#include <SDL2/SDL_ttf.h>
#include "Renderable.h"
namespace ley {
class Font : public Renderable {
private:
std::string textMessage;
SDL_Texture* Message;
SDL_Rect Message_rect;
TTF_Font* Classic;
SDL_Color color;
protected:
public:
Font();
Font(int, int, int, int);
~Font();
void init();
Font& operator=(const ley::Font& other); //copy assignment
Font operator()(Font& other); //copy constructor
void updateMessage(std::string s); // TODO this should be setMessage instead of updateMessage.
std::string getMessage();
std::string* getMessagePtr();
SDL_Texture* getTexturePtr();
void preRender(SDL_Renderer* r);
void render(SDL_Renderer * r, bool d);
TTF_Font* getTTFFont();
void setPos(SDL_Point p);
std::pair<int, int> size();
void setColor(SDL_Color c);
};
}
#endif
#include "Font.h"
ley::Font::Font()
:
Message(nullptr),
Classic(nullptr) {
Message_rect.x = 0;
Message_rect.y = 0;
Message_rect.h = 0;
Message_rect.w = 0;
init();
}
ley::Font::Font(int x, int y, int w, int h)
:
Message(nullptr),
Classic(nullptr) {
Message_rect.x = x;
Message_rect.y = y;
Message_rect.w = w;
Message_rect.h = h;
init();
}
void ley::Font::init() {
if (TTF_Init() < 0) {
SDL_Log("TTF_Init failed");
}
SDL_Log("Open font %s", textMessage.c_str());
Classic = TTF_OpenFont("assets/fonts/MartianMono-Regular.ttf", 24);
if(!Classic) {
printf("TTF_OpenFont: %s\n", TTF_GetError());
}
color = {255, 255, 255, 255};
}
ley::Font::~Font() {
if(Message) {
SDL_DestroyTexture(Message);
}
SDL_Log("Close Font %s , Inits, %d", textMessage.c_str(), TTF_WasInit());
if(Classic) {
TTF_CloseFont(Classic);
Classic = nullptr;
}
TTF_Quit();
}
//copy assignment operator
/*
ley::Font& ley::Font::operator=(ley::Font other) {
Message = nullptr;
Message_rect.x = other.Message_rect.x;
Message_rect.y = other.Message_rect.y;
Message_rect.w = other.Message_rect.w;
Message_rect.h = other.Message_rect.h;
updateMessage("");
return *this;
}
*/
ley::Font& ley::Font::operator=(const ley::Font& other) {
if (this == &other) return *this; // Handle self-assignment
// Free existing resources
if (Message) {
SDL_DestroyTexture(Message);
Message = nullptr;
}
if (Classic) {
TTF_CloseFont(Classic);
Classic = nullptr;
}
// Copy the state
Message_rect = other.Message_rect;
color = other.color;
textMessage = other.textMessage;
// Reinitialize resources
Classic = TTF_OpenFont("assets/fonts/MartianMono-Regular.ttf", 24);
if (!Classic) {
printf("TTF_OpenFont failed: %s\n", TTF_GetError());
}
return *this;
}
ley::Font ley::Font::operator()(ley::Font& other) {
Message = nullptr;
if (Classic) {
TTF_CloseFont(Classic);
}
SDL_Log("Open font");
Classic = TTF_OpenFont("assets/fonts/Montserrat-Regular.ttf", 24);
if(!Classic) {
printf("TTF_OpenFont: %s\n", TTF_GetError());
}
Message_rect.x = other.Message_rect.x; //controls the rect's x coordinate
Message_rect.y = other.Message_rect.y; // controls the rect's y coordinte
Message_rect.w = other.Message_rect.w; // controls the width of the rect
Message_rect.h = other.Message_rect.h; // controls the height of the rect
return *this;
}
void ley::Font::setColor(SDL_Color c) {
color = c;
}
void ley::Font::updateMessage(std::string s) {
//Only update the texture if the message has changed.
if(s != textMessage) {
textMessage = s;
//then invalidate the texture
if(Message) {
SDL_DestroyTexture(Message);
Message = nullptr;
}
}
}
std::string ley::Font::getMessage() {
return textMessage;
}
std::string* ley::Font::getMessagePtr() {
return &textMessage;
}
SDL_Texture* ley::Font::getTexturePtr() {
return Message;
}
void ley::Font::preRender(SDL_Renderer* r)
{
if(!Message) {
SDL_Surface* surfaceMessage;
surfaceMessage = TTF_RenderUTF8_Solid(Classic, textMessage.c_str(), color);
Message = SDL_CreateTextureFromSurface(r, surfaceMessage);
SDL_FreeSurface(surfaceMessage);
surfaceMessage = nullptr;
}
}
void ley::Font::render(SDL_Renderer * r, bool d) {
preRender(r);
// TODO this query texture should probably go in the setpos method and be called only when the position changes.
int w;
int h;
SDL_QueryTexture(Message,
NULL, NULL,
&w, &h);
Message_rect.h = h;
Message_rect.w = w;
SDL_RenderCopy(r, Message, NULL, &Message_rect);
}
TTF_Font* ley::Font::getTTFFont() {
return Classic;
}
void ley::Font::setPos(SDL_Point p) {
Message_rect.x = p.x;
Message_rect.y = p.y;
}
std::pair<int, int> ley::Font::size() {
int width = -1;
int height = -1;
if(Classic) {
TTF_SizeText(Classic, textMessage.c_str(), &width, &height);
}
return std::make_pair(width, height);
}