13 Font::Font(const char *src, int size, long index)
14 : handle(TTF_OpenFontIndex(src, size, index)) {
16 throw std::runtime_error(TTF_GetError());
22 TTF_CloseFont(handle);
26 Font::Font(Font &&other) noexcept
27 : handle(other.handle) {
28 other.handle = nullptr;
31 Font &Font::operator =(Font &&other) noexcept {
32 std::swap(handle, other.handle);
37 int Font::Style() const noexcept {
38 return TTF_GetFontStyle(handle);
41 void Font::Style(int s) const noexcept {
42 TTF_SetFontStyle(handle, s);
45 int Font::Outline() const noexcept {
46 return TTF_GetFontOutline(handle);
49 void Font::Outline(int px) noexcept {
50 TTF_SetFontOutline(handle, px);
54 int Font::Hinting() const noexcept {
55 return TTF_GetFontHinting(handle);
58 void Font::Hinting(int h) const noexcept {
59 TTF_SetFontHinting(handle, h);
62 bool Font::Kerning() const noexcept {
63 return TTF_GetFontKerning(handle);
66 void Font::Kerning(bool b) noexcept {
67 TTF_SetFontKerning(handle, b);
71 int Font::Height() const noexcept {
72 return TTF_FontHeight(handle);
75 int Font::Ascent() const noexcept {
76 return TTF_FontAscent(handle);
79 int Font::Descent() const noexcept {
80 return TTF_FontDescent(handle);
83 int Font::LineSkip() const noexcept {
84 return TTF_FontLineSkip(handle);
88 const char *Font::FamilyName() const noexcept {
89 return TTF_FontFaceFamilyName(handle);
92 const char *Font::StyleName() const noexcept {
93 return TTF_FontFaceStyleName(handle);
97 bool Font::HasGlyph(Uint16 c) const noexcept {
98 return TTF_GlyphIsProvided(handle, c);
102 glm::tvec2<int> Font::TextSize(const char *text) const {
103 glm::tvec2<int> size;
104 if (TTF_SizeUTF8(handle, text, &size.x, &size.y) != 0) {
105 throw std::runtime_error(TTF_GetError());
110 Texture Font::Render(const char *text) const {
116 void Font::Render(const char *text, Texture &tex) const {
117 SDL_Surface *srf = TTF_RenderUTF8_Blended(handle, text, { 0xFF, 0xFF, 0xFF, 0xFF });
119 throw std::runtime_error(TTF_GetError());
122 tex.Data(*srf, false);
124 SDL_FreeSurface(srf);
128 void Format::ReadPixelFormat(const SDL_PixelFormat &fmt) {
129 if (fmt.BytesPerPixel == 4) {
130 if (fmt.Amask == 0xFF) {
131 if (fmt.Rmask == 0xFF00) {
136 type = GL_UNSIGNED_INT_8_8_8_8;
138 if (fmt.Rmask == 0xFF) {
143 type = GL_UNSIGNED_INT_8_8_8_8_REV;
147 if (fmt.Rmask == 0xFF) {
152 type = GL_UNSIGNED_BYTE;
162 glGenTextures(1, &handle);
165 Texture::~Texture() {
167 glDeleteTextures(1, &handle);
171 Texture::Texture(Texture &&other) noexcept
172 : handle(other.handle) {
175 height = other.height;
178 Texture &Texture::operator =(Texture &&other) noexcept {
179 std::swap(handle, other.handle);
181 height = other.height;
186 void Texture::Bind() noexcept {
187 glBindTexture(GL_TEXTURE_2D, handle);
191 bool ispow2(unsigned int i) {
192 // don't care about i == 0 here
193 return !(i & (i - 1));
197 void Texture::Data(const SDL_Surface &srf, bool pad2) noexcept {
199 format.ReadPixelFormat(*srf.format);
201 if (!pad2 || (ispow2(srf.w) && ispow2(srf.h))) {
202 int align = UnpackAlignmentFromPitch(srf.pitch);
204 int pitch = (srf.w * srf.format->BytesPerPixel + align - 1) / align * align;
205 if (srf.pitch - pitch >= align) {
206 UnpackRowLength(srf.pitch / srf.format->BytesPerPixel);
211 Data(srf.w, srf.h, format, srf.pixels);
214 } else if (srf.w > (1 << 30) || srf.h > (1 << 30)) {
216 throw std::runtime_error("texture too large");
219 GLsizei width = 1, height = 1;
220 while (width < srf.w) {
223 while (height < srf.h) {
226 size_t pitch = width * srf.format->BytesPerPixel;
227 size_t size = pitch * height;
228 size_t row_pad = pitch - srf.pitch;
229 std::unique_ptr<unsigned char[]> data(new unsigned char[size]);
230 unsigned char *src = reinterpret_cast<unsigned char *>(srf.pixels);
231 unsigned char *dst = data.get();
232 for (int row = 0; row < srf.h; ++row) {
233 std::memcpy(dst, src, srf.pitch);
236 std::memset(dst, 0, row_pad);
239 std::memset(dst, 0, (height - srf.h) * pitch);
240 UnpackAlignmentFromPitch(pitch);
241 Data(width, height, format, data.get());
247 void Texture::Data(GLsizei w, GLsizei h, const Format &format, GLvoid *data) noexcept {
253 format.format, format.type,
261 void Texture::FilterNearest() noexcept {
262 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
263 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
266 void Texture::FilterLinear() noexcept {
267 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
268 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
271 void Texture::FilterTrilinear() noexcept {
272 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
273 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
274 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
275 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
276 glGenerateMipmap(GL_TEXTURE_2D);
280 void Texture::UnpackAlignment(GLint i) noexcept {
281 glPixelStorei(GL_UNPACK_ALIGNMENT, i);
284 int Texture::UnpackAlignmentFromPitch(int pitch) noexcept {
286 while (pitch % align) {
289 UnpackAlignment(align);
293 void Texture::UnpackRowLength(GLint i) noexcept {
294 glPixelStorei(GL_UNPACK_ROW_LENGTH, i);