CBitmapHanFont.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. * CBitmapHanFont.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "Fonts.h"
  12. #include <SDL_ttf.h>
  13. #include "SDL_Extensions.h"
  14. #include "../../lib/JsonNode.h"
  15. #include "../../lib/vcmi_endian.h"
  16. #include "../../lib/filesystem/Filesystem.h"
  17. #include "../../lib/CGeneralTextHandler.h"
  18. size_t CBitmapHanFont::getCharacterDataOffset(size_t index) const
  19. {
  20. size_t rowSize = (size + 7) / 8; // 1 bit per pixel, rounded up
  21. size_t charSize = rowSize * size; // glyph contains "size" rows
  22. return index * charSize;
  23. }
  24. size_t CBitmapHanFont::getCharacterIndex(ui8 first, ui8 second) const
  25. {
  26. if (second > 0x7f )
  27. second--;
  28. return (first - 0x81) * (12*16 - 2) + (second - 0x40);
  29. }
  30. void CBitmapHanFont::renderCharacter(SDL_Surface * surface, int characterIndex, const SDL_Color & color, int &posX, int &posY) const
  31. {
  32. //TODO: somewhat duplicated with CBitmapFont::renderCharacter();
  33. Rect clipRect;
  34. CSDL_Ext::getClipRect(surface, clipRect);
  35. CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0);
  36. uint8_t bpp = surface->format->BytesPerPixel;
  37. // start of line, may differ from 0 due to end of surface or clipped surface
  38. int lineBegin = std::max<int>(0, clipRect.y - posY);
  39. int lineEnd = std::min((int)size, clipRect.y + clipRect.h - posY);
  40. // start end end of each row, may differ from 0
  41. int rowBegin = std::max<int>(0, clipRect.x - posX);
  42. int rowEnd = std::min<int>((int)size, clipRect.x + clipRect.w - posX);
  43. //for each line in symbol
  44. for(int dy = lineBegin; dy <lineEnd; dy++)
  45. {
  46. uint8_t *dstLine = (uint8_t*)surface->pixels;
  47. uint8_t *source = data.first.get() + getCharacterDataOffset(characterIndex);
  48. // shift source\destination pixels to current position
  49. dstLine += (posY+dy) * surface->pitch + posX * bpp;
  50. source += ((size + 7) / 8) * dy;
  51. //for each column in line
  52. for(int dx = rowBegin; dx < rowEnd; dx++)
  53. {
  54. // select current bit in bitmap
  55. int bit = (source[dx / 8] << (dx % 8)) & 0x80;
  56. uint8_t* dstPixel = dstLine + dx*bpp;
  57. if (bit != 0)
  58. colorPutter(dstPixel, color.r, color.g, color.b);
  59. }
  60. }
  61. posX += (int)size + 1;
  62. }
  63. void CBitmapHanFont::renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const
  64. {
  65. int posX = pos.x;
  66. int posY = pos.y;
  67. SDL_LockSurface(surface);
  68. for(size_t i=0; i<data.size(); i += Unicode::getCharacterSize(data[i]))
  69. {
  70. std::string localChar = Unicode::fromUnicode(data.substr(i, Unicode::getCharacterSize(data[i])));
  71. if (localChar.size() == 1)
  72. fallback->renderCharacter(surface, fallback->chars[ui8(localChar[0])], color, posX, posY);
  73. if (localChar.size() == 2)
  74. renderCharacter(surface, (int)getCharacterIndex(localChar[0], localChar[1]), color, posX, posY);
  75. }
  76. SDL_UnlockSurface(surface);
  77. }
  78. CBitmapHanFont::CBitmapHanFont(const JsonNode &config):
  79. fallback(new CBitmapFont(config["fallback"].String())),
  80. data(CResourceHandler::get()->load(ResourceID("data/" + config["name"].String(), EResType::OTHER))->readAll()),
  81. size((size_t)config["size"].Float())
  82. {
  83. // basic tests to make sure that fonts are OK
  84. // 1) fonts must contain 190 "sections", 126 symbols each.
  85. assert(getCharacterIndex(0xfe, 0xff) == 190*126);
  86. // 2) ensure that font size is correct - enough to fit all possible symbols
  87. assert(getCharacterDataOffset(getCharacterIndex(0xfe, 0xff)) == data.second);
  88. }
  89. size_t CBitmapHanFont::getLineHeight() const
  90. {
  91. return std::max(size + 1, fallback->getLineHeight());
  92. }
  93. size_t CBitmapHanFont::getGlyphWidth(const char * data) const
  94. {
  95. std::string localChar = Unicode::fromUnicode(std::string(data, Unicode::getCharacterSize(data[0])));
  96. if (localChar.size() == 1)
  97. return fallback->getGlyphWidth(data);
  98. if (localChar.size() == 2)
  99. return size + 1;
  100. return 0;
  101. }