Root/src/asfont.cpp

1#include "asfont.h"
2#include "imageio.h"
3#include "surface.h"
4#include "utilities.h"
5
6#include <cassert>
7#include <cstring>
8
9#define SFONTPLUS_CHARSET "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~¡¿ÀÁÈÉÌÍÒÓÙÚÝÄËÏÖÜŸÂÊÎÔÛÅÃÕÑÆÇČĎĚĽĹŇÔŘŔŠŤŮŽàáèéìíòóùúýäëïöüÿâêîôûåãõñæçčďěľĺňôřŕšťžůðßÐÞþАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяØøąćęłńśżźĄĆĘŁŃŚŻŹ"
10
11ASFont::ASFont(const std::string &fontImagePath)
12    : characters(SFONTPLUS_CHARSET)
13{
14    surface = loadPNG(fontImagePath);
15    if (!surface) {
16        return;
17    }
18    assert(surface->format->BytesPerPixel == 4);
19
20    SDL_LockSurface(surface);
21
22    // Determine character widths.
23    Uint32 pink = SDL_MapRGB(surface->format, 255, 0, 255);
24    Uint32 *topLine = static_cast<Uint32 *>(surface->pixels);
25    const unsigned width = surface->w;
26    unsigned x = 0;
27    unsigned c = 0;
28    while (c < characters.length()) {
29        while (x < width && topLine[x] != pink) x++;
30        unsigned startx = x;
31        x++;
32        while (x < width && topLine[x] == pink) x++;
33
34        charpos.push_back(startx);
35        charpos.push_back(x);
36        if (c > 0 && utf8Code(characters[c - 1])) {
37            // UTF8 character
38            charpos.push_back(startx);
39            charpos.push_back(x);
40            c++;
41        }
42        c++;
43    }
44
45    // Scan height of "0" glyph.
46    std::string::size_type pos = characters.find("0") * 2;
47    SDL_Rect srcrect = {
48        charpos[pos], 1, charpos[pos + 2] - charpos[pos], surface->h - 1
49    };
50    const unsigned alphaMask = surface->format->Amask;
51    unsigned y = srcrect.h;
52    bool nonTransparentFound = false;
53    while (!nonTransparentFound && y-- > 0) {
54        Uint32 *line = reinterpret_cast<Uint32 *>(
55            reinterpret_cast<Uint8 *>(surface->pixels)
56                + (srcrect.y + y) * surface->pitch
57            );
58        for (unsigned x = 0; !nonTransparentFound && x < srcrect.w; x++) {
59            nonTransparentFound = (line[srcrect.x + x] & alphaMask) != 0;
60        }
61    }
62    lineHeight = y + 1;
63
64    SDL_UnlockSurface(surface);
65}
66
67ASFont::~ASFont() {
68    if (surface) {
69        SDL_FreeSurface(surface);
70    }
71}
72
73bool ASFont::utf8Code(unsigned char c) {
74    return (c>=194 && c<=198) || c==208 || c==209;
75    //return c>=194;
76}
77
78void ASFont::writeLine(Surface *s, const std::string &text, int x, int y) {
79    if (text.empty()) return;
80
81    std::string::size_type pos;
82    SDL_Rect srcrect, dstrect;
83
84    // these values won't change in the loop
85    srcrect.y = 1;
86    dstrect.y = y;
87    srcrect.h = dstrect.h = surface->h-1;
88
89    for(unsigned i=0; i<text.length() && x<surface->w; i++) {
90        //Utf8 characters
91        if (utf8Code(text[i]) && i+1<text.length()) {
92            pos = characters.find(text.substr(i,2));
93            i++;
94        } else
95            pos = characters.find(text[i]);
96        if (pos == std::string::npos) {
97            x += charpos[2]-charpos[1];
98            continue;
99        }
100
101        pos *= 2;
102
103        srcrect.x = charpos[pos];
104        srcrect.w = charpos[pos+2] - charpos[pos];
105        dstrect.x = x - charpos[pos+1] + charpos[pos];
106
107        SDL_BlitSurface(surface, &srcrect, s->raw, &dstrect);
108
109        x += charpos[pos+2] - charpos[pos+1];
110    }
111}
112
113int ASFont::getTextWidth(const char *text) {
114    int maxWidth = 0, width = 0;
115    while (char ch = *text++) {
116        if (ch == '\n') {
117            // New line.
118            maxWidth = max(width, maxWidth);
119            width = 0;
120        } else {
121            std::string::size_type pos;
122            if (utf8Code(ch) && *text) {
123                // 2-byte character.
124                pos = characters.find(std::string(&text[-1], 2));
125                text++;
126            } else {
127                // 1-byte character.
128                pos = characters.find(ch);
129            }
130            if (pos == std::string::npos) {
131                pos = 0;
132            }
133            width += charpos[pos * 2 + 2] - charpos[pos * 2 + 1];
134        }
135    }
136    return max(width, maxWidth);
137}
138
139int ASFont::getTextWidth(const std::string& text) {
140    return getTextWidth(text.c_str());
141}
142
143void ASFont::writeLine(Surface* surface, const std::string& text, int x, int y, HAlign halign) {
144    switch (halign) {
145    case HAlignLeft:
146        break;
147    case HAlignCenter:
148        x -= getTextWidth(text) / 2;
149        break;
150    case HAlignRight:
151        x -= getTextWidth(text);
152        break;
153    }
154    writeLine(surface, text, x, y);
155}
156
157void ASFont::writeLine(Surface* surface, const std::string& text, int x, int y, HAlign halign, VAlign valign) {
158    switch (valign) {
159    case VAlignTop:
160        break;
161    case VAlignMiddle:
162        y -= getHeight() / 2;
163        break;
164    case VAlignBottom:
165        y -= getHeight();
166        break;
167    }
168    writeLine(surface, text, x, y, halign);
169}
170
171void ASFont::writeLine(Surface* surface, const std::vector<std::string> &text, int x, int y, HAlign halign, VAlign valign) {
172    switch (valign) {
173    case VAlignTop:
174        break;
175    case VAlignMiddle:
176        y -= (getHeight() / 2) * text.size();
177        break;
178    case VAlignBottom:
179        y -= getHeight() * text.size();
180        break;
181    }
182
183    for (std::vector<std::string>::const_iterator it = text.begin(); it != text.end(); ++it) {
184        write(surface, *it, x, y, halign);
185        y += getHeight();
186    }
187}
188
189void ASFont::write(Surface* surface, const std::string& text, int x, int y, HAlign halign, VAlign valign) {
190    if (text.find("\n", 0) != std::string::npos) {
191        std::vector<std::string> textArr;
192        split(textArr, text, "\n");
193        writeLine(surface, textArr, x, y, halign, valign);
194    } else
195        writeLine(surface, text, x, y, halign, valign);
196}
197

Archive Download this file



interactive