1 #include "ArrayTexture.hpp"
6 #include "TextureBase.hpp"
7 #include "Viewport.hpp"
9 #include "../app/init.hpp"
19 Font::Font(const char *src, int size, long index)
20 : handle(TTF_OpenFontIndex(src, size, index)) {
22 throw std::runtime_error(TTF_GetError());
28 TTF_CloseFont(handle);
32 Font::Font(Font &&other) noexcept
33 : handle(other.handle) {
34 other.handle = nullptr;
37 Font &Font::operator =(Font &&other) noexcept {
38 std::swap(handle, other.handle);
43 int Font::Style() const noexcept {
44 return TTF_GetFontStyle(handle);
47 void Font::Style(int s) const noexcept {
48 TTF_SetFontStyle(handle, s);
51 int Font::Outline() const noexcept {
52 return TTF_GetFontOutline(handle);
55 void Font::Outline(int px) noexcept {
56 TTF_SetFontOutline(handle, px);
60 int Font::Hinting() const noexcept {
61 return TTF_GetFontHinting(handle);
64 void Font::Hinting(int h) const noexcept {
65 TTF_SetFontHinting(handle, h);
68 bool Font::Kerning() const noexcept {
69 return TTF_GetFontKerning(handle);
72 void Font::Kerning(bool b) noexcept {
73 TTF_SetFontKerning(handle, b);
77 int Font::Height() const noexcept {
78 return TTF_FontHeight(handle);
81 int Font::Ascent() const noexcept {
82 return TTF_FontAscent(handle);
85 int Font::Descent() const noexcept {
86 return TTF_FontDescent(handle);
89 int Font::LineSkip() const noexcept {
90 return TTF_FontLineSkip(handle);
94 const char *Font::FamilyName() const noexcept {
95 return TTF_FontFaceFamilyName(handle);
98 const char *Font::StyleName() const noexcept {
99 return TTF_FontFaceStyleName(handle);
103 bool Font::HasGlyph(Uint16 c) const noexcept {
104 return TTF_GlyphIsProvided(handle, c);
108 glm::ivec2 Font::TextSize(const char *text) const {
110 if (TTF_SizeUTF8(handle, text, &size.x, &size.y) != 0) {
111 throw std::runtime_error(TTF_GetError());
116 Texture Font::Render(const char *text) const {
122 void Font::Render(const char *text, Texture &tex) const {
123 SDL_Surface *srf = TTF_RenderUTF8_Blended(handle, text, { 0xFF, 0xFF, 0xFF, 0xFF });
125 throw std::runtime_error(TTF_GetError());
128 tex.Data(*srf, false);
130 SDL_FreeSurface(srf);
133 Format::Format() noexcept
135 , type(GL_UNSIGNED_INT_8_8_8_8_REV)
136 , internal(GL_RGBA8) {
137 sdl_format.format = SDL_PIXELFORMAT_ARGB8888;
138 sdl_format.palette = nullptr;
139 sdl_format.BitsPerPixel = 32;
140 sdl_format.BytesPerPixel = 4;
141 sdl_format.Rmask = 0x00FF0000;
142 sdl_format.Gmask = 0x0000FF00;
143 sdl_format.Bmask = 0x000000FF;
144 sdl_format.Amask = 0xFF000000;
145 sdl_format.Rloss = 0;
146 sdl_format.Gloss = 0;
147 sdl_format.Bloss = 0;
148 sdl_format.Aloss = 0;
149 sdl_format.Rshift = 16;
150 sdl_format.Gshift = 8;
151 sdl_format.Bshift = 0;
152 sdl_format.Ashift = 24;
153 sdl_format.refcount = 1;
154 sdl_format.next = nullptr;
157 Format::Format(const SDL_PixelFormat &fmt) noexcept
159 if (fmt.BytesPerPixel == 4) {
160 if (fmt.Amask == 0xFF) {
161 if (fmt.Rmask == 0xFF00) {
166 type = GL_UNSIGNED_INT_8_8_8_8;
168 if (fmt.Rmask == 0xFF) {
173 type = GL_UNSIGNED_INT_8_8_8_8_REV;
177 if (fmt.Rmask == 0xFF) {
182 type = GL_UNSIGNED_BYTE;
187 bool Format::Compatible(const Format &other) const noexcept {
188 return format == other.format && type == other.type && internal == other.internal;
192 template<GLenum TARGET, GLsizei COUNT>
193 TextureBase<TARGET, COUNT>::TextureBase() {
194 glGenTextures(COUNT, handle);
197 template<GLenum TARGET, GLsizei COUNT>
198 TextureBase<TARGET, COUNT>::~TextureBase() {
199 glDeleteTextures(COUNT, handle);
202 template<GLenum TARGET, GLsizei COUNT>
203 TextureBase<TARGET, COUNT>::TextureBase(TextureBase &&other) noexcept {
204 std::memcpy(handle, other.handle, sizeof(handle));
205 std::memset(other.handle, 0, sizeof(handle));
208 template<GLenum TARGET, GLsizei COUNT>
209 TextureBase<TARGET, COUNT> &TextureBase<TARGET, COUNT>::operator =(TextureBase &&other) noexcept {
210 std::swap(handle, other.handle);
222 Texture::~Texture() {
226 Texture::Texture(Texture &&other) noexcept
227 : TextureBase(std::move(other)) {
229 height = other.height;
232 Texture &Texture::operator =(Texture &&other) noexcept {
233 TextureBase::operator =(std::move(other));
235 height = other.height;
241 bool ispow2(unsigned int i) {
242 // don't care about i == 0 here
243 return !(i & (i - 1));
247 void Texture::Data(const SDL_Surface &srf, bool pad2) noexcept {
248 Format format(*srf.format);
250 if (!pad2 || (ispow2(srf.w) && ispow2(srf.h))) {
251 int align = UnpackAlignmentFromPitch(srf.pitch);
253 int pitch = (srf.w * srf.format->BytesPerPixel + align - 1) / align * align;
254 if (srf.pitch - pitch >= align) {
255 UnpackRowLength(srf.pitch / srf.format->BytesPerPixel);
260 Data(srf.w, srf.h, format, srf.pixels);
263 } else if (srf.w > (1 << 30) || srf.h > (1 << 30)) {
265 throw std::runtime_error("texture too large");
268 GLsizei width = 1, height = 1;
269 while (width < srf.w) {
272 while (height < srf.h) {
275 size_t pitch = width * srf.format->BytesPerPixel;
276 size_t size = pitch * height;
277 size_t row_pad = pitch - srf.pitch;
278 std::unique_ptr<unsigned char[]> data(new unsigned char[size]);
279 unsigned char *src = reinterpret_cast<unsigned char *>(srf.pixels);
280 unsigned char *dst = data.get();
281 for (int row = 0; row < srf.h; ++row) {
282 std::memcpy(dst, src, srf.pitch);
285 std::memset(dst, 0, row_pad);
288 std::memset(dst, 0, (height - srf.h) * pitch);
289 UnpackAlignmentFromPitch(pitch);
290 Data(width, height, format, data.get());
296 void Texture::Data(GLsizei w, GLsizei h, const Format &format, GLvoid *data) noexcept {
302 format.format, format.type,
310 void Texture::UnpackAlignment(GLint i) noexcept {
311 glPixelStorei(GL_UNPACK_ALIGNMENT, i);
314 int Texture::UnpackAlignmentFromPitch(int pitch) noexcept {
316 while (pitch % align) {
319 UnpackAlignment(align);
323 void Texture::UnpackRowLength(GLint i) noexcept {
324 glPixelStorei(GL_UNPACK_ROW_LENGTH, i);
328 ArrayTexture::ArrayTexture()
336 ArrayTexture::~ArrayTexture() {
340 ArrayTexture::ArrayTexture(ArrayTexture &&other) noexcept
341 : TextureBase(std::move(other)) {
343 height = other.height;
347 ArrayTexture &ArrayTexture::operator =(ArrayTexture &&other) noexcept {
348 TextureBase::operator =(std::move(other));
350 height = other.height;
356 void ArrayTexture::Reserve(GLsizei w, GLsizei h, GLsizei d, const Format &f) noexcept {
358 GL_TEXTURE_2D_ARRAY, // which
360 f.internal, // format
370 void ArrayTexture::Data(GLsizei l, const SDL_Surface &srf) {
371 Format fmt(*srf.format);
372 if (format.Compatible(fmt)) {
373 Data(l, fmt, srf.pixels);
375 SDL_Surface *converted = SDL_ConvertSurface(
376 const_cast<SDL_Surface *>(&srf),
381 throw SDLError("SDL_ConvertSurface");
383 Format new_fmt(*converted->format);
384 if (!format.Compatible(new_fmt)) {
385 SDL_FreeSurface(converted);
386 throw std::runtime_error("unable to convert texture input");
388 Data(l, new_fmt, converted->pixels);
389 SDL_FreeSurface(converted);
393 void ArrayTexture::Data(GLsizei l, const Format &f, GLvoid *data) noexcept {
395 GL_TEXTURE_2D_ARRAY, // which
397 0, 0, // dest X and Y offset
412 CubeMap::~CubeMap() {
416 CubeMap::CubeMap(CubeMap &&other) noexcept
417 : TextureBase(std::move(other)) {
421 CubeMap &CubeMap::operator =(CubeMap &&other) noexcept {
422 TextureBase::operator =(std::move(other));
427 void CubeMap::Data(Face f, const SDL_Surface &srf) {
429 Format fmt(*srf.format);
430 if (format.Compatible(fmt)) {
431 Data(f, srf.w, srf.h, fmt, srf.pixels);
433 SDL_Surface *converted = SDL_ConvertSurface(
434 const_cast<SDL_Surface *>(&srf),
439 throw SDLError("SDL_ConvertSurface");
441 Format new_fmt(*converted->format);
442 if (!format.Compatible(new_fmt)) {
443 SDL_FreeSurface(converted);
444 throw std::runtime_error("unable to convert texture input");
446 Data(f, converted->w, converted->h, new_fmt, converted->pixels);
447 SDL_FreeSurface(converted);
451 void CubeMap::Data(Face face, GLsizei w, GLsizei h, const Format &f, GLvoid *data) noexcept {
455 f.internal, // internal format
458 f.format, f.type, // pixel format