1 #include "BlendedSprite.hpp"
6 #include "Viewport.hpp"
16 Font::Font(const char *src, int size, long index)
17 : handle(TTF_OpenFontIndex(src, size, index)) {
19 throw std::runtime_error(TTF_GetError());
25 TTF_CloseFont(handle);
29 Font::Font(Font &&other) noexcept
30 : handle(other.handle) {
31 other.handle = nullptr;
34 Font &Font::operator =(Font &&other) noexcept {
35 std::swap(handle, other.handle);
40 int Font::Style() const noexcept {
41 return TTF_GetFontStyle(handle);
44 void Font::Style(int s) const noexcept {
45 TTF_SetFontStyle(handle, s);
48 int Font::Outline() const noexcept {
49 return TTF_GetFontOutline(handle);
52 void Font::Outline(int px) noexcept {
53 TTF_SetFontOutline(handle, px);
57 int Font::Hinting() const noexcept {
58 return TTF_GetFontHinting(handle);
61 void Font::Hinting(int h) const noexcept {
62 TTF_SetFontHinting(handle, h);
65 bool Font::Kerning() const noexcept {
66 return TTF_GetFontKerning(handle);
69 void Font::Kerning(bool b) noexcept {
70 TTF_SetFontKerning(handle, b);
74 int Font::Height() const noexcept {
75 return TTF_FontHeight(handle);
78 int Font::Ascent() const noexcept {
79 return TTF_FontAscent(handle);
82 int Font::Descent() const noexcept {
83 return TTF_FontDescent(handle);
86 int Font::LineSkip() const noexcept {
87 return TTF_FontLineSkip(handle);
91 const char *Font::FamilyName() const noexcept {
92 return TTF_FontFaceFamilyName(handle);
95 const char *Font::StyleName() const noexcept {
96 return TTF_FontFaceStyleName(handle);
100 bool Font::HasGlyph(Uint16 c) const noexcept {
101 return TTF_GlyphIsProvided(handle, c);
105 glm::tvec2<int> Font::TextSize(const char *text) const {
106 glm::tvec2<int> size;
107 if (TTF_SizeUTF8(handle, text, &size.x, &size.y) != 0) {
108 throw std::runtime_error(TTF_GetError());
113 Texture Font::Render(const char *text) const {
119 void Font::Render(const char *text, Texture &tex) const {
120 SDL_Surface *srf = TTF_RenderUTF8_Blended(handle, text, { 0xFF, 0xFF, 0xFF, 0xFF });
122 throw std::runtime_error(TTF_GetError());
125 tex.Data(*srf, false);
127 SDL_FreeSurface(srf);
131 void Format::ReadPixelFormat(const SDL_PixelFormat &fmt) {
132 if (fmt.BytesPerPixel == 4) {
133 if (fmt.Amask == 0xFF) {
134 if (fmt.Rmask == 0xFF00) {
139 type = GL_UNSIGNED_INT_8_8_8_8;
141 if (fmt.Rmask == 0xFF) {
146 type = GL_UNSIGNED_INT_8_8_8_8_REV;
150 if (fmt.Rmask == 0xFF) {
155 type = GL_UNSIGNED_BYTE;
161 Text::Text() noexcept
164 , bg(1.0f, 1.0f, 1.0f, 0.0f)
165 , fg(1.0f, 1.0f, 1.0f, 1.0f)
168 , grav(Gravity::NORTH_WEST)
169 , pivot(Gravity::NORTH_WEST)
175 void Text::Set(const Font &font, const char *text) {
176 font.Render(text, tex);
177 size = font.TextSize(text);
181 void Text::Update() {
182 sprite.LoadRect(size.x, size.y, align(pivot, size));
186 void Text::Render(Viewport &viewport) noexcept {
190 BlendedSprite &prog = viewport.SpriteProgram();
191 viewport.SetCursor(pos, grav);
192 prog.SetM(viewport.Cursor());
193 prog.SetTexture(tex);
204 glGenTextures(1, &handle);
207 Texture::~Texture() {
209 glDeleteTextures(1, &handle);
213 Texture::Texture(Texture &&other) noexcept
214 : handle(other.handle) {
217 height = other.height;
220 Texture &Texture::operator =(Texture &&other) noexcept {
221 std::swap(handle, other.handle);
223 height = other.height;
228 void Texture::Bind() noexcept {
229 glBindTexture(GL_TEXTURE_2D, handle);
233 bool ispow2(unsigned int i) {
234 // don't care about i == 0 here
235 return !(i & (i - 1));
239 void Texture::Data(const SDL_Surface &srf, bool pad2) noexcept {
241 format.ReadPixelFormat(*srf.format);
243 if (!pad2 || (ispow2(srf.w) && ispow2(srf.h))) {
244 int align = UnpackAlignmentFromPitch(srf.pitch);
246 int pitch = (srf.w * srf.format->BytesPerPixel + align - 1) / align * align;
247 if (srf.pitch - pitch >= align) {
248 UnpackRowLength(srf.pitch / srf.format->BytesPerPixel);
253 Data(srf.w, srf.h, format, srf.pixels);
256 } else if (srf.w > (1 << 30) || srf.h > (1 << 30)) {
258 throw std::runtime_error("texture too large");
261 GLsizei width = 1, height = 1;
262 while (width < srf.w) {
265 while (height < srf.h) {
268 size_t pitch = width * srf.format->BytesPerPixel;
269 size_t size = pitch * height;
270 size_t row_pad = pitch - srf.pitch;
271 std::unique_ptr<unsigned char[]> data(new unsigned char[size]);
272 unsigned char *src = reinterpret_cast<unsigned char *>(srf.pixels);
273 unsigned char *dst = data.get();
274 for (int row = 0; row < srf.h; ++row) {
275 std::memcpy(dst, src, srf.pitch);
278 std::memset(dst, 0, row_pad);
281 std::memset(dst, 0, (height - srf.h) * pitch);
282 UnpackAlignmentFromPitch(pitch);
283 Data(width, height, format, data.get());
289 void Texture::Data(GLsizei w, GLsizei h, const Format &format, GLvoid *data) noexcept {
295 format.format, format.type,
303 void Texture::FilterNearest() noexcept {
304 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
305 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
308 void Texture::FilterLinear() noexcept {
309 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
310 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
313 void Texture::FilterTrilinear() noexcept {
314 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
316 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
318 glGenerateMipmap(GL_TEXTURE_2D);
322 void Texture::UnpackAlignment(GLint i) noexcept {
323 glPixelStorei(GL_UNPACK_ALIGNMENT, i);
326 int Texture::UnpackAlignmentFromPitch(int pitch) noexcept {
328 while (pitch % align) {
331 UnpackAlignment(align);
335 void Texture::UnpackRowLength(GLint i) noexcept {
336 glPixelStorei(GL_UNPACK_ROW_LENGTH, i);