1 #include "ArrayTexture.hpp"
6 #include "TextureBase.hpp"
7 #include "Viewport.hpp"
9 #include "../app/error.hpp"
21 Font::Font(const std::string &src, int size, long index)
22 : Font(src.c_str(), size, index) {
25 Font::Font(const char *src, int size, long index)
26 : handle(TTF_OpenFontIndex(src, size, index)) {
28 throw std::runtime_error(TTF_GetError());
34 TTF_CloseFont(handle);
38 Font::Font(Font &&other) noexcept
39 : handle(other.handle) {
40 other.handle = nullptr;
43 Font &Font::operator =(Font &&other) noexcept {
44 std::swap(handle, other.handle);
49 int Font::Style() const noexcept {
50 return TTF_GetFontStyle(handle);
53 void Font::Style(int s) const noexcept {
54 TTF_SetFontStyle(handle, s);
57 int Font::Outline() const noexcept {
58 return TTF_GetFontOutline(handle);
61 void Font::Outline(int px) noexcept {
62 TTF_SetFontOutline(handle, px);
66 int Font::Hinting() const noexcept {
67 return TTF_GetFontHinting(handle);
70 void Font::Hinting(int h) const noexcept {
71 TTF_SetFontHinting(handle, h);
74 bool Font::Kerning() const noexcept {
75 return TTF_GetFontKerning(handle);
78 void Font::Kerning(bool b) noexcept {
79 TTF_SetFontKerning(handle, b);
83 int Font::Height() const noexcept {
84 return TTF_FontHeight(handle);
87 int Font::Ascent() const noexcept {
88 return TTF_FontAscent(handle);
91 int Font::Descent() const noexcept {
92 return TTF_FontDescent(handle);
95 int Font::LineSkip() const noexcept {
96 return TTF_FontLineSkip(handle);
100 const char *Font::FamilyName() const noexcept {
101 return TTF_FontFaceFamilyName(handle);
104 const char *Font::StyleName() const noexcept {
105 return TTF_FontFaceStyleName(handle);
109 bool Font::HasGlyph(Uint16 c) const noexcept {
110 return TTF_GlyphIsProvided(handle, c);
114 glm::ivec2 Font::TextSize(const char *text) const {
116 if (TTF_SizeUTF8(handle, text, &size.x, &size.y) != 0) {
117 throw std::runtime_error(TTF_GetError());
122 glm::ivec2 Font::TextSize(const std::string &text) const {
123 return TextSize(text.c_str());
126 Texture Font::Render(const char *text) const {
132 Texture Font::Render(const std::string &text) const {
133 return Render(text.c_str());
136 void Font::Render(const char *text, Texture &tex) const {
137 SDL_Surface *srf = TTF_RenderUTF8_Blended(handle, text, { 0xFF, 0xFF, 0xFF, 0xFF });
139 throw std::runtime_error(TTF_GetError());
142 tex.Data(*srf, false);
144 SDL_FreeSurface(srf);
147 void Font::Render(const std::string &text, Texture &tex) const {
148 Render(text.c_str(), tex);
151 Format::Format() noexcept
153 , type(GL_UNSIGNED_INT_8_8_8_8_REV)
154 , internal(GL_RGBA8) {
155 sdl_format.format = SDL_PIXELFORMAT_ARGB8888;
156 sdl_format.palette = nullptr;
157 sdl_format.BitsPerPixel = 32;
158 sdl_format.BytesPerPixel = 4;
159 sdl_format.Rmask = 0x00FF0000;
160 sdl_format.Gmask = 0x0000FF00;
161 sdl_format.Bmask = 0x000000FF;
162 sdl_format.Amask = 0xFF000000;
163 sdl_format.Rloss = 0;
164 sdl_format.Gloss = 0;
165 sdl_format.Bloss = 0;
166 sdl_format.Aloss = 0;
167 sdl_format.Rshift = 16;
168 sdl_format.Gshift = 8;
169 sdl_format.Bshift = 0;
170 sdl_format.Ashift = 24;
171 sdl_format.refcount = 1;
172 sdl_format.next = nullptr;
175 Format::Format(const SDL_PixelFormat &fmt) noexcept
177 if (fmt.BytesPerPixel == 4) {
178 if (fmt.Amask == 0xFF) {
179 if (fmt.Rmask == 0xFF00) {
184 type = GL_UNSIGNED_INT_8_8_8_8;
186 if (fmt.Rmask == 0xFF) {
191 type = GL_UNSIGNED_INT_8_8_8_8_REV;
195 if (fmt.Rmask == 0xFF) {
200 type = GL_UNSIGNED_BYTE;
205 bool Format::Compatible(const Format &other) const noexcept {
206 return format == other.format && type == other.type && internal == other.internal;
210 template<GLenum TARGET, GLsizei COUNT>
211 TextureBase<TARGET, COUNT>::TextureBase() {
212 glGenTextures(COUNT, handle);
215 template<GLenum TARGET, GLsizei COUNT>
216 TextureBase<TARGET, COUNT>::~TextureBase() {
217 glDeleteTextures(COUNT, handle);
220 template<GLenum TARGET, GLsizei COUNT>
221 TextureBase<TARGET, COUNT>::TextureBase(TextureBase &&other) noexcept {
222 std::memcpy(handle, other.handle, sizeof(handle));
223 std::memset(other.handle, 0, sizeof(handle));
226 template<GLenum TARGET, GLsizei COUNT>
227 TextureBase<TARGET, COUNT> &TextureBase<TARGET, COUNT>::operator =(TextureBase &&other) noexcept {
228 std::swap(handle, other.handle);
240 Texture::~Texture() {
244 Texture::Texture(Texture &&other) noexcept
245 : TextureBase(std::move(other)) {
247 height = other.height;
250 Texture &Texture::operator =(Texture &&other) noexcept {
251 TextureBase::operator =(std::move(other));
253 height = other.height;
259 bool ispow2(unsigned int i) {
260 // don't care about i == 0 here
261 return !(i & (i - 1));
265 void Texture::Data(const SDL_Surface &srf, bool pad2) noexcept {
266 Format format(*srf.format);
268 if (!pad2 || (ispow2(srf.w) && ispow2(srf.h))) {
269 int align = UnpackAlignmentFromPitch(srf.pitch);
271 int pitch = (srf.w * srf.format->BytesPerPixel + align - 1) / align * align;
272 if (srf.pitch - pitch >= align) {
273 UnpackRowLength(srf.pitch / srf.format->BytesPerPixel);
278 Data(srf.w, srf.h, format, srf.pixels);
281 } else if (srf.w > (1 << 30) || srf.h > (1 << 30)) {
282 // That's at least one gigapixel in either or both dimensions.
283 // If this is not an error, that's an insanely large or high
284 // resolution texture.
286 std::cerr << "texture size exceeds 2^30, aborting data import" << std::endl;
289 GLsizei width = 1, height = 1;
290 while (width < srf.w) {
293 while (height < srf.h) {
296 size_t pitch = width * srf.format->BytesPerPixel;
297 size_t size = pitch * height;
298 size_t row_pad = pitch - srf.pitch;
299 std::unique_ptr<unsigned char[]> data(new unsigned char[size]);
300 unsigned char *src = reinterpret_cast<unsigned char *>(srf.pixels);
301 unsigned char *dst = data.get();
302 for (int row = 0; row < srf.h; ++row) {
303 std::memcpy(dst, src, srf.pitch);
306 std::memset(dst, 0, row_pad);
309 std::memset(dst, 0, (height - srf.h) * pitch);
310 UnpackAlignmentFromPitch(pitch);
311 Data(width, height, format, data.get());
317 void Texture::Data(GLsizei w, GLsizei h, const Format &format, GLvoid *data) noexcept {
323 format.format, format.type,
331 void Texture::UnpackAlignment(GLint i) noexcept {
332 glPixelStorei(GL_UNPACK_ALIGNMENT, i);
335 int Texture::UnpackAlignmentFromPitch(int pitch) noexcept {
337 while (pitch % align) {
340 UnpackAlignment(align);
344 void Texture::UnpackRowLength(GLint i) noexcept {
345 glPixelStorei(GL_UNPACK_ROW_LENGTH, i);
349 ArrayTexture::ArrayTexture()
357 ArrayTexture::~ArrayTexture() {
361 ArrayTexture::ArrayTexture(ArrayTexture &&other) noexcept
362 : TextureBase(std::move(other)) {
364 height = other.height;
368 ArrayTexture &ArrayTexture::operator =(ArrayTexture &&other) noexcept {
369 TextureBase::operator =(std::move(other));
371 height = other.height;
377 void ArrayTexture::Reserve(GLsizei w, GLsizei h, GLsizei d, const Format &f) noexcept {
379 GL_TEXTURE_2D_ARRAY, // which
381 f.internal, // format
391 void ArrayTexture::Data(GLsizei l, const SDL_Surface &srf) {
392 Format fmt(*srf.format);
393 if (format.Compatible(fmt)) {
394 Data(l, fmt, srf.pixels);
396 SDL_Surface *converted = SDL_ConvertSurface(
397 const_cast<SDL_Surface *>(&srf),
402 throw app::SDLError("SDL_ConvertSurface");
404 Format new_fmt(*converted->format);
405 if (!format.Compatible(new_fmt)) {
406 SDL_FreeSurface(converted);
407 throw std::runtime_error("unable to convert texture input");
409 Data(l, new_fmt, converted->pixels);
410 SDL_FreeSurface(converted);
414 void ArrayTexture::Data(GLsizei l, const Format &f, GLvoid *data) noexcept {
416 GL_TEXTURE_2D_ARRAY, // which
418 0, 0, // dest X and Y offset
433 CubeMap::~CubeMap() {
437 CubeMap::CubeMap(CubeMap &&other) noexcept
438 : TextureBase(std::move(other)) {
442 CubeMap &CubeMap::operator =(CubeMap &&other) noexcept {
443 TextureBase::operator =(std::move(other));
448 void CubeMap::Data(Face f, const SDL_Surface &srf) {
450 Format fmt(*srf.format);
451 if (format.Compatible(fmt)) {
452 Data(f, srf.w, srf.h, fmt, srf.pixels);
454 SDL_Surface *converted = SDL_ConvertSurface(
455 const_cast<SDL_Surface *>(&srf),
460 throw app::SDLError("SDL_ConvertSurface");
462 Format new_fmt(*converted->format);
463 if (!format.Compatible(new_fmt)) {
464 SDL_FreeSurface(converted);
465 throw std::runtime_error("unable to convert texture input");
467 Data(f, converted->w, converted->h, new_fmt, converted->pixels);
468 SDL_FreeSurface(converted);
472 void CubeMap::Data(Face face, GLsizei w, GLsizei h, const Format &f, GLvoid *data) noexcept {
476 f.internal, // internal format
479 f.format, f.type, // pixel format