texturefont.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:11k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // texturefont.cpp
  2. //
  3. // Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. #include <cassert>
  10. #include <cstring>
  11. #include <fstream>
  12. #ifndef _WIN32
  13. #ifndef TARGET_OS_MAC
  14. #include <config.h>
  15. #endif /* TARGET_OS_MAC */
  16. #endif /* _WIN32 */
  17. #include <celutil/debug.h>
  18. #include <celutil/bytes.h>
  19. #include <celutil/utf8.h>
  20. #include <celutil/util.h>
  21. #include <celengine/gl.h>
  22. #include "texturefont.h"
  23. using namespace std;
  24. TextureFont::TextureFont() :
  25.     maxAscent(0),
  26.     maxDescent(0),
  27.     maxWidth(0),
  28.     texWidth(0),
  29.     texHeight(0),
  30.     fontImage(NULL),
  31.     texName(0),
  32.     glyphLookup(NULL),
  33.     glyphLookupTableSize(0)
  34. {
  35. }
  36. TextureFont::~TextureFont()
  37. {
  38.     if (texName != 0)
  39.         glDeleteTextures(1, (const GLuint*) &texName);
  40.     if (fontImage != NULL)
  41.         delete[] fontImage;
  42.     if (glyphLookup != NULL)
  43.         delete[] glyphLookup;
  44. }
  45. void TextureFont::render(wchar_t ch) const
  46. {
  47.     const Glyph* glyph = getGlyph(ch);
  48.     if (glyph == NULL) glyph = getGlyph((wchar_t)'?');
  49.     if (glyph != NULL)
  50.     {
  51.         glBegin(GL_QUADS);
  52.         glTexCoord2f(glyph->texCoords[0].u, glyph->texCoords[0].v);
  53.         glVertex2f(glyph->xoff, glyph->yoff);
  54.         glTexCoord2f(glyph->texCoords[1].u, glyph->texCoords[1].v);
  55.         glVertex2f(glyph->xoff + glyph->width, glyph->yoff);
  56.         glTexCoord2f(glyph->texCoords[2].u, glyph->texCoords[2].v);
  57.         glVertex2f(glyph->xoff + glyph->width, glyph->yoff + glyph->height);
  58.         glTexCoord2f(glyph->texCoords[3].u, glyph->texCoords[3].v);
  59.         glVertex2f(glyph->xoff, glyph->yoff + glyph->height);
  60.         glEnd();
  61.         glTranslatef(glyph->advance, 0.0f, 0.0f);
  62.     }
  63. }
  64. void TextureFont::render(const string& s) const
  65. {
  66.     int len = s.length();
  67.     bool validChar = true;
  68.     int i = 0;
  69. while (i < len && validChar) {
  70.         wchar_t ch = 0;
  71.         validChar = UTF8Decode(s, i, ch);
  72.         i += UTF8EncodedSize(ch);
  73.         
  74.         render(ch);
  75.     }
  76. }
  77. int TextureFont::getWidth(const string& s) const
  78. {
  79.     int width = 0;
  80.     int len = s.length();
  81.     bool validChar = true;
  82. int i = 0;
  83.     while (i < len && validChar)
  84.     {
  85.         wchar_t ch = 0;
  86.         validChar = UTF8Decode(s, i, ch);
  87.         i += UTF8EncodedSize(ch);
  88.         const Glyph* g = getGlyph(ch);
  89.         if (g != NULL)
  90.             width += g->advance;
  91.     }
  92.     return width;
  93. }
  94. int TextureFont::getHeight() const
  95. {
  96.     return maxAscent + maxDescent;
  97. }
  98. int TextureFont::getMaxWidth() const
  99. {
  100.     return maxWidth;
  101. }
  102. int TextureFont::getMaxAscent() const
  103. {
  104.     return maxAscent;
  105. }
  106. void TextureFont::setMaxAscent(int _maxAscent)
  107. {
  108.     maxAscent = _maxAscent;
  109. }
  110. int TextureFont::getMaxDescent() const
  111. {
  112.     return maxDescent;
  113. }
  114. void TextureFont::setMaxDescent(int _maxDescent)
  115. {
  116.     maxDescent = _maxDescent;
  117. }
  118. int TextureFont::getTextureName() const
  119. {
  120.     return texName;
  121. }
  122. void TextureFont::bind()
  123. {
  124.     if (texName != 0)
  125.         glBindTexture(GL_TEXTURE_2D, texName);
  126. }
  127. void TextureFont::addGlyph(const TextureFont::Glyph& g)
  128. {
  129.     glyphs.insert(glyphs.end(), g);
  130.     if (g.width > maxWidth)
  131.         maxWidth = g.width;
  132. }
  133. const TextureFont::Glyph* TextureFont::getGlyph(wchar_t ch) const
  134. {
  135.     if (ch >= (wchar_t)glyphLookupTableSize)
  136.         return NULL;
  137.     else
  138.         return glyphLookup[ch];
  139. }
  140. bool TextureFont::buildTexture()
  141. {
  142.     assert(fontImage != NULL);
  143.     if (texName != 0)
  144.         glDeleteTextures(1, (const GLuint*) &texName);
  145.     glGenTextures(1, (GLuint*) &texName);
  146.     if (texName == 0)
  147.     {
  148.         DPRINTF(0, "Failed to allocate texture object for font.n");
  149.         return false;
  150.     }
  151.     glBindTexture(GL_TEXTURE_2D, texName);
  152.     // Don't build mipmaps . . . should really make them an option.
  153.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  154.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  155.     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA,
  156.                  texWidth, texHeight,
  157.                  0,
  158.                  GL_ALPHA, GL_UNSIGNED_BYTE,
  159.                  fontImage);
  160.     return true;
  161. }
  162. void TextureFont::rebuildGlyphLookupTable()
  163. {
  164.     if (glyphs.size() == 0)
  165.         return;
  166.     // Find the largest glyph id
  167.     int maxID = glyphs[0].__id;
  168.     vector<Glyph>::const_iterator iter;
  169.     for (iter = glyphs.begin(); iter != glyphs.end(); iter++)
  170.     {
  171.         if (iter->__id > maxID)
  172.             maxID = iter->__id;
  173.     }
  174.     // If there was already a lookup table, delete it.
  175.     if (glyphLookup != NULL)
  176.         delete[] glyphLookup;
  177.     DPRINTF(1, "texturefont: allocating glyph lookup table with %d entries.n",
  178.             maxID + 1);
  179.     glyphLookup = new const Glyph*[maxID + 1];
  180.     for (int i = 0; i <= maxID; i++)
  181.         glyphLookup[i] = NULL;
  182.     // Fill the table with glyph pointers
  183.     for (iter = glyphs.begin(); iter != glyphs.end(); iter++)
  184.         glyphLookup[iter->__id] = &(*iter);
  185.     glyphLookupTableSize = (unsigned int) maxID + 1;
  186. }
  187. static uint32 readUint32(istream& in, bool swap)
  188. {
  189.     uint32 x;
  190.     in.read(reinterpret_cast<char*>(&x), sizeof x);
  191.     return swap ? bswap_32(x) : x;
  192. }
  193. static uint16 readUint16(istream& in, bool swap)
  194. {
  195.     uint16 x;
  196.     in.read(reinterpret_cast<char*>(&x), sizeof x);
  197.     return swap ? bswap_16(x) : x;
  198. }
  199. static uint8 readUint8(istream& in)
  200. {
  201.     uint8 x;
  202.     in.read(reinterpret_cast<char*>(&x), sizeof x);
  203.     return x;
  204. }
  205. /* Not currently used
  206. static int32 readInt32(istream& in, bool swap)
  207. {
  208.     int32 x;
  209.     in.read(reinterpret_cast<char*>(&x), sizeof x);
  210.     return swap ? static_cast<int32>(bswap_32(static_cast<uint32>(x))) : x;
  211. }*/
  212. static int16 readInt16(istream& in, bool swap)
  213. {
  214.     int16 x;
  215.     in.read(reinterpret_cast<char*>(&x), sizeof x);
  216.     return swap ? static_cast<int16>(bswap_16(static_cast<uint16>(x))) : x;
  217. }
  218. static int8 readInt8(istream& in)
  219. {
  220.     int8 x;
  221.     in.read(reinterpret_cast<char*>(&x), sizeof x);
  222.     return x;
  223. }
  224. TextureFont* TextureFont::load(istream& in)
  225. {
  226.     char header[4];
  227.     in.read(header, sizeof header);
  228.     if (!in.good() || strncmp(header, "377txf", 4) != 0)
  229.     {
  230.         DPRINTF(0, "Stream is not a texture font!.n");
  231.         return NULL;
  232.     }
  233.     uint32 endiannessTest = 0;
  234.     in.read(reinterpret_cast<char*>(&endiannessTest), sizeof endiannessTest);
  235.     if (!in.good())
  236.     {
  237.         DPRINTF(0, "Error reading endianness bytes in txf header.n");
  238.         return NULL;
  239.     }
  240.     bool byteSwap;
  241.     if (endiannessTest == 0x78563412)
  242.         byteSwap = true;
  243.     else if (endiannessTest == 0x12345678)
  244.         byteSwap = false;
  245.     else
  246.     {
  247.         DPRINTF(0, "Stream is not a texture font!.n");
  248.         return NULL;
  249.     }
  250.     int format = readUint32(in, byteSwap);
  251.     unsigned int texWidth = readUint32(in, byteSwap);
  252.     unsigned int texHeight = readUint32(in, byteSwap);
  253.     unsigned int maxAscent = readUint32(in, byteSwap);
  254.     unsigned int maxDescent = readUint32(in, byteSwap);
  255.     unsigned int nGlyphs = readUint32(in, byteSwap);
  256.     if (!in)
  257.     {
  258.         DPRINTF(0, "Texture font stream is incomplete");
  259.         return NULL;
  260.     }
  261.     DPRINTF(1, "Font contains %d glyphs.n", nGlyphs);
  262.     TextureFont* font = new TextureFont();
  263.     assert(font != NULL);
  264.     font->setMaxAscent(maxAscent);
  265.     font->setMaxDescent(maxDescent);
  266.     float dx = 0.5f / texWidth;
  267.     float dy = 0.5f / texHeight;
  268.     for (unsigned int i = 0; i < nGlyphs; i++)
  269.     {
  270.         uint16 __id = readUint16(in, byteSwap);
  271.         TextureFont::Glyph glyph(__id);
  272.         glyph.width = readUint8(in);
  273.         glyph.height = readUint8(in);
  274.         glyph.xoff = readInt8(in);
  275.         glyph.yoff = readInt8(in);
  276.         glyph.advance = readInt8(in);
  277.         readInt8(in);
  278.         glyph.x = readInt16(in, byteSwap);
  279.         glyph.y = readInt16(in, byteSwap);
  280.         
  281.         if (!in)
  282.         {
  283.             DPRINTF(0, "Error reading glyph %ud from texture font stream.n", i);
  284.             delete font;
  285.             return NULL;
  286.         }
  287.         float fWidth = texWidth;
  288.         float fHeight = texHeight;
  289.         glyph.texCoords[0].u = glyph.x / fWidth + dx;
  290.         glyph.texCoords[0].v = glyph.y / fHeight + dy;
  291.         glyph.texCoords[1].u = (glyph.x + glyph.width) / fWidth + dx;
  292.         glyph.texCoords[1].v = glyph.y / fHeight + dy;
  293.         glyph.texCoords[2].u = (glyph.x + glyph.width) / fWidth + dx;
  294.         glyph.texCoords[2].v = (glyph.y + glyph.height) / fHeight + dy;
  295.         glyph.texCoords[3].u = glyph.x / fWidth + dx;
  296.         glyph.texCoords[3].v = (glyph.y + glyph.height) / fHeight + dy;
  297.         font->addGlyph(glyph);
  298.     }
  299.     font->texWidth = texWidth;
  300.     font->texHeight = texHeight;
  301.     if (format == TxfByte)
  302.     {
  303.         unsigned char* fontImage = new unsigned char[texWidth * texHeight];
  304.         if (fontImage == NULL)
  305.         {
  306.             DPRINTF(0, "Not enough memory for font bitmap.n");
  307.             delete font;
  308.             return NULL;
  309.         }
  310.         DPRINTF(1, "Reading %d x %d 8-bit font image.n", texWidth, texHeight);
  311.         in.read(reinterpret_cast<char*>(fontImage), texWidth * texHeight);
  312.         if (in.gcount() != (signed)(texWidth * texHeight))
  313.         {
  314.             DPRINTF(0, "Missing bitmap data in font stream.n");
  315.             delete font;
  316.             delete[] fontImage;
  317.             return NULL;
  318.         }
  319.         font->fontImage = fontImage;
  320.     }
  321.     else
  322.     {
  323.         int rowBytes = (texWidth + 7) >> 3;
  324.         unsigned char* fontBits = new unsigned char[rowBytes * texHeight];
  325.         unsigned char* fontImage = new unsigned char[texWidth * texHeight];
  326.         if (fontImage == NULL || fontBits == NULL)
  327.         {
  328.             DPRINTF(0, "Not enough memory for font bitmap.n");
  329.             delete font;
  330.             if (fontBits != NULL)
  331.                 delete[] fontBits;
  332.             if (fontImage != NULL)
  333.                 delete[] fontImage;
  334.             return NULL;
  335.         }
  336.         DPRINTF(1, "Reading %d x %d 1-bit font image.n", texWidth, texHeight);
  337.         in.read(reinterpret_cast<char*>(fontBits), rowBytes * texHeight);
  338.         if (in.gcount() != (signed)(rowBytes * texHeight))
  339.         {
  340.             DPRINTF(0, "Missing bitmap data in font stream.n");
  341.             delete font;
  342.             return NULL;
  343.         }
  344.         for (unsigned int y = 0; y < texHeight; y++)
  345.         {
  346.             for (unsigned int x = 0; x < texWidth; x++)
  347.             {
  348.                 if ((fontBits[y * rowBytes + (x >> 3)] & (1 << (x & 0x7))) != 0)
  349.                     fontImage[y * texWidth + x] = 0xff;
  350.                 else
  351.                     fontImage[y * texWidth + x] = 0x0;
  352.             }
  353.         }
  354.         font->fontImage = fontImage;
  355.         delete[] fontBits;
  356.     }
  357.     font->rebuildGlyphLookupTable();
  358.     return font;
  359. }
  360. TextureFont* LoadTextureFont(const string& filename)
  361. {
  362.     string localeFilename = LocaleFilename(filename);
  363.     ifstream in(localeFilename.c_str(), ios::in | ios::binary);
  364.     if (!in.good())
  365.     {
  366.         DPRINTF(0, "Could not open font file %sn", filename.c_str());
  367.         return NULL;
  368.     }
  369.     return TextureFont::load(in);
  370. }