Root/
| 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 | |
| 11 | ASFont::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 | |
| 67 | ASFont::~ASFont() { |
| 68 | if (surface) { |
| 69 | SDL_FreeSurface(surface); |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | bool ASFont::utf8Code(unsigned char c) { |
| 74 | return (c>=194 && c<=198) || c==208 || c==209; |
| 75 | //return c>=194; |
| 76 | } |
| 77 | |
| 78 | void 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 | |
| 113 | int 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 | |
| 139 | int ASFont::getTextWidth(const std::string& text) { |
| 140 | return getTextWidth(text.c_str()); |
| 141 | } |
| 142 | |
| 143 | void 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 | |
| 157 | void 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 | |
| 171 | void 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 | |
| 189 | void 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 |
Branches:
install_locations
master
opkrun
packages
