git repos / blockattack-game

blame: source/code/sago/SagoTextField.cpp

normal view · raw

55ea55dd sago007 2018-03-24 16:07 1
/*
55ea55dd sago007 2018-03-24 16:07 2
Copyright (c) 2018 Poul Sander
55ea55dd sago007 2018-03-24 16:07 3
55ea55dd sago007 2018-03-24 16:07 4
Permission is hereby granted, free of charge, to any person
55ea55dd sago007 2018-03-24 16:07 5
obtaining a copy of this software and associated documentation files
55ea55dd sago007 2018-03-24 16:07 6
(the "Software"), to deal in the Software without restriction,
55ea55dd sago007 2018-03-24 16:07 7
including without limitation the rights to use, copy, modify, merge,
55ea55dd sago007 2018-03-24 16:07 8
publish, distribute, sublicense, and/or sell copies of the Software,
55ea55dd sago007 2018-03-24 16:07 9
and to permit persons to whom the Software is furnished to do so,
55ea55dd sago007 2018-03-24 16:07 10
subject to the following conditions:
55ea55dd sago007 2018-03-24 16:07 11
55ea55dd sago007 2018-03-24 16:07 12
The above copyright notice and this permission notice shall be
55ea55dd sago007 2018-03-24 16:07 13
included in all copies or substantial portions of the Software.
55ea55dd sago007 2018-03-24 16:07 14
55ea55dd sago007 2018-03-24 16:07 15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
55ea55dd sago007 2018-03-24 16:07 16
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
55ea55dd sago007 2018-03-24 16:07 17
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
55ea55dd sago007 2018-03-24 16:07 18
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
55ea55dd sago007 2018-03-24 16:07 19
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
55ea55dd sago007 2018-03-24 16:07 20
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
55ea55dd sago007 2018-03-24 16:07 21
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
55ea55dd sago007 2018-03-24 16:07 22
SOFTWARE.
55ea55dd sago007 2018-03-24 16:07 23
*/
55ea55dd sago007 2018-03-24 16:07 24
55ea55dd sago007 2018-03-24 16:07 25
#include "SagoTextField.hpp"
55ea55dd sago007 2018-03-24 16:07 26
#include <iostream>
55ea55dd sago007 2018-03-24 16:07 27
#include <SDL_ttf.h>
55ea55dd sago007 2018-03-24 16:07 28
55ea55dd sago007 2018-03-24 16:07 29
namespace sago {
55ea55dd sago007 2018-03-24 16:07 30
e94af580 sago007 2020-12-30 17:45 31
class OutlineHandler {
e94af580 sago007 2020-12-30 17:45 32
	TTF_Font* font;
e94af580 sago007 2020-12-30 17:45 33
	int originalOutline = 0;
e94af580 sago007 2020-12-30 17:45 34
	int targetOutline;
e94af580 sago007 2020-12-30 17:45 35
	bool doChange = false;
e94af580 sago007 2020-12-30 17:45 36
public:
e94af580 sago007 2020-12-30 17:45 37
	OutlineHandler(TTF_Font* font, int outline) : font{font}, targetOutline{outline} {
e94af580 sago007 2020-12-30 17:45 38
		originalOutline = TTF_GetFontOutline(font);
e94af580 sago007 2020-12-30 17:45 39
		if (originalOutline == targetOutline) {
e94af580 sago007 2020-12-30 17:45 40
			return;
55ea55dd sago007 2018-03-24 16:07 41
		}
e94af580 sago007 2020-12-30 17:45 42
		doChange = true;
e94af580 sago007 2020-12-30 17:45 43
		TTF_SetFontOutline(font, targetOutline);
55ea55dd sago007 2018-03-24 16:07 44
	};
e94af580 sago007 2020-12-30 17:45 45
e94af580 sago007 2020-12-30 17:45 46
	void reset() {
e94af580 sago007 2020-12-30 17:45 47
		if (doChange) {
e94af580 sago007 2020-12-30 17:45 48
			TTF_SetFontOutline(font,originalOutline);
e94af580 sago007 2020-12-30 17:45 49
			doChange = false;
e94af580 sago007 2020-12-30 17:45 50
		}
e94af580 sago007 2020-12-30 17:45 51
	}
e94af580 sago007 2020-12-30 17:45 52
e94af580 sago007 2020-12-30 17:45 53
	~OutlineHandler() {
e94af580 sago007 2020-12-30 17:45 54
		reset();
e94af580 sago007 2020-12-30 17:45 55
	}
e94af580 sago007 2020-12-30 17:45 56
private:
e94af580 sago007 2020-12-30 17:45 57
	OutlineHandler(const OutlineHandler& orig) = delete;
e94af580 sago007 2020-12-30 17:45 58
	OutlineHandler& operator=(const OutlineHandler& base) = delete;
e94af580 sago007 2020-12-30 17:45 59
};
e94af580 sago007 2020-12-30 17:45 60
55ea55dd sago007 2018-03-24 16:07 61
struct SagoTextField::SagoTextFieldData {
1a09fcd5 sago007 2018-03-25 13:32 62
	const sago::SagoDataHolder* tex = nullptr;
55ea55dd sago007 2018-03-24 16:07 63
	SDL_Surface* textSurface = nullptr;
55ea55dd sago007 2018-03-24 16:07 64
	SDL_Texture* texture = nullptr;
55ea55dd sago007 2018-03-24 16:07 65
	SDL_Surface* outlineTextSurface = nullptr;
55ea55dd sago007 2018-03-24 16:07 66
	SDL_Texture* outlineTexture = nullptr;
55ea55dd sago007 2018-03-24 16:07 67
	std::string fontName = "freeserif";
55ea55dd sago007 2018-03-24 16:07 68
	SDL_Color color = { 255, 255, 255, 0 };
55ea55dd sago007 2018-03-24 16:07 69
	SDL_Color outlineColor = { 255, 255, 0, 0 };
55ea55dd sago007 2018-03-24 16:07 70
	int fontSize = 16;
55ea55dd sago007 2018-03-24 16:07 71
	int outline = 0;
55ea55dd sago007 2018-03-24 16:07 72
	std::string text = "";
55ea55dd sago007 2018-03-24 16:07 73
	std::string renderedText = "";
55ea55dd sago007 2018-03-24 16:07 74
	Uint64 renderedVersion = 0;
55ea55dd sago007 2018-03-24 16:07 75
};
e94af580 sago007 2020-12-30 17:45 76
55ea55dd sago007 2018-03-24 16:07 77
SagoTextField::SagoTextField() {
55ea55dd sago007 2018-03-24 16:07 78
	data = new SagoTextFieldData();
55ea55dd sago007 2018-03-24 16:07 79
}
55ea55dd sago007 2018-03-24 16:07 80
55ea55dd sago007 2018-03-24 16:07 81
SagoTextField::SagoTextField(SagoTextField&& o) noexcept {
55ea55dd sago007 2018-03-24 16:07 82
	data = o.data;
55ea55dd sago007 2018-03-24 16:07 83
	o.data = nullptr;
55ea55dd sago007 2018-03-24 16:07 84
}
55ea55dd sago007 2018-03-24 16:07 85
eb0258c8 sago007 2018-04-02 13:23 86
SagoTextField& SagoTextField::CopyFrom(const SagoTextField& base) {
ff33341c sago007 2018-03-26 16:03 87
	ClearCache();
906183f8 sago007 2018-03-26 13:14 88
	try {
906183f8 sago007 2018-03-26 13:14 89
		*data = *(base.data);
906183f8 sago007 2018-03-26 13:14 90
		//Copy all data but do not reuse the cache as it would result in a double free
906183f8 sago007 2018-03-26 13:14 91
		data->outlineTextSurface = nullptr;
906183f8 sago007 2018-03-26 13:14 92
		data->outlineTexture = nullptr;
906183f8 sago007 2018-03-26 13:14 93
		data->textSurface = nullptr;
906183f8 sago007 2018-03-26 13:14 94
		data->texture = nullptr;
906183f8 sago007 2018-03-26 13:14 95
		return *this;
e94af580 sago007 2020-12-30 17:45 96
	}
e94af580 sago007 2020-12-30 17:45 97
	catch (...) {
906183f8 sago007 2018-03-26 13:14 98
		delete data;
906183f8 sago007 2018-03-26 13:14 99
		throw;
906183f8 sago007 2018-03-26 13:14 100
	}
d91e7363 sago007 2018-03-26 13:09 101
}
d91e7363 sago007 2018-03-26 13:09 102
55ea55dd sago007 2018-03-24 16:07 103
SagoTextField::~SagoTextField() {
e94af580 sago007 2020-12-30 17:45 104
	if (!data) {
55ea55dd sago007 2018-03-24 16:07 105
		return;
55ea55dd sago007 2018-03-24 16:07 106
	}
55ea55dd sago007 2018-03-24 16:07 107
	ClearCache();
55ea55dd sago007 2018-03-24 16:07 108
	delete data;
55ea55dd sago007 2018-03-24 16:07 109
}
55ea55dd sago007 2018-03-24 16:07 110
1a09fcd5 sago007 2018-03-25 13:32 111
void SagoTextField::SetHolder(const SagoDataHolder* holder) {
55ea55dd sago007 2018-03-24 16:07 112
	data->tex = holder;
55ea55dd sago007 2018-03-24 16:07 113
}
55ea55dd sago007 2018-03-24 16:07 114
55ea55dd sago007 2018-03-24 16:07 115
void SagoTextField::SetText(const char* text) {
0b8fb137 sago007 2018-03-31 19:53 116
	data->text = text;
0b8fb137 sago007 2018-03-31 19:53 117
}
0b8fb137 sago007 2018-03-31 19:53 118
0b8fb137 sago007 2018-03-31 19:53 119
void SagoTextField::SetText(const std::string& text) {
55ea55dd sago007 2018-03-24 16:07 120
	data->text = text;
55ea55dd sago007 2018-03-24 16:07 121
}
55ea55dd sago007 2018-03-24 16:07 122
55ea55dd sago007 2018-03-24 16:07 123
void SagoTextField::SetColor(const SDL_Color& color) {
55ea55dd sago007 2018-03-24 16:07 124
	data->color = color;
55ea55dd sago007 2018-03-24 16:07 125
}
55ea55dd sago007 2018-03-24 16:07 126
55ea55dd sago007 2018-03-24 16:07 127
void SagoTextField::SetFont(const char* fontName) {
55ea55dd sago007 2018-03-24 16:07 128
	data->fontName = fontName;
55ea55dd sago007 2018-03-24 16:07 129
}
55ea55dd sago007 2018-03-24 16:07 130
55ea55dd sago007 2018-03-24 16:07 131
void SagoTextField::SetFontSize(int fontSize) {
55ea55dd sago007 2018-03-24 16:07 132
	data->fontSize = fontSize;
55ea55dd sago007 2018-03-24 16:07 133
}
55ea55dd sago007 2018-03-24 16:07 134
55ea55dd sago007 2018-03-24 16:07 135
void SagoTextField::SetOutline(int outlineSize, const SDL_Color& color) {
55ea55dd sago007 2018-03-24 16:07 136
	data->outline = outlineSize;
55ea55dd sago007 2018-03-24 16:07 137
	data->outlineColor = color;
55ea55dd sago007 2018-03-24 16:07 138
}
55ea55dd sago007 2018-03-24 16:07 139
55ea55dd sago007 2018-03-24 16:07 140
const std::string& SagoTextField::GetText() const {
55ea55dd sago007 2018-03-24 16:07 141
	return data->text;
55ea55dd sago007 2018-03-24 16:07 142
}
55ea55dd sago007 2018-03-24 16:07 143
55ea55dd sago007 2018-03-24 16:07 144
void SagoTextField::ClearCache() {
55ea55dd sago007 2018-03-24 16:07 145
	if (data->texture) {
55ea55dd sago007 2018-03-24 16:07 146
		SDL_DestroyTexture(data->texture);
55ea55dd sago007 2018-03-24 16:07 147
		data->texture = nullptr;
55ea55dd sago007 2018-03-24 16:07 148
	}
55ea55dd sago007 2018-03-24 16:07 149
	if (data->textSurface) {
55ea55dd sago007 2018-03-24 16:07 150
		SDL_FreeSurface(data->textSurface);
55ea55dd sago007 2018-03-24 16:07 151
		data->textSurface = nullptr;
55ea55dd sago007 2018-03-24 16:07 152
	}
55ea55dd sago007 2018-03-24 16:07 153
	if (data->outlineTexture) {
55ea55dd sago007 2018-03-24 16:07 154
		SDL_DestroyTexture(data->outlineTexture);
55ea55dd sago007 2018-03-24 16:07 155
		data->outlineTexture = nullptr;
55ea55dd sago007 2018-03-24 16:07 156
	}
55ea55dd sago007 2018-03-24 16:07 157
	if (data->outlineTextSurface) {
55ea55dd sago007 2018-03-24 16:07 158
		SDL_FreeSurface(data->outlineTextSurface);
55ea55dd sago007 2018-03-24 16:07 159
		data->outlineTextSurface = nullptr;
55ea55dd sago007 2018-03-24 16:07 160
	}
55ea55dd sago007 2018-03-24 16:07 161
}
55ea55dd sago007 2018-03-24 16:07 162
55ea55dd sago007 2018-03-24 16:07 163
void SagoTextField::UpdateCache(SDL_Renderer* target) {
343fbe43 sago007 2018-03-27 19:53 164
	if (!data->tex) {
343fbe43 sago007 2018-03-27 19:53 165
		std::cerr << "FATAL: DataHolder not set!\n";
343fbe43 sago007 2018-03-27 19:53 166
		abort();
343fbe43 sago007 2018-03-27 19:53 167
	}
55ea55dd sago007 2018-03-24 16:07 168
	ClearCache();
e94af580 sago007 2020-12-30 17:45 169
	TTF_Font* font = data->tex->getFontPtr(data->fontName, data->fontSize);
55ea55dd sago007 2018-03-24 16:07 170
	data->textSurface = TTF_RenderUTF8_Blended (font, data->text.c_str(), data->color);
55ea55dd sago007 2018-03-24 16:07 171
	data->texture = SDL_CreateTextureFromSurface(target, data->textSurface);
55ea55dd sago007 2018-03-24 16:07 172
	if (data->outline > 0) {
55ea55dd sago007 2018-03-24 16:07 173
		OutlineHandler oh(font, data->outline);
55ea55dd sago007 2018-03-24 16:07 174
		data->outlineTextSurface = TTF_RenderUTF8_Blended (font, data->text.c_str(), data->outlineColor);
55ea55dd sago007 2018-03-24 16:07 175
		data->outlineTexture = SDL_CreateTextureFromSurface(target, data->outlineTextSurface);
55ea55dd sago007 2018-03-24 16:07 176
		oh.reset();
55ea55dd sago007 2018-03-24 16:07 177
	}
55ea55dd sago007 2018-03-24 16:07 178
	data->renderedText = data->text;
55ea55dd sago007 2018-03-24 16:07 179
	data->renderedVersion = data->tex->getVersion();
55ea55dd sago007 2018-03-24 16:07 180
}
55ea55dd sago007 2018-03-24 16:07 181
bd788178 sago007 2018-03-31 16:03 182
void SagoTextField::GetRenderedSize(const char* text, int* w, int* h) {
e94af580 sago007 2020-12-30 17:45 183
	TTF_Font* font = data->tex->getFontPtr(data->fontName, data->fontSize);
bd788178 sago007 2018-03-31 16:03 184
	int ret = TTF_SizeUTF8(font, text, w, h);
bd788178 sago007 2018-03-31 16:03 185
	if (ret) {
bd788178 sago007 2018-03-31 16:03 186
		if (w) {
1ee3769b sago007 2018-03-31 16:34 187
			*w = 0;
bd788178 sago007 2018-03-31 16:03 188
		}
bd788178 sago007 2018-03-31 16:03 189
		if (h) {
1ee3769b sago007 2018-03-31 16:34 190
			*h = 0;
bd788178 sago007 2018-03-31 16:03 191
		}
bd788178 sago007 2018-03-31 16:03 192
		std::cerr << "GetRenderedSize failed to find size of " << text << ". Error code: " << ret << "\n";
bd788178 sago007 2018-03-31 16:03 193
	}
bd788178 sago007 2018-03-31 16:03 194
}
bd788178 sago007 2018-03-31 16:03 195
d91e7363 sago007 2018-03-26 13:09 196
void SagoTextField::Draw(SDL_Renderer* target, int x, int y, Alignment alignment, VerticalAlignment verticalAlignment) {
55ea55dd sago007 2018-03-24 16:07 197
	if (data->text.empty()) {
55ea55dd sago007 2018-03-24 16:07 198
		return;
55ea55dd sago007 2018-03-24 16:07 199
	}
55ea55dd sago007 2018-03-24 16:07 200
	if (data->text != data->renderedText || data->renderedVersion != data->tex->getVersion()) {
55ea55dd sago007 2018-03-24 16:07 201
		UpdateCache(target);
55ea55dd sago007 2018-03-24 16:07 202
	}
55ea55dd sago007 2018-03-24 16:07 203
	if (!data->texture) {
55ea55dd sago007 2018-03-24 16:07 204
		return;
55ea55dd sago007 2018-03-24 16:07 205
	}
55ea55dd sago007 2018-03-24 16:07 206
	int texW = 0;
55ea55dd sago007 2018-03-24 16:07 207
	int texH = 0;
55ea55dd sago007 2018-03-24 16:07 208
	SDL_QueryTexture(data->texture, NULL, NULL, &texW, &texH);
d91e7363 sago007 2018-03-26 13:09 209
	if (alignment == Alignment::center) {
d91e7363 sago007 2018-03-26 13:09 210
		x -= texW/2;
d91e7363 sago007 2018-03-26 13:09 211
	}
fc338170 sago007 2018-03-28 14:31 212
	if (alignment == Alignment::right) {
f9f05e62 sago007 2018-10-28 12:36 213
		x -= texW;
fc338170 sago007 2018-03-28 14:31 214
	}
d91e7363 sago007 2018-03-26 13:09 215
	if (verticalAlignment == VerticalAlignment::center) {
d91e7363 sago007 2018-03-26 13:09 216
		y -= texH/2;
d91e7363 sago007 2018-03-26 13:09 217
	}
492b2753 sago007 2018-04-07 14:37 218
	if (verticalAlignment == VerticalAlignment::bottom) {
492b2753 sago007 2018-04-07 14:37 219
		y -= texH;
492b2753 sago007 2018-04-07 14:37 220
	}
55ea55dd sago007 2018-03-24 16:07 221
	SDL_Rect dstrect = { x, y, texW, texH };
55ea55dd sago007 2018-03-24 16:07 222
	if (data->outlineTexture) {
55ea55dd sago007 2018-03-24 16:07 223
		int outlineTexW = 0;
55ea55dd sago007 2018-03-24 16:07 224
		int outlineTexH = 0;
55ea55dd sago007 2018-03-24 16:07 225
		SDL_QueryTexture(data->outlineTexture, NULL, NULL, &outlineTexW, &outlineTexH);
55ea55dd sago007 2018-03-24 16:07 226
		SDL_Rect dstrectOutline = { x-(data->outline), y-(data->outline), outlineTexW, outlineTexH };
55ea55dd sago007 2018-03-24 16:07 227
		SDL_RenderCopy(target, data->outlineTexture, NULL, &dstrectOutline);
55ea55dd sago007 2018-03-24 16:07 228
	}
55ea55dd sago007 2018-03-24 16:07 229
	SDL_RenderCopy(target, data->texture, NULL, &dstrect);
55ea55dd sago007 2018-03-24 16:07 230
}
55ea55dd sago007 2018-03-24 16:07 231
55ea55dd sago007 2018-03-24 16:07 232
}  //namespace sago