1 #include "BlendedSprite.hpp"
2 #include "FixedText.hpp"
5 #include "MessageBox.hpp"
8 #include "Viewport.hpp"
18 Font::Font(const char *src, int size, long index)
19 : handle(TTF_OpenFontIndex(src, size, index)) {
21 throw std::runtime_error(TTF_GetError());
27 TTF_CloseFont(handle);
31 Font::Font(Font &&other) noexcept
32 : handle(other.handle) {
33 other.handle = nullptr;
36 Font &Font::operator =(Font &&other) noexcept {
37 std::swap(handle, other.handle);
42 int Font::Style() const noexcept {
43 return TTF_GetFontStyle(handle);
46 void Font::Style(int s) const noexcept {
47 TTF_SetFontStyle(handle, s);
50 int Font::Outline() const noexcept {
51 return TTF_GetFontOutline(handle);
54 void Font::Outline(int px) noexcept {
55 TTF_SetFontOutline(handle, px);
59 int Font::Hinting() const noexcept {
60 return TTF_GetFontHinting(handle);
63 void Font::Hinting(int h) const noexcept {
64 TTF_SetFontHinting(handle, h);
67 bool Font::Kerning() const noexcept {
68 return TTF_GetFontKerning(handle);
71 void Font::Kerning(bool b) noexcept {
72 TTF_SetFontKerning(handle, b);
76 int Font::Height() const noexcept {
77 return TTF_FontHeight(handle);
80 int Font::Ascent() const noexcept {
81 return TTF_FontAscent(handle);
84 int Font::Descent() const noexcept {
85 return TTF_FontDescent(handle);
88 int Font::LineSkip() const noexcept {
89 return TTF_FontLineSkip(handle);
93 const char *Font::FamilyName() const noexcept {
94 return TTF_FontFaceFamilyName(handle);
97 const char *Font::StyleName() const noexcept {
98 return TTF_FontFaceStyleName(handle);
102 bool Font::HasGlyph(Uint16 c) const noexcept {
103 return TTF_GlyphIsProvided(handle, c);
107 glm::tvec2<int> Font::TextSize(const char *text) const {
108 glm::tvec2<int> size;
109 if (TTF_SizeUTF8(handle, text, &size.x, &size.y) != 0) {
110 throw std::runtime_error(TTF_GetError());
115 Texture Font::Render(const char *text) const {
121 void Font::Render(const char *text, Texture &tex) const {
122 SDL_Surface *srf = TTF_RenderUTF8_Blended(handle, text, { 0xFF, 0xFF, 0xFF, 0xFF });
124 throw std::runtime_error(TTF_GetError());
127 tex.Data(*srf, false);
129 SDL_FreeSurface(srf);
133 void Format::ReadPixelFormat(const SDL_PixelFormat &fmt) {
134 if (fmt.BytesPerPixel == 4) {
135 if (fmt.Amask == 0xFF) {
136 if (fmt.Rmask == 0xFF00) {
141 type = GL_UNSIGNED_INT_8_8_8_8;
143 if (fmt.Rmask == 0xFF) {
148 type = GL_UNSIGNED_INT_8_8_8_8_REV;
152 if (fmt.Rmask == 0xFF) {
157 type = GL_UNSIGNED_BYTE;
163 MessageBox::MessageBox(const Font &f)
168 , adv(0.0f, font.LineSkip(), 0.0f)
169 , bg(1.0f, 1.0f, 1.0f, 0.0f)
170 , fg(1.0f, 1.0f, 1.0f, 1.0f)
171 , grav(Gravity::NORTH_WEST) {
175 void MessageBox::Position(const glm::vec3 &p, Gravity g) noexcept {
178 if (get_y(g) == Align::END) {
179 adv.y = -font.LineSkip();
181 adv.y = font.LineSkip();
183 for (Text &txt : lines) {
188 void MessageBox::PushLine(const char *text) {
189 lines.emplace_front();
190 Text &txt = lines.front();
194 while (lines.size() > max_lines) {
199 void MessageBox::Render(Viewport &viewport) noexcept {
200 BlendedSprite &prog = viewport.SpriteProgram();
203 viewport.SetCursor(pos, grav);
204 for (Text &txt : lines) {
205 prog.SetM(viewport.Cursor());
206 txt.Render(viewport);
207 viewport.MoveCursor(adv);
212 Text::Text() noexcept
216 , pivot(Gravity::NORTH_WEST)
221 FixedText::FixedText() noexcept
223 , bg(1.0f, 1.0f, 1.0f, 0.0f)
224 , fg(1.0f, 1.0f, 1.0f, 1.0f)
226 , grav(Gravity::NORTH_WEST)
231 void Text::Set(const Font &font, const char *text) {
232 font.Render(text, tex);
233 size = font.TextSize(text);
237 void Text::Update() {
238 sprite.LoadRect(size.x, size.y, align(pivot, size));
242 void FixedText::Render(Viewport &viewport) noexcept {
243 BlendedSprite &prog = viewport.SpriteProgram();
244 viewport.SetCursor(pos, grav);
245 prog.SetM(viewport.Cursor());
248 Text::Render(viewport);
251 void Text::Render(Viewport &viewport) noexcept {
255 BlendedSprite &prog = viewport.SpriteProgram();
256 prog.SetTexture(tex);
265 glGenTextures(1, &handle);
268 Texture::~Texture() {
270 glDeleteTextures(1, &handle);
274 Texture::Texture(Texture &&other) noexcept
275 : handle(other.handle) {
278 height = other.height;
281 Texture &Texture::operator =(Texture &&other) noexcept {
282 std::swap(handle, other.handle);
284 height = other.height;
289 void Texture::Bind() noexcept {
290 glBindTexture(GL_TEXTURE_2D, handle);
294 bool ispow2(unsigned int i) {
295 // don't care about i == 0 here
296 return !(i & (i - 1));
300 void Texture::Data(const SDL_Surface &srf, bool pad2) noexcept {
302 format.ReadPixelFormat(*srf.format);
304 if (!pad2 || (ispow2(srf.w) && ispow2(srf.h))) {
305 int align = UnpackAlignmentFromPitch(srf.pitch);
307 int pitch = (srf.w * srf.format->BytesPerPixel + align - 1) / align * align;
308 if (srf.pitch - pitch >= align) {
309 UnpackRowLength(srf.pitch / srf.format->BytesPerPixel);
314 Data(srf.w, srf.h, format, srf.pixels);
317 } else if (srf.w > (1 << 30) || srf.h > (1 << 30)) {
319 throw std::runtime_error("texture too large");
322 GLsizei width = 1, height = 1;
323 while (width < srf.w) {
326 while (height < srf.h) {
329 size_t pitch = width * srf.format->BytesPerPixel;
330 size_t size = pitch * height;
331 size_t row_pad = pitch - srf.pitch;
332 std::unique_ptr<unsigned char[]> data(new unsigned char[size]);
333 unsigned char *src = reinterpret_cast<unsigned char *>(srf.pixels);
334 unsigned char *dst = data.get();
335 for (int row = 0; row < srf.h; ++row) {
336 std::memcpy(dst, src, srf.pitch);
339 std::memset(dst, 0, row_pad);
342 std::memset(dst, 0, (height - srf.h) * pitch);
343 UnpackAlignmentFromPitch(pitch);
344 Data(width, height, format, data.get());
350 void Texture::Data(GLsizei w, GLsizei h, const Format &format, GLvoid *data) noexcept {
356 format.format, format.type,
364 void Texture::FilterNearest() noexcept {
365 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
369 void Texture::FilterLinear() noexcept {
370 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
371 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
374 void Texture::FilterTrilinear() noexcept {
375 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
376 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
377 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
378 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
379 glGenerateMipmap(GL_TEXTURE_2D);
383 void Texture::UnpackAlignment(GLint i) noexcept {
384 glPixelStorei(GL_UNPACK_ALIGNMENT, i);
387 int Texture::UnpackAlignmentFromPitch(int pitch) noexcept {
389 while (pitch % align) {
392 UnpackAlignment(align);
396 void Texture::UnpackRowLength(GLint i) noexcept {
397 glPixelStorei(GL_UNPACK_ROW_LENGTH, i);