From 9bb913a9b13917818492b5f4ee61e49d1de3ae3a Mon Sep 17 00:00:00 2001
From: cozman
Date: Mon, 18 Jul 2005 22:19:16 +0000
Subject: [PATCH] Initial revision
---
GLFT_Font.cpp | 363 ++++++++++++++++++++++++++++++++++++++++++++++++++
GLFT_Font.hpp | 112 ++++++++++++++++
README | 34 +++++
index.html | 55 ++++++++
test.cpp | 53 ++++++++
5 files changed, 617 insertions(+)
create mode 100644 GLFT_Font.cpp
create mode 100644 GLFT_Font.hpp
create mode 100644 README
create mode 100644 index.html
create mode 100644 test.cpp
diff --git a/GLFT_Font.cpp b/GLFT_Font.cpp
new file mode 100644
index 0000000..be80142
--- /dev/null
+++ b/GLFT_Font.cpp
@@ -0,0 +1,363 @@
+// GLFT_Font (http://www.cs.rit.edu/~jpt2433/glftfont/)
+// by James Turk (jpt2433@rit.edu)
+// Based on work by Marijn Haverbeke (http://marijn.haverbeke.nl)
+//
+// Version 0.1 - Released 1 July 2005 - Initial Release
+// Version 0.2 - Released 18 July 2005 - Added beginDraw/endDraw,
+// Changed vsprintf to vsnprintf
+//
+// $Id: GLFT_Font.cpp,v 1.1 2005/07/18 22:19:16 cozman Exp $
+//
+// Copyright (c) 2005, James Turk
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the GLFT_Font nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+
+#include "GLFT_Font.hpp"
+
+// static members
+FT_Library FTLibraryContainer::library_;
+FTLibraryContainer GLFT_Font::library_;
+
+// FTLibraryContainer implementation //
+
+FTLibraryContainer::FTLibraryContainer()
+{
+ if (FT_Init_FreeType(&library_) != 0)
+ {
+ throw std::runtime_error("Could not initialize FreeType2 library.");
+ }
+}
+
+FTLibraryContainer::~FTLibraryContainer()
+{
+ FT_Done_FreeType(library_);
+}
+
+FT_Library& FTLibraryContainer::getLibrary()
+{
+ return library_;
+}
+
+std::ostream& operator<<(std::ostream& os, const StreamFlusher& rhs)
+{
+ return os.flush();
+}
+
+// GLFT_Font implementation //
+
+GLFT_Font::GLFT_Font() :
+ texID_(0), listBase_(0), // initalize GL variables to zero
+ widths_(NUM_CHARS), // make room for 96 widths
+ height_(0), drawX_(0), drawY_(0)
+{
+}
+
+GLFT_Font::GLFT_Font(const std::string& filename, unsigned int size) :
+ texID_(0), listBase_(0), // initalize GL variables to zero
+ widths_(NUM_CHARS), // make room for 96 widths
+ height_(0), drawX_(0), drawY_(0)
+{
+ open(filename, size);
+}
+
+GLFT_Font::~GLFT_Font()
+{
+ release();
+}
+
+void GLFT_Font::open(const std::string& filename, unsigned int size)
+{
+ const size_t MARGIN = 3;
+
+ // release the font if it already exists
+ if(isValid())
+ {
+ release();
+ }
+
+ // Step 1: Open the font using FreeType //
+ FT_Face face;
+
+ if(FT_New_Face(library_.getLibrary(), filename.c_str(), 0, &face) != 0)
+ {
+ throw std::runtime_error("Could not load font file.");
+ }
+
+ // Abort if this is not a scalable font.
+ if(!(face->face_flags & FT_FACE_FLAG_SCALABLE) ||
+ !(face->face_flags & FT_FACE_FLAG_HORIZONTAL))
+ {
+ throw std::runtime_error("Invalid font: Error setting font size.");
+ }
+
+ // Set the font size
+ FT_Set_Pixel_Sizes(face, size, 0);
+
+ // Step 2: Find maxAscent/Descent to calculate imageHeight //
+ size_t imageHeight = 0;
+ size_t imageWidth = 256;
+ int maxDescent = 0;
+ int maxAscent = 0;
+ size_t lineSpace = imageWidth - MARGIN;
+ size_t lines = 1;
+ size_t charIndex;
+
+ for(unsigned int ch = 0; ch < NUM_CHARS; ++ch)
+ {
+ // Look up the character in the font file.
+ charIndex = FT_Get_Char_Index(face, ch+SPACE);
+
+ // Render the current glyph.
+ FT_Load_Glyph(face, charIndex, FT_LOAD_RENDER);
+
+ widths_[ch] = (face->glyph->metrics.horiAdvance >> 6) + MARGIN;
+ // If the line is full go to the next line
+ if(widths_[ch] > lineSpace)
+ {
+ lineSpace = imageWidth - MARGIN;
+ ++lines;
+ }
+ lineSpace -= widths_[ch];
+
+ maxAscent = std::max(face->glyph->bitmap_top, maxAscent);
+ maxDescent = std::max(face->glyph->bitmap.rows -
+ face->glyph->bitmap_top, maxDescent);
+ }
+
+ height_ = maxAscent + maxDescent; // calculate height_ for text
+
+ // Compute how high the texture has to be.
+ size_t neededHeight = (maxAscent + maxDescent + MARGIN) * lines + MARGIN;
+ // Get the first power of two in which it will fit
+ imageHeight = 16;
+ while(imageHeight < neededHeight)
+ {
+ imageHeight <<= 1;
+ }
+
+ // Step 3: Generation of the actual texture //
+
+ // create and zero the memory
+ unsigned char* image = new unsigned char[imageHeight * imageWidth];
+ std::memset(image, 0, imageHeight * imageWidth);
+
+ // These are the position at which to draw the next glyph
+ size_t x = MARGIN;
+ size_t y = MARGIN + maxAscent;
+ float texX1, texX2, texY1, texY2; // used for display list
+
+ listBase_ = glGenLists(NUM_CHARS); // generate the lists for filling
+
+ // Drawing loop
+ for(unsigned int ch = 0; ch < NUM_CHARS; ++ch)
+ {
+ size_t charIndex = FT_Get_Char_Index(face, ch+SPACE);
+
+ // Render the glyph
+ FT_Load_Glyph(face, charIndex, FT_LOAD_DEFAULT);
+ FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
+
+ // See whether the character fits on the current line
+ if(widths_[ch] > imageWidth - x)
+ {
+ x = MARGIN;
+ y += (maxAscent + maxDescent + MARGIN);
+ }
+
+ // calculate texture coordinates of the character
+ texX1 = static_cast(x) / imageWidth;
+ texX2 = static_cast(x+widths_[ch]) / imageWidth;
+ texY1 = static_cast(y - maxAscent) / imageHeight;
+ texY2 = texY1 + static_cast(height_) / imageHeight;
+
+ // generate the character's display list
+ glNewList(listBase_ + ch, GL_COMPILE);
+ glBegin(GL_QUADS);
+ glTexCoord2f(texX1,texY1); glVertex2i(0,0);
+ glTexCoord2f(texX2,texY1); glVertex2i(widths_[ch],0);
+ glTexCoord2f(texX2,texY2); glVertex2i(widths_[ch],height_);
+ glTexCoord2f(texX1,texY2); glVertex2i(0,height_);
+ glEnd();
+ glTranslatef(widths_[ch],0,0); // translate forward
+ glEndList();
+
+ // copy image generated by FreeType to the texture
+ for(int row = 0; row < face->glyph->bitmap.rows; ++row)
+ {
+ for(int pixel = 0; pixel < face->glyph->bitmap.width; ++pixel)
+ {
+ // set pixel at position to intensity (0-255) at the position
+ image[(x + face->glyph->bitmap_left + pixel) +
+ (y - face->glyph->bitmap_top + row) * imageWidth] =
+ face->glyph->bitmap.buffer[pixel +
+ row * face->glyph->bitmap.pitch];
+ }
+ }
+
+ x += widths_[ch];
+ }
+
+ // generate the OpenGL texture from the byte array
+ glGenTextures(1, &texID_);
+ glBindTexture(GL_TEXTURE_2D, texID_);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, imageWidth, imageHeight, 0,
+ GL_ALPHA, GL_UNSIGNED_BYTE, image);
+
+ delete[] image; // now done with the image memory
+ FT_Done_Face(face); // free the face data
+}
+
+void GLFT_Font::release()
+{
+ if(glIsList(listBase_))
+ {
+ glDeleteLists(listBase_, NUM_CHARS);
+ }
+ if(glIsTexture(texID_))
+ {
+ glDeleteTextures(1, &texID_);
+ }
+
+ // clear out data
+ texID_ = 0;
+ listBase_ = 0;
+ widths_.clear();
+ widths_.resize(NUM_CHARS);
+ height_ = 0;
+}
+
+bool GLFT_Font::isValid() const
+{
+ return glIsTexture(texID_) == GL_TRUE;
+}
+
+void GLFT_Font::drawText(float x, float y, const char *str, ...) const
+{
+ if(!isValid())
+ {
+ throw std::logic_error("Invalid GLFT_Font::drawText call.");
+ }
+
+ std::va_list args;
+ char buf[1024];
+
+ va_start(args,str);
+ std::vsnprintf(buf, 1024, str, args); // avoid buffer overflow
+ va_end(args);
+
+ glBindTexture(GL_TEXTURE_2D, texID_);
+ glPushMatrix();
+ glTranslated(x,y,0);
+ for(unsigned int i=0; i < std::strlen(buf); ++i)
+ {
+ unsigned char ch( buf[i] - SPACE ); // ch-SPACE = DisplayList offset
+ // replace characters outside the valid range with undrawable
+ if(ch > NUM_CHARS)
+ {
+ ch = NUM_CHARS-1; // last character is 'undrawable'
+ }
+ glCallList(listBase_+ch); // calculate list to call
+ }
+
+ // Alternative, ignores undrawables (no noticable speed difference)
+ //glListBase(listBase_-32);
+ //glCallLists(static_cast(std::strlen(buf)), GL_UNSIGNED_BYTE, buf);
+
+ glPopMatrix();
+}
+
+void GLFT_Font::drawText(float x, float y, const std::string& str) const
+{
+ if(!isValid())
+ {
+ throw std::logic_error("Invalid GLFT_Font::drawText call.");
+ }
+
+ glBindTexture(GL_TEXTURE_2D, texID_);
+ glPushMatrix();
+ glTranslated(x,y,0);
+ for(std::string::const_iterator i = str.begin(); i != str.end(); ++i)
+ {
+ unsigned char ch( *i - SPACE ); // ch-SPACE = DisplayList offset
+ // replace characters outside the valid range with undrawable
+ if(ch > NUM_CHARS)
+ {
+ ch = NUM_CHARS-1; // last character is 'undrawable'
+ }
+ glCallList(listBase_+ch); // calculate list to call
+ }
+
+ // Alternative, ignores undrawables (no noticable speed difference)
+ //glListBase(listBase_-32);
+ //glCallLists(static_cast(std::strlen(buf)), GL_UNSIGNED_BYTE, buf);
+
+ glPopMatrix();
+}
+
+std::ostream& GLFT_Font::beginDraw(float x, float y)
+{
+ // clear the string and store the draw-position
+ ss_.str("");
+ drawX_ = x;
+ drawY_ = y;
+ return ss_;
+}
+
+StreamFlusher GLFT_Font::endDraw()
+{
+ drawText(drawX_, drawY_, ss_.str()); // draw the string
+ ss_.str(""); // clear the buffer
+ return StreamFlusher();
+}
+
+unsigned int GLFT_Font::calcStringWidth(const std::string& str) const
+{
+ if(!isValid())
+ {
+ throw std::logic_error("Invalid GLFT_Font::calcStringWidth call.");
+ }
+ unsigned int width=0;
+
+ // iterate through widths of each char and accumulate width of string
+ for(std::string::const_iterator i = str.begin(); i < str.end(); ++i)
+ {
+ width += widths_[static_cast(*i) - SPACE];
+ }
+
+ return width;
+}
+
+unsigned int GLFT_Font::getHeight() const
+{
+ if(!isValid())
+ {
+ throw std::logic_error("Invalid GLFT_Font::getHeight call.");
+ }
+ return height_;
+}
diff --git a/GLFT_Font.hpp b/GLFT_Font.hpp
new file mode 100644
index 0000000..208c554
--- /dev/null
+++ b/GLFT_Font.hpp
@@ -0,0 +1,112 @@
+// GLFT_Font (http://www.cs.rit.edu/~jpt2433/glftfont/)
+// by James Turk (jpt2433@rit.edu)
+// Based on work by Marijn Haverbeke (http://marijn.haverbeke.nl)
+//
+// Version 0.1 - Released 1 July 2005 - Initial Release
+// Version 0.2 - Released 18 July 2005 - Added beginDraw/endDraw,
+// Changed vsprintf to vsnprintf
+//
+// $Id: GLFT_Font.hpp,v 1.1 2005/07/18 22:19:16 cozman Exp $
+//
+// Copyright (c) 2005, James Turk
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the GLFT_Font nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+
+#ifndef GLFT_FONT_HPP
+#define GLFT_FONT_HPP
+
+#include
+
+#include
+#include FT_FREETYPE_H
+
+#include
+#include
+#include
+#include
+#include
+
+class FTLibraryContainer
+{
+public:
+ FTLibraryContainer();
+ ~FTLibraryContainer();
+
+ FT_Library& getLibrary();
+
+private:
+ static FT_Library library_;
+};
+
+class StreamFlusher { };
+std::ostream& operator<<(std::ostream& os, const StreamFlusher& rhs);
+
+class GLFT_Font
+{
+public:
+ GLFT_Font();
+ GLFT_Font(const std::string& filename, unsigned int size);
+
+ ~GLFT_Font();
+
+ void open(const std::string& filename, unsigned int size);
+ void release();
+
+ bool isValid() const;
+
+ void drawText(float x, float y, const char *str, ...) const;
+ void drawText(float x, float y, const std::string& str) const;
+
+ std::ostream& beginDraw(float x, float y);
+ StreamFlusher endDraw();
+
+ unsigned int calcStringWidth(const std::string& str) const;
+ unsigned int getHeight() const;
+
+private:
+ // leave copy constructor and operator= undefined to make noncopyable
+ GLFT_Font(const GLFT_Font&);
+ const GLFT_Font& operator=(const GLFT_Font&);
+
+private:
+ // font data
+ unsigned int texID_;
+ unsigned int listBase_;
+ std::vector widths_;
+ unsigned char height_;
+ // stream drawing stuff
+ std::ostringstream ss_;
+ float drawX_;
+ float drawY_;
+
+ static const unsigned int SPACE = 32;
+ static const unsigned int NUM_CHARS = 96;
+
+ static FTLibraryContainer library_;
+};
+
+#endif //GLFT_FONT_HPP
diff --git a/README b/README
new file mode 100644
index 0000000..bc0b3a1
--- /dev/null
+++ b/README
@@ -0,0 +1,34 @@
+// GLFT_Font (http://www.cs.rit.edu/~jpt2433/glftfont/)
+// by James Turk (jpt2433@rit.edu)
+// Based on work by Marijn Haverbeke (http://marijn.haverbeke.nl)
+//
+// Version 0.1 - Released 1 July 2005
+//
+// Copyright (c) 2005, James Turk
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the GLFT_Font nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+$Id: README,v 1.1 2005/07/18 22:19:16 cozman Exp $
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..2561f04
--- /dev/null
+++ b/index.html
@@ -0,0 +1,55 @@
+
+GLFT_Font
+
+GLFT_Font
+
+About GLFT_Font
+
+GLFT_Font is originally by James Turk
+although it is based on the work of
+Marijn Haverbeke. GLFT_Font allows
+programmers to use fonts in their OpenGL applications with great ease on any
+platform for which both FreeType2 and
+OpenGL are available.
+
+
+Obtaining GLFT_Font
+
+The latest copy of GLFT_Font will be available via this website.
+At the moment the latest version is 0.1.
+
+
+Using GLFT_Font
+
+Using GLFT_Font is designed to be extremely simple. The simplest use is:
+
+
+#include "GLFT_Font.h"
+
+...
+glEnable(GL_TEXTURE_2D);
+glEnable(GL_BLEND);
+glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+...
+Font fnt("somefont.ttf", size);
+...
+fnt.drawText(x, y, "Hello World");
+
+
+GLFT_Font also includes support for finding the width/height of a string and
+drawText supports printf-style argument formatting.
+
+
+Changelog
+
+
+
+
+
+$Id: index.html,v 1.1 2005/07/18 22:19:16 cozman Exp $
+
+
+
+
diff --git a/test.cpp b/test.cpp
new file mode 100644
index 0000000..ce0d2ad
--- /dev/null
+++ b/test.cpp
@@ -0,0 +1,53 @@
+// This file is distributed along with GLFT_Font and is in the public domain.
+// Compiled with g++ GLFT_Font.cpp test.cpp -o test -Wall -pedantic
+// -lglfw -lGL -lfreetype
+//
+// $Id: test.cpp,v 1.1 2005/07/18 22:19:16 cozman Exp $
+
+#include
+#include "GLFT_Font.hpp"
+#include
+
+int main(int argc, char** argv)
+{
+ if(argc != 2)
+ {
+ std::cerr << "Usage: test file. Where file is a valid font\n";
+ }
+ else
+ {
+ glfwInit();
+ glfwOpenWindow(800, 600, 8, 8, 8, 8, 0, 0, GLFW_WINDOW);
+
+ GLFT_Font f;
+ f.open(argv[1],24);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, 800, 600, 0, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glDisable(GL_LIGHTING);
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+
+ do
+ {
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ f.drawText(0, 0, "drawText");
+ f.drawText(f.calcStringWidth("drawText"), f.getHeight(),
+ "drawText 0x%X", 250);
+ f.beginDraw(200, 200) << "beginDraw: " << 10 << f.endDraw();
+
+ glfwSwapBuffers();
+
+ } while(glfwGetWindowParam(GLFW_OPENED) &&
+ glfwGetKey(GLFW_KEY_ESC) != GLFW_PRESS);
+
+ glfwCloseWindow();
+ glfwTerminate();
+ }
+}
+