post GLFT_Font integration, pre ResourceManagement revisions

This commit is contained in:
James Turk 2005-07-03 05:20:49 +00:00
parent fc6ce7335c
commit 5ca1c67cba
7 changed files with 428 additions and 57 deletions

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// Version:
// $Id: Font.hpp,v 1.1 2005/06/29 04:30:40 cozman Exp $
// $Id: Font.hpp,v 1.2 2005/07/03 05:20:49 cozman Exp $
#ifndef PHOTON_VIDEO_FONT_HPP
#define PHOTON_VIDEO_FONT_HPP
@ -18,6 +18,9 @@ namespace photon
namespace video
{
class StreamFlusher { };
std::ostream& operator<<(std::ostream& os, const StreamFlusher& rhs);
// Class: Font
// Simple OO wrapper around a TrueType font that can be drawn to textures and
// rendered via OpenGL.
@ -31,11 +34,31 @@ namespace video
// - ostream& << Font
class Font: public ResourceManaged<FontResourceManager>
{
// Resource Creation
public:
// Function: addResource
// Define a new named font resource, works just like
// <ResourceManaged::addResource> except that it takes a size for the font.
//
// Parameters:
// name - Name to give to font resource.
// path - Path of font file.
// size - Point size for the font.
static void addResource(const std::string& name, const std::string& path,
uint size);
// Function: addResource
// Define a new unaliased font resource (name == path). Works just like
// <ResourceManaged::addResource> except that it takes a size for the font.
//
// Parameters:.
// path - Path of font file.
// size - Point size for the font.
static void addResource(const std::string& path, uint size);
// Group: (Con/De)structors
public:
// Function: Font
// Default constructor, initalizes internal state of Font.
Font();
@ -63,21 +86,40 @@ public:
// Function: open
// Opens an TrueType font.
//
// Loading is done via FTGL.
// Loading is done via FreeType.
//
// Parameters:
// name - Name of the Font <Resource> to open.
void open(const std::string& name);
bool isValid() const;
Font& operator=(const Font &rhs);
operator bool() const;
// Group: Writing
// Group: Drawing
public:
void write(const std::string& str);
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();
// Group: Font Metrics
public:
unsigned int calcStringWidth(const std::string& str) const;
unsigned int getHeight() const;
private:
FTFont* font_;
// font data
uint texID_;
uint listBase_;
std::vector<ubyte> widths_;
ubyte height_;
// stream drawing stuff
std::ostringstream ss_;
float drawX_;
float drawY_;
};
}

View File

@ -5,15 +5,15 @@
// James Turk (jpt2433@rit.edu)
//
// Version:
// $Id: FontResourceManager.hpp,v 1.1 2005/06/29 04:30:40 cozman Exp $
// $Id: FontResourceManager.hpp,v 1.2 2005/07/03 05:20:49 cozman Exp $
#ifndef PHOTON_VIDEO_FONTRESOURCEMANAGER_HPP
#define PHOTON_VIDEO_FONTRESOURCEMANAGER_HPP
#include "ResourceManager.hpp"
#include "FTGL/FTGL.h"
#include "FTGL/FTFont.h"
#include <ft2build.h>
#include FT_FREETYPE_H
namespace photon
{
@ -23,17 +23,38 @@ namespace video
class FontResource : public Resource
{
public:
FTFont* font;
uint texID;
uint listBase;
std::vector<ubyte> widths;
ubyte height;
};
class FontResourceManager : public ResourceManager<FontResource>
{
public:
void getFontData(const std::string& name, FTFont*& font);
FontResourceManager();
~FontResourceManager();
void getFontData(const std::string& name, uint& texID, uint& listBase,
std::vector<ubyte>& widths, ubyte& height);
private:
// defined but not implemented
virtual void loadResource(FontResource &res, const std::string& name);
FontResource newResource(const std::string& name, const std::string& path,
uint size);
virtual void loadResource(FontResource &res, const std::string& name,
uint size);
virtual void freeResource(FontResource &res);
private:
FT_Library library_;
public:
static const unsigned int SPACE = 32;
static const unsigned int NUM_CHARS = 96;
};
}

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// Version:
// $Id: Texture.hpp,v 1.2 2005/06/13 07:05:28 cozman Exp $
// $Id: Texture.hpp,v 1.3 2005/07/03 05:20:49 cozman Exp $
#ifndef PHOTON_VIDEO_TEXTURE_HPP
#define PHOTON_VIDEO_TEXTURE_HPP
@ -31,7 +31,7 @@ namespace video
// - Texture = Texture
// - bool : True if texture is loaded, false if not.
// - ostream& << Texture
class Texture: public ResourceManaged<TextureResourceManager>
class Texture : public ResourceManaged<TextureResourceManager>
{
// Group: (Con/De)structors

View File

@ -5,26 +5,53 @@
// James Turk (jpt2433@rit.edu)
//
// Version:
// $Id: Font.cpp,v 1.1 2005/06/29 04:30:40 cozman Exp $
// $Id: Font.cpp,v 1.2 2005/07/03 05:20:49 cozman Exp $
#include "video/Font.hpp"
#include <string>
#include <vector>
#include <stdexcept>
#include <cstdarg>
#include <sstream>
namespace photon
{
namespace video
{
Font::Font()
{ }
Font::Font(const Font &rhs) :
ResourceManaged<FontResourceManager>(rhs)
std::ostream& operator<<(std::ostream& os, const StreamFlusher& rhs)
{
resMgr_.getFontData(getName(), font_);
return os.flush();
}
Font::Font(const std::string& name)
void Font::addResource(const std::string& name, const std::string& path,
uint size)
{
resMgr_.newResource(name,path,size);
}
void Font::addResource(const std::string& path, uint size)
{
resMgr_.newResource(path,path,size);
}
Font::Font() :
texID_(0), listBase_(0), // initalize GL variables to zero
widths_(FontResourceManager::NUM_CHARS), // make room for 96 widths
height_(0), drawX_(0), drawY_(0)
{
}
Font::Font(const Font &rhs) :
ResourceManaged<FontResourceManager>(rhs),
drawX_(0), drawY_(0)
{
resMgr_.getFontData(getName(), texID_, listBase_, widths_, height_);
}
Font::Font(const std::string& name) :
drawX_(0), drawY_(0)
{
open(name);
}
@ -32,7 +59,12 @@ Font::Font(const std::string& name)
void Font::open(const std::string& name)
{
ResourceManaged<FontResourceManager>::open(name);
resMgr_.getFontData(getName(), font_);
resMgr_.getFontData(getName(), texID_, listBase_, widths_, height_);
}
bool Font::isValid() const
{
return glIsTexture(texID_) == GL_TRUE;
}
Font& Font::operator=(const Font &rhs)
@ -40,19 +72,124 @@ Font& Font::operator=(const Font &rhs)
if(&rhs != this)
{
ResourceManaged<FontResourceManager>::operator=(rhs);
resMgr_.getFontData(getName(), font_);
resMgr_.getFontData(getName(), texID_, listBase_, widths_, height_);
}
return *this;
}
Font::operator bool() const
{
return font_ != 0;
return isValid();
}
void Font::write(const std::string& str)
void Font::drawText(float x, float y, const char *str, ...) const
{
font_->Render(str.c_str());
if(!isValid())
{
throw PreconditionException("Invalid 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)
{
// ch-SPACE = DisplayList offset
unsigned char ch( buf[i] - FontResourceManager::SPACE );
// replace characters outside the valid range with undrawable
if(ch > FontResourceManager::NUM_CHARS)
{
// last character is 'undrawable'
ch = FontResourceManager::NUM_CHARS-1;
}
glCallList(listBase_+ch); // calculate list to call
}
// Alternative, ignores undrawables (no noticable speed difference)
//glListBase(listBase_-32);
//glCallLists(static_cast<int>(std::strlen(buf)), GL_UNSIGNED_BYTE, buf);
glPopMatrix();
}
void Font::drawText(float x, float y, const std::string& str) const
{
if(!isValid())
{
throw PreconditionException("Invalid 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)
{
// ch-SPACE = DisplayList offset
unsigned char ch( *i - FontResourceManager::SPACE );
// replace characters outside the valid range with undrawable
if(ch > FontResourceManager::NUM_CHARS)
{
// last character is 'undrawable'
ch = FontResourceManager::NUM_CHARS-1;
}
glCallList(listBase_+ch); // calculate list to call
}
// Alternative, ignores undrawables (no noticable speed difference)
//glListBase(listBase_-32);
//glCallLists(static_cast<int>(std::strlen(buf)), GL_UNSIGNED_BYTE, buf);
glPopMatrix();
}
std::ostream& Font::beginDraw(float x, float y)
{
// clear the string and store the draw-position
ss_.str("");
drawX_ = x;
drawY_ = y;
return ss_;
}
StreamFlusher Font::endDraw()
{
drawText(drawX_, drawY_, ss_.str()); // draw the string
ss_.str(""); // clear the buffer
return StreamFlusher();
}
unsigned int Font::calcStringWidth(const std::string& str) const
{
if(!isValid())
{
throw PreconditionException("Invalid 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<unsigned int>(*i) -
FontResourceManager::SPACE];
}
return width;
}
unsigned int Font::getHeight() const
{
if(!isValid())
{
throw PreconditionException("Invalid Font::getHeight call.");
}
return height_;
}
}

View File

@ -5,47 +5,227 @@
// James Turk (jpt2433@rit.edu)
//
// Version:
// $Id: FontResourceManager.cpp,v 1.1 2005/06/29 04:30:40 cozman Exp $
// $Id: FontResourceManager.cpp,v 1.2 2005/07/03 05:20:49 cozman Exp $
#include "video/FontResourceManager.hpp"
#include "util/FileBuffer.hpp"
#include "FTGL/FTGLTextureFont.h"
namespace photon
{
namespace video
{
FontResourceManager::FontResourceManager()
{
if(FT_Init_FreeType(&library_) != 0)
{
throw APIError("Could not initialize FreeType2 library.");
}
}
FontResourceManager::~FontResourceManager()
{
FT_Done_FreeType(library_);
}
void FontResourceManager::getFontData(const std::string& name, FTFont*& font)
void FontResourceManager::getFontData(const std::string& name, uint& texID,
uint& listBase,
std::vector<ubyte>& widths,
ubyte& height)
{
FontResource resource( getResource(name) );
font = resource.font;
texID = resource.texID;
listBase = resource.listBase;
widths = resource.widths;
height = resource.height;
}
void FontResourceManager::loadResource(FontResource &res,
const std::string& path)
{
util::FileBuffer buf(path);
throw Error("loadResource(FontResource&, const std::string& is undefined "
" for Font. A size must be specified.");
}
FontResource FontResourceManager::newResource(const std::string& name,
const std::string& path,
uint size)
{
FontResource resource;
resource.name = name;
resource.path = path;
try
{
// attempt to load
loadResource(resource, path, size);
}
catch(ResourceException& e)
{
// rethrow any exceptions with specific information
throw ResourceException("Could not load " + path + " as " + name +
": " + e.getDesc());
}
resourceMap_[name] = resource; // add the resource to resourceMap
}
void FontResourceManager::loadResource(FontResource &res,
const std::string& path, uint size)
{
const size_t MARGIN = 3;
res.widths.resize(NUM_CHARS);
// Step 1: Open the font using FreeType //
util::FileBuffer buf(path);
std::vector<ubyte> data = buf.getData();
//res.font = new FTGLTextureFont((ubyte*)&data[0],data.size());
res.font = new FTGLTextureFont("/usr/share/fonts/truetype/freefont/FreeMono.ttf");
FT_Face face;
if(!res.font || res.font->Error() != 0)
if(FT_New_Memory_Face(library_, (ubyte*)&data[0], data.size(), 0, &face)
!= 0)
{
throw APIError("Failed to create FTGLTextureFont");
throw APIError("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 ResourceException("Invalid font: Error setting font size.");
}
assert( res.font->FaceSize(6) );
// 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);
res.widths[ch] = (face->glyph->metrics.horiAdvance >> 6) + MARGIN;
// If the line is full go to the next line
if(res.widths[ch] > lineSpace)
{
lineSpace = imageWidth - MARGIN;
++lines;
}
lineSpace -= res.widths[ch];
maxAscent = std::max(face->glyph->bitmap_top, maxAscent);
maxDescent = std::max(face->glyph->bitmap.rows -
face->glyph->bitmap_top, maxDescent);
}
res.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
res.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(res.widths[ch] > imageWidth - x)
{
x = MARGIN;
y += (maxAscent + maxDescent + MARGIN);
}
// calculate texture coordinates of the character
texX1 = static_cast<float>(x) / imageWidth;
texX2 = static_cast<float>(x+res.widths[ch]) / imageWidth;
texY1 = static_cast<float>(y - maxAscent) / imageHeight;
texY2 = texY1 + static_cast<float>(res.height) / imageHeight;
// generate the character's display list
glNewList(res.listBase + ch, GL_COMPILE);
glBegin(GL_QUADS);
glTexCoord2f(texX1,texY1); glVertex2i(0, 0);
glTexCoord2f(texX2,texY1); glVertex2i(res.widths[ch], 0);
glTexCoord2f(texX2,texY2); glVertex2i(res.widths[ch], res.height);
glTexCoord2f(texX1,texY2); glVertex2i(0, res.height);
glEnd();
glTranslatef(res.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 += res.widths[ch];
}
// generate the OpenGL texture from the byte array
glGenTextures(1, &res.texID);
glBindTexture(GL_TEXTURE_2D, res.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 FontResourceManager::freeResource(FontResource &res)
{
delete res.font;
if(glIsList(res.listBase))
{
glDeleteLists(res.listBase, NUM_CHARS);
}
if(glIsTexture(res.texID))
{
glDeleteTextures(1, &res.texID);
}
}
}

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// Version:
// $Id: VideoCore.cpp,v 1.6 2005/06/29 04:30:40 cozman Exp $
// $Id: VideoCore.cpp,v 1.7 2005/07/03 05:20:49 cozman Exp $
#include "video/VideoCore.hpp"
@ -13,7 +13,6 @@
#include "GL/gl.h"
#include "GL/glu.h"
#include "FTGL/FTLibrary.h"
namespace photon
{
@ -25,7 +24,6 @@ VideoCore::VideoCore() :
viewportWidth_(0), viewportHeight_(0)
{
initOpenGL();
FTLibrary::Instance().Error(); // ignoring error, fix this
}
VideoCore::~VideoCore()

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// Version:
// $Id: Font_test.cpp,v 1.1 2005/06/29 04:30:40 cozman Exp $
// $Id: Font_test.cpp,v 1.2 2005/07/03 05:20:49 cozman Exp $
#include "photon.hpp"
using namespace photon;
@ -34,7 +34,7 @@ public:
font.open("font");
}
void update()
{
static double t=0;
@ -48,17 +48,10 @@ public:
video.clear();
glColor4ub(255,0,0,255);
glEnable(GL_TEXTURE_2D);
glScaled(1.0/.75,1,1);
font.write("he");
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex2f(150,200);
glTexCoord2f(1,0); glVertex2f(300,350);
glTexCoord2f(1,1); glVertex2f(150,300);
glTexCoord2f(0,1); glVertex2f(200,350);
glEnd();
glColor4ub(255,255,255,255);
font.drawText(0, 0, "Photon");
font.drawText(font.calcStringWidth("Photon"), font.getHeight(),
"FPS: %.0f", app.getFramerate() );
font.beginDraw(200, 200) << "another font" << font.endDraw();
}
private: