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
55ea55dd sago007 2018-03-24 16:07 31
	class OutlineHandler {
55ea55dd sago007 2018-03-24 16:07 32
		TTF_Font* font;
55ea55dd sago007 2018-03-24 16:07 33
		int originalOutline = 0;
55ea55dd sago007 2018-03-24 16:07 34
		int targetOutline;
55ea55dd sago007 2018-03-24 16:07 35
		bool doChange = false;
55ea55dd sago007 2018-03-24 16:07 36
	public:
55ea55dd sago007 2018-03-24 16:07 37
		OutlineHandler(TTF_Font* font, int outline) : font{font}, targetOutline{outline} {
55ea55dd sago007 2018-03-24 16:07 38
			originalOutline = TTF_GetFontOutline(font);
55ea55dd sago007 2018-03-24 16:07 39
			if (originalOutline == targetOutline) {
55ea55dd sago007 2018-03-24 16:07 40
				return;
55ea55dd sago007 2018-03-24 16:07 41
			}
55ea55dd sago007 2018-03-24 16:07 42
			doChange = true;
55ea55dd sago007 2018-03-24 16:07 43
			TTF_SetFontOutline(font, targetOutline);
55ea55dd sago007 2018-03-24 16:07 44
		};
55ea55dd sago007 2018-03-24 16:07 45
		
55ea55dd sago007 2018-03-24 16:07 46
		void reset() {
55ea55dd sago007 2018-03-24 16:07 47
			if (doChange) {
55ea55dd sago007 2018-03-24 16:07 48
				TTF_SetFontOutline(font,originalOutline);
55ea55dd sago007 2018-03-24 16:07 49
				doChange = false;
55ea55dd sago007 2018-03-24 16:07 50
			}
55ea55dd sago007 2018-03-24 16:07 51
		}
55ea55dd sago007 2018-03-24 16:07 52
		
55ea55dd sago007 2018-03-24 16:07 53
		~OutlineHandler() {
55ea55dd sago007 2018-03-24 16:07 54
			reset();
55ea55dd sago007 2018-03-24 16:07 55
		}
55ea55dd sago007 2018-03-24 16:07 56
	private:
55ea55dd sago007 2018-03-24 16:07 57
		OutlineHandler(const OutlineHandler& orig) = delete;
55ea55dd sago007 2018-03-24 16:07 58
		OutlineHandler& operator=(const OutlineHandler& base) = delete;
55ea55dd sago007 2018-03-24 16:07 59
	};
55ea55dd sago007 2018-03-24 16:07 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
};
55ea55dd sago007 2018-03-24 16:07 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
d91e7363 sago007 2018-03-26 13:09 86
SagoTextField& SagoTextField::operator=(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;
906183f8 sago007 2018-03-26 13:14 96
	} catch (...) {
906183f8 sago007 2018-03-26 13:14 97
		delete data;
906183f8 sago007 2018-03-26 13:14 98
		throw;
906183f8 sago007 2018-03-26 13:14 99
	}
