/* Text.hxx * * Copyright (c) 2003, Tuomas J. Lukka * * This file is part of Gzz. * * Gzz is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Gzz is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General * Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with Gzz; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * */ /* * Written by Tuomas J. Lukka */ #include #include #include #ifndef GZZ_TEXT_HXX #define GZZ_TEXT_HXX /** Fonts using OpenGL textures (mosaics) and FreeType2. */ namespace GLMosaicText { PREDBGVAR(dbg); PREDBGVAR(dbg_glyphdetails); using std::string; using std::vector; using std::ostream; using std::cout; using Mosaic::Id; using Mosaic::Raster; using Mosaic::Rect; using Mosaic::MosaicBuilder; using Mosaic::MosaicTile; using Mosaic::Texture2DFactory; /** The extents of a glyph. */ class GlyphInfo { public: GlyphInfo(float top, float left, float width, float height, float xadvance, float scaleFromPixels, short iwidth, short iheight) : top(top), left(left), width(width), height(height), xadvance(xadvance), scaleFromPixels(scaleFromPixels), iwidth(iwidth), iheight(iheight) { } GlyphInfo() : top(0), left(0), width(0), height(0), xadvance(0) { } float top; float left; float width; float height; float xadvance; float scaleFromPixels; short iwidth; short iheight; friend ostream& operator<<(ostream& o, const GlyphInfo &g) ; }; inline ostream& operator<<(ostream& o, const GlyphInfo &g) { return o << "[glyphinfo "< raster; Glyph(GlyphInfo extents, Raster raster) : extents(extents), raster(raster) { } Glyph() { } ~Glyph() { } Glyph withBorder(int texels) { // Empty glyphs remain empty. if(extents.width == 0) return *this; float scale = extents.scaleFromPixels; float st = scale * texels; return Glyph( GlyphInfo( extents.top - 1 * st, extents.left - 1 * st, extents.width + 2 * st, extents.height + 2 * st, extents.xadvance, extents.scaleFromPixels, extents.iwidth + 2 * texels, extents.iheight + 2 * texels ), raster.addBorder(texels, 0)); } friend ostream& operator<<(ostream&, const Glyph &); // void print(ostream &outt); }; inline ostream& operator<<(ostream&o, const Glyph &g) { return o << "[Glyph "<getRaster(unicode); return g.withBorder(bwidth); } virtual float getLineHeight() { return f->getLineHeight(); } virtual float getLineOffset() { return f->getLineOffset(); } }; struct QuadGlyph { Glyph glyph; Rect rect; QuadGlyph() {} QuadGlyph(Glyph glyph, Rect &rect) : glyph(glyph), rect(rect) { } bool valid() { return rect.tex.isGood() ; } template void draw(float &cx, float &cy, Vertex &vertex) { if(glyph.extents.width != 0) { float cx1 = cx + glyph.extents.left; float cy1 = cy + glyph.extents.top; float cx2 = cx1 + glyph.extents.width; float cy2 = cy1 + glyph.extents.height; rect.texcoord(0, 0); vertex(cx1, cy1); rect.texcoord(0, 1); vertex(cx1, cy2); rect.texcoord(1, 1); vertex(cx2, cy2); rect.texcoord(1, 0); vertex(cx2, cy1); } cx += glyph.extents.xadvance; } friend ostream &operator<< (ostream &, const QuadGlyph &); }; inline ostream &operator<<(ostream &o, const QuadGlyph &gi) { return o << "[glyphinfo "< class DenseGlyphs { MosaicBuilder mosaic; vector< QuadGlyph > glyphs; public: /** Create. */ DenseGlyphs(Font *face) : mosaic(new Texture2DFactory( new Raster(512, 512))), glyphs(256) { for(int i=0; i<256; i++) { try { Glyph g = face->getRaster(i); if(g.extents.width == 0 || g.extents.height == 0) continue; MosaicTile tile = mosaic.alloc(g.extents.iwidth, g.extents.iheight); DBG(dbg_glyphdetails) << "MTile: "< 255) { std::cerr << "DenseGlyphs::operator[]: character " << c << " out of range\n"; return glyphs['?']; } return glyphs[c]; } /** Get the width of a single glyph. */ float getGlyphWidth(Char c) { if((unsigned)c >= glyphs.size()) return 0; DBG(dbg_glyphdetails) << "Glyphwidth: "<<((int)c)<<" "< class Renderer { Mosaic::Id curtex; public: Glyphs g; /** Construct. Note: this is an expensive operation * so it should not be done for every string ;) */ Renderer(Font *f) : g(f) { } /** Initialize OpenGL state for rendering. */ void startRendering() { glBegin(GL_QUADS); curtex = Mosaic::Id(); // clear. } /** Render a single character. * @return New x position. */ template float renderChar(Char c, float x, float y, Vertex &vertex, TexBind t) { // returns new x pos QuadGlyph &glyph = g[(unsigned)c]; if(!glyph.valid()) return x; if(glyph.rect.tex != curtex) { glEnd(); t(glyph.rect.tex); glBegin(GL_QUADS); } glyph.draw(x, y, vertex); return x; } /** Finish OpenGL state for rendering. */ void endRendering() { glEnd(); } }; /** Render a string. * OpenGL texture coordinates are set normally but * in order to allow nonlinear transforms of vertices, * all vertex commands are routed through the Vertex object. */ template float renderIter( RandomRenderer &r, Iterator begin, Iterator end, float x, float y, Vertex &vertex, TexBind t) { r.startRendering(); while(begin != end) { x = r.renderChar(*begin, x, y, vertex, t); begin++; } r.endRendering(); return x; } } #endif