1 #include "ArrayTexture.hpp"
5 #include "Viewport.hpp"
7 #include "../app/init.hpp"
17 Font::Font(const char *src, int size, long index)
18 : handle(TTF_OpenFontIndex(src, size, index)) {
20 throw std::runtime_error(TTF_GetError());
26 TTF_CloseFont(handle);
30 Font::Font(Font &&other) noexcept
31 : handle(other.handle) {
32 other.handle = nullptr;
35 Font &Font::operator =(Font &&other) noexcept {
36 std::swap(handle, other.handle);
41 int Font::Style() const noexcept {
42 return TTF_GetFontStyle(handle);
45 void Font::Style(int s) const noexcept {
46 TTF_SetFontStyle(handle, s);
49 int Font::Outline() const noexcept {
50 return TTF_GetFontOutline(handle);
53 void Font::Outline(int px) noexcept {
54 TTF_SetFontOutline(handle, px);
58 int Font::Hinting() const noexcept {
59 return TTF_GetFontHinting(handle);
62 void Font::Hinting(int h) const noexcept {
63 TTF_SetFontHinting(handle, h);
66 bool Font::Kerning() const noexcept {
67 return TTF_GetFontKerning(handle);
70 void Font::Kerning(bool b) noexcept {
71 TTF_SetFontKerning(handle, b);
75 int Font::Height() const noexcept {
76 return TTF_FontHeight(handle);
79 int Font::Ascent() const noexcept {
80 return TTF_FontAscent(handle);
83 int Font::Descent() const noexcept {
84 return TTF_FontDescent(handle);
87 int Font::LineSkip() const noexcept {
88 return TTF_FontLineSkip(handle);
92 const char *Font::FamilyName() const noexcept {
93 return TTF_FontFaceFamilyName(handle);
96 const char *Font::StyleName() const noexcept {
97 return TTF_FontFaceStyleName(handle);
101 bool Font::HasGlyph(Uint16 c) const noexcept {
102 return TTF_GlyphIsProvided(handle, c);
106 glm::ivec2 Font::TextSize(const char *text) const {
108 if (TTF_SizeUTF8(handle, text, &size.x, &size.y) != 0) {
109 throw std::runtime_error(TTF_GetError());
114 Texture Font::Render(const char *text) const {
120 void Font::Render(const char *text, Texture &tex) const {
121 SDL_Surface *srf = TTF_RenderUTF8_Blended(handle, text, { 0xFF, 0xFF, 0xFF, 0xFF });
123 throw std::runtime_error(TTF_GetError());
126 tex.Data(*srf, false);
128 SDL_FreeSurface(srf);
133 , type(GL_UNSIGNED_INT_8_8_8_8_REV)
134 , internal(GL_RGBA8) {
135 sdl_format.format = SDL_PIXELFORMAT_ARGB8888;
136 sdl_format.palette = nullptr;
137 sdl_format.BitsPerPixel = 32;
138 sdl_format.BytesPerPixel = 4;
139 sdl_format.Rmask = 0x00FF0000;
140 sdl_format.Gmask = 0x0000FF00;
141 sdl_format.Bmask = 0x000000FF;
142 sdl_format.Amask = 0xFF000000;
143 sdl_format.Rloss = 0;
144 sdl_format.Gloss = 0;
145 sdl_format.Bloss = 0;
146 sdl_format.Aloss = 0;
147 sdl_format.Rshift = 16;
148 sdl_format.Gshift = 8;
149 sdl_format.Bshift = 0;
150 sdl_format.Ashift = 24;
151 sdl_format.refcount = 1;
152 sdl_format.next = nullptr;
155 Format::Format(const SDL_PixelFormat &fmt)
157 if (fmt.BytesPerPixel == 4) {
158 if (fmt.Amask == 0xFF) {
159 if (fmt.Rmask == 0xFF00) {
164 type = GL_UNSIGNED_INT_8_8_8_8;
166 if (fmt.Rmask == 0xFF) {
171 type = GL_UNSIGNED_INT_8_8_8_8_REV;
175 if (fmt.Rmask == 0xFF) {
180 type = GL_UNSIGNED_BYTE;
185 bool Format::Compatible(const Format &other) const noexcept {
186 return format == other.format && type == other.type && internal == other.internal;
194 glGenTextures(1, &handle);
197 Texture::~Texture() {
199 glDeleteTextures(1, &handle);
203 Texture::Texture(Texture &&other) noexcept
204 : handle(other.handle) {
207 height = other.height;
210 Texture &Texture::operator =(Texture &&other) noexcept {
211 std::swap(handle, other.handle);
213 height = other.height;
218 void Texture::Bind() noexcept {
219 glBindTexture(GL_TEXTURE_2D, handle);
223 bool ispow2(unsigned int i) {
224 // don't care about i == 0 here
225 return !(i & (i - 1));
229 void Texture::Data(const SDL_Surface &srf, bool pad2) noexcept {
230 Format format(*srf.format);
232 if (!pad2 || (ispow2(srf.w) && ispow2(srf.h))) {
233 int align = UnpackAlignmentFromPitch(srf.pitch);
235 int pitch = (srf.w * srf.format->BytesPerPixel + align - 1) / align * align;
236 if (srf.pitch - pitch >= align) {
237 UnpackRowLength(srf.pitch / srf.format->BytesPerPixel);
242 Data(srf.w, srf.h, format, srf.pixels);
245 } else if (srf.w > (1 << 30) || srf.h > (1 << 30)) {
247 throw std::runtime_error("texture too large");
250 GLsizei width = 1, height = 1;
251 while (width < srf.w) {
254 while (height < srf.h) {
257 size_t pitch = width * srf.format->BytesPerPixel;
258 size_t size = pitch * height;
259 size_t row_pad = pitch - srf.pitch;
260 std::unique_ptr<unsigned char[]> data(new unsigned char[size]);
261 unsigned char *src = reinterpret_cast<unsigned char *>(srf.pixels);
262 unsigned char *dst = data.get();
263 for (int row = 0; row < srf.h; ++row) {
264 std::memcpy(dst, src, srf.pitch);
267 std::memset(dst, 0, row_pad);
270 std::memset(dst, 0, (height - srf.h) * pitch);
271 UnpackAlignmentFromPitch(pitch);
272 Data(width, height, format, data.get());
278 void Texture::Data(GLsizei w, GLsizei h, const Format &format, GLvoid *data) noexcept {
284 format.format, format.type,
292 void Texture::FilterNearest() noexcept {
293 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
294 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
297 void Texture::FilterLinear() noexcept {
298 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
299 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
302 void Texture::FilterTrilinear() noexcept {
303 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
304 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
305 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
306 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
307 glGenerateMipmap(GL_TEXTURE_2D);
311 void Texture::UnpackAlignment(GLint i) noexcept {
312 glPixelStorei(GL_UNPACK_ALIGNMENT, i);
315 int Texture::UnpackAlignmentFromPitch(int pitch) noexcept {
317 while (pitch % align) {
320 UnpackAlignment(align);
324 void Texture::UnpackRowLength(GLint i) noexcept {
325 glPixelStorei(GL_UNPACK_ROW_LENGTH, i);
329 ArrayTexture::ArrayTexture()
334 glGenTextures(1, &handle);
337 ArrayTexture::~ArrayTexture() {
339 glDeleteTextures(1, &handle);
343 ArrayTexture::ArrayTexture(ArrayTexture &&other) noexcept
344 : handle(other.handle) {
347 height = other.height;
351 ArrayTexture &ArrayTexture::operator =(ArrayTexture &&other) noexcept {
352 std::swap(handle, other.handle);
354 height = other.height;
360 void ArrayTexture::Bind() noexcept {
361 glBindTexture(GL_TEXTURE_2D_ARRAY, handle);
365 void ArrayTexture::Reserve(GLsizei w, GLsizei h, GLsizei d, const Format &f) noexcept {
367 GL_TEXTURE_2D_ARRAY, // which
369 f.internal, // format
379 void ArrayTexture::Data(GLsizei l, const SDL_Surface &srf) {
380 Format fmt(*srf.format);
381 if (format.Compatible(fmt)) {
382 Data(l, fmt, srf.pixels);
384 SDL_Surface *converted = SDL_ConvertSurface(
385 const_cast<SDL_Surface *>(&srf),
390 throw SDLError("SDL_ConvertSurface");
392 Format new_fmt(*converted->format);
393 if (!format.Compatible(new_fmt)) {
394 SDL_FreeSurface(converted);
395 throw std::runtime_error("unable to convert texture input");
397 Data(l, new_fmt, converted->pixels);
398 SDL_FreeSurface(converted);
402 void ArrayTexture::Data(GLsizei l, const Format &f, GLvoid *data) noexcept {
404 GL_TEXTURE_2D_ARRAY, // which
406 0, 0, // dest X and Y offset
416 void ArrayTexture::FilterNearest() noexcept {
417 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
418 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
421 void ArrayTexture::FilterLinear() noexcept {
422 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
423 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
426 void ArrayTexture::FilterTrilinear() noexcept {
427 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
428 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
429 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
430 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
431 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);