d91e7363 sago007 2018-03-26 13:09 100
}
d91e7363 sago007 2018-03-26 13:09 101
55ea55dd sago007 2018-03-24 16:07 102
SagoTextField::~SagoTextField() {
55ea55dd sago007 2018-03-24 16:07 103
	if(!data) {
55ea55dd sago007 2018-03-24 16:07 104
		return;
55ea55dd sago007 2018-03-24 16:07 105
	}
55ea55dd sago007 2018-03-24 16:07 106
	ClearCache();
55ea55dd sago007 2018-03-24 16:07 107
	delete data;
55ea55dd sago007 2018-03-24 16:07 108
}
55ea55dd sago007 2018-03-24 16:07 109
1a09fcd5 sago007 2018-03-25 13:32 110
void SagoTextField::SetHolder(const SagoDataHolder* holder) {
55ea55dd sago007 2018-03-24 16:07 111
	data->tex = holder;
55ea55dd sago007 2018-03-24 16:07 112
}
55ea55dd sago007 2018-03-24 16:07 113
55ea55dd sago007 2018-03-24 16:07 114
void SagoTextField::SetText(const char* text) {
55ea55dd sago007 2018-03-24 16:07 115
	data->text = text;
55ea55dd sago007 2018-03-24 16:07 116
}
55ea55dd sago007 2018-03-24 16:07 117
55ea55dd sago007 2018-03-24 16:07 118
void SagoTextField::SetColor(const SDL_Color& color) {
55ea55dd sago007 2018-03-24 16:07 119
	data->color = color;
55ea55dd sago007 2018-03-24 16:07 120
}
55ea55dd sago007 2018-03-24 16:07 121
55ea55dd sago007 2018-03-24 16:07 122
void SagoTextField::SetFont(const char* fontName) {
55ea55dd sago007 2018-03-24 16:07 123
	data->fontName = fontName;
55ea55dd sago007 2018-03-24 16:07 124
}
55ea55dd sago007 2018-03-24 16:07 125
55ea55dd sago007 2018-03-24 16:07 126
void SagoTextField::SetFontSize(int fontSize) {
55ea55dd sago007 2018-03-24 16:07 127
	data->fontSize = fontSize;
55ea55dd sago007 2018-03-24 16:07 128
}
55ea55dd sago007 2018-03-24 16:07 129
55ea55dd sago007 2018-03-24 16:07 130
void SagoTextField::SetOutline(int outlineSize, const SDL_Color& color) {
55ea55dd sago007 2018-03-24 16:07 131
	data->outline = outlineSize;
55ea55dd sago007 2018-03-24 16:07 132
	data->outlineColor = color;
55ea55dd sago007 2018-03-24 16:07 133
}
55ea55dd sago007 2018-03-24 16:07 134
55ea55dd sago007 2018-03-24 16:07 135
const std::string& SagoTextField::GetText() const {
55ea55dd sago007 2018-03-24 16:07 136
	return data->text;
55ea55dd sago007 2018-03-24 16:07 137
}
55ea55dd sago007 2018-03-24 16:07 138
55ea55dd sago007 2018-03-24 16:07 139
void SagoTextField::ClearCache() {
55ea55dd sago007 2018-03-24 16:07 140
	if (data->texture) {
55ea55dd sago007 2018-03-24 16:07 141
		SDL_DestroyTexture(data->texture);
55ea55dd sago007 2018-03-24 16:07 142
		data->texture = nullptr;
55ea55dd sago007 2018-03-24 16:07 143
	}
55ea55dd sago007 2018-03-24 16:07 144
	if (data->textSurface) {
55ea55dd sago007 2018-03-24 16:07 145
		SDL_FreeSurface(data->textSurface);
55ea55dd sago007 2018-03-24 16:07 146
		data->textSurface = nullptr;
55ea55dd sago007 2018-03-24 16:07 147
	}
55ea55dd sago007 2018-03-24 16:07 148
	if (data->outlineTexture) {
55ea55dd sago007 2018-03-24 16:07 149
		SDL_DestroyTexture(data->outlineTexture);
55ea55dd sago007 2018-03-24 16:07 150
		data->outlineTexture = nullptr;
55ea55dd sago007 2018-03-24 16:07 151
	}
55ea55dd sago007 2018-03-24 16:07 152
	if (data->outlineTextSurface) {
55ea55dd sago007 2018-03-24 16:07 153
		SDL_FreeSurface(data->outlineTextSurface);
55ea55dd sago007 2018-03-24 16:07 154
		data->outlineTextSurface = nullptr;
55ea55dd sago007 2018-03-24 16:07 155
	}
55ea55dd sago007 2018-03-24 16:07 156
}
55ea55dd sago007 2018-03-24 16:07 157
55ea55dd sago007 2018-03-24 16:07 158
void SagoTextField::UpdateCache(SDL_Renderer* target) {
343fbe43 sago007 2018-03-27 19:53 159
	if (!data->tex) {
343fbe43 sago007 2018-03-27 19:53 160
		std::cerr << "FATAL: DataHolder not set!\n";
343fbe43 sago007 2018-03-27 19:53 161
		abort();
343fbe43 sago007 2018-03-27 19:53 162
	}
55ea55dd sago007 2018-03-24 16:07 163
	ClearCache();
55ea55dd sago007 2018-03-24 16:07 164
	TTF_Font *font = data->tex->getFontPtr(data->fontName, data->fontSize);
55ea55dd sago007 2018-03-24 16:07 165
	data->textSurface = TTF_RenderUTF8_Blended (font, data->text.c_str(), data->color);
55ea55dd sago007 2018-03-24 16:07 166
	data->texture = SDL_CreateTextureFromSurface(target, data->textSurface);
55ea55dd sago007 2018-03-24 16:07 167
	int textWidth = 0;
55ea55dd sago007 2018-03-24 16:07 168
	SDL_QueryTexture(data->texture, NULL, NULL, &textWidth, NULL);
55ea55dd sago007 2018-03-24 16:07 169
	if (data->outline > 0) {
55ea55dd sago007 2018-03-24 16:07 170
		OutlineHandler oh(font, data->outline);
55ea55dd sago007 2018-03-24 16:07 171
		data->outlineTextSurface = TTF_RenderUTF8_Blended (font, data->text.c_str(), data->outlineColor);
55ea55dd sago007 2018-03-24 16:07 172
		data->outlineTexture = SDL_CreateTextureFromSurface(target, data->outlineTextSurface);
55ea55dd sago007 2018-03-24 16:07 173
		oh.reset();
55ea55dd sago007 2018-03-24 16:07 174
	}
55ea55dd sago007 2018-03-24 16:07 175
	data->renderedText = data->text;
55ea55dd sago007 2018-03-24 16:07 176
	data->renderedVersion = data->tex->getVersion();
55ea55dd sago007 2018-03-24 16:07 177
}
55ea55dd sago007 2018-03-24 16:07 178
d91e7363 sago007 2018-03-26 13:09 179
void SagoTextField::Draw(SDL_Renderer* target, int x, int y, Alignment alignment, VerticalAlignment verticalAlignment) {
55ea55dd sago007 2018-03-24 16:07 180
	if (data->text.empty()) {
55ea55dd sago007 2018-03-24 16:07 181
		return;
55ea55dd sago007 2018-03-24 16:07 182
	}
55ea55dd sago007 2018-03-24 16:07 183
	if (data->text != data->renderedText || data->renderedVersion != data->tex->getVersion()) {
55ea55dd sago007 2018-03-24 16:07 184
		UpdateCache(target);
55ea55dd sago007 2018-03-24 16:07 185
	}
55ea55dd sago007 2018-03-24 16:07 186
	if (!data->texture) {
55ea55dd sago007 2018-03-24 16:07 187
		return;
55ea55dd sago007 2018-03-24 16:07 188
	}
55ea55dd sago007 2018-03-24 16:07 189
	int texW = 0;
55ea55dd sago007 2018-03-24 16:07 190
	int texH = 0;
55ea55dd sago007 2018-03-24 16:07 191
	SDL_QueryTexture(data->texture, NULL, NULL, &texW, &texH);
d91e7363 sago007 2018-03-26 13:09 192
	if (alignment == Alignment::center) {
d91e7363 sago007 2018-03-26 13:09 193
		x -= texW/2;
d91e7363 sago007 2018-03-26 13:09 194
	}
d91e7363 sago007 2018-03-26 13:09 195
	if (verticalAlignment == VerticalAlignment::center) {
d91e7363 sago007 2018-03-26 13:09 196
		y -= texH/2;
d91e7363 sago007 2018-03-26 13:09 197
	}
55ea55dd sago007 2018-03-24 16:07 198
	SDL_Rect dstrect = { x, y, texW, texH };
55ea55dd sago007 2018-03-24 16:07 199
	if (data->outlineTexture) {
55ea55dd sago007 2018-03-24 16:07 200
		int outlineTexW = 0;
55ea55dd sago007 2018-03-24 16:07 201
		int outlineTexH = 0;
55ea55dd sago007 2018-03-24 16:07 202
		SDL_QueryTexture(data->outlineTexture, NULL, NULL, &outlineTexW, &outlineTexH);
55ea55dd sago007 2018-03-24 16:07 203
		SDL_Rect dstrectOutline = { x-(data->outline), y-(data->outline), outlineTexW, outlineTexH };
55ea55dd sago007 2018-03-24 16:07 204
		SDL_RenderCopy(target, data->outlineTexture, NULL, &dstrectOutline);
55ea55dd sago007 2018-03-24 16:07 205
	}
55ea55dd sago007 2018-03-24 16:07 206
	SDL_RenderCopy(target, data->texture, NULL, &dstrect);
55ea55dd sago007 2018-03-24 16:07 207
}
55ea55dd sago007 2018-03-24 16:07 208
55ea55dd sago007 2018-03-24 16:07 209
}  //namespace sago