diff --git a/asteroids/View.cc b/asteroids/View.cc index d146067..8736690 100644 --- a/asteroids/View.cc +++ b/asteroids/View.cc @@ -556,6 +556,7 @@ void View::DrawUiHighscore() { unsigned int entry_length = 32; float char_width, height; DrawGLStringMeasure ("M", &char_width, &height); + height = fabsf(height); float entry_width = fabsf(char_width * entry_length); float x = screen_right * 0.5 - entry_width * 0.5; float y = screen_bottom * 0.5 - 8 - 128; @@ -580,7 +581,7 @@ void View::DrawUiHighscore() { DrawHighscoreEntry ( x, y, entry_width, highscore_iter->name, highscore_iter->points); // go down one line - y += 20; + y += height * 1.3; i++; highscore_iter++; diff --git a/data/levels/level1.txt b/data/levels/level1.txt index 8cc0c17..dd8f5e2 100644 --- a/data/levels/level1.txt +++ b/data/levels/level1.txt @@ -2,4 +2,5 @@ # GameEntityTypeShip 1 0 0 0 0 90 0 0 0 0 0 GameEntityTypeAsteroid 0 7 0 -3 0 0 0 0.6 0 -0.1 -10 -GameEntityTypeAsteroid 0 -5 0 1 0 0 0 0.3 0 0.4 5 +GameEntityTypeAsteroid 0 -5 0 1 0 0 0 0.3 0 0.4 5 +GameEntityTypeAsteroid 0 -2 0 3 0 0 3 0.1 0 0.7 5 diff --git a/engine/SoundBase.cc b/engine/SoundBase.cc index d52baa9..2790ee2 100644 --- a/engine/SoundBase.cc +++ b/engine/SoundBase.cc @@ -52,7 +52,7 @@ int SoundBase::OnInit(int argc, char* argv[]) { LogDebug("Sound Init"); if (Mix_OpenAudio (audio_rate, audio_format, audio_channels, audio_buffers)) { - LogError ("Unable to initialize the sound system!"); + LogError ("Unable to initialize the sound system! Error message: %s", SDL_GetError()); } Mix_QuerySpec (&audio_rate, &audio_format, &audio_channels); diff --git a/engine/libraries/oglft/CMakeLists.txt b/engine/libraries/oglft/CMakeLists.txt index fa0b50d..bbc3990 100644 --- a/engine/libraries/oglft/CMakeLists.txt +++ b/engine/libraries/oglft/CMakeLists.txt @@ -7,6 +7,8 @@ Set( CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake ) FIND_PACKAGE( OpenGL REQUIRED ) FIND_PACKAGE( FreeType2 REQUIRED ) +INCLUDE_DIRECTORIES (${PROJECT_SOURCE_DIR}/liboglft) + IF( ENABLE_QT ) FIND_PACKAGE( QT REQUIRED ) IF( DESIRED_QT_VERSION EQUAL 3 ) diff --git a/engine/libraries/oglft/liboglft/OGLFT.h b/engine/libraries/oglft/liboglft/OGLFT.h new file mode 100644 index 0000000..5852a47 --- /dev/null +++ b/engine/libraries/oglft/liboglft/OGLFT.h @@ -0,0 +1,2321 @@ +// -*- c++ -*- +/* + * OGLFT: A library for drawing text with OpenGL using the FreeType library + * Copyright (C) 2002 lignum Computing, Inc. + * $Id: OGLFT.h.cmake 107 2008-04-25 09:29:24Z brevilo $ + * + * This library 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.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef OGLFT_H +#define OGLFT_H + +// CMake activates these definitions. +/* #undef ENABLE_QT */ +/* #undef ENABLE_GLE */ +/* #undef GLU_TESS_CALLBACK_TRIPLEDOT */ +/* #undef HAVE_OPENGL_DIR */ +// Convert to our old options. +#if !defined(ENABLE_QT) +#define OGLFT_NO_QT +#endif +#if !defined(ENABLE_GLE) +#define OGLFT_NO_SOLID +#endif + +#include +#include +#include +#include + +#ifdef WIN32 +#include +#endif + +#ifdef HAVE_OPENGL_DIR +#include +#include +#else +#include +#include +#endif + +#ifndef OGLFT_NO_SOLID +#ifdef HAVE_OPENGL_DIR +#include +#else +#include +#endif +#endif + +#ifndef OGLFT_NO_QT +#define OGLFT_QT_VERSION +#if OGLFT_QT_VERSION == 3 +#include +#include +#elif OGLFT_QT_VERSION == 4 +#include +#include +#endif +#endif + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include FT_OUTLINE_H +#include FT_TRIGONOMETRY_H + +#ifdef _MSC_VER +#ifdef OGLFT_BUILD +#define OGLFT_API __declspec(dllexport) +#else +#define OGLFT_API __declspec(dllimport) +#endif +#else +#define OGLFT_API +#endif + +//! All of OGLFT C++ objects are in this namespace. + +namespace OGLFT { + + //! Thanks to DesCartes, I'd consider these manifest constants. + enum Coordinates { + X, //!< The X component of space + Y, //!< The Y component of space + Z, //!< The Z component of space + W //!< The projection component of space + }; + + //! Who to credit? Newton? I'd consider these manifest constants. + enum ColorSpace { + R, //!< The Red component of a color + G, //!< The Green component of a color + B, //!< The Blue component of a color + A, //!< The Alpha (or transparency) of a color + }; + + //! Callback from GLU tessellation routines. +#ifdef GLU_TESS_CALLBACK_TRIPLEDOT + typedef GLvoid (*GLUTessCallback)(...); +#else + typedef GLvoid (*GLUTessCallback)(); +#endif + + //! The FreeType library instance. + /*! + * The FreeType library has a single, global instance of a library + * handle. This reference is used to load font faces. This detail + * is generally hidden from the user of OGLFT, however, it + * can be useful to get the FT_Library instance if you want to open + * a font file yourself, either from disk or embedded in the program. + */ + class Library { + public: + /*! + * The FreeType library's library handle is only available through this + * accessor method. + * \return the global OGLFT FreeType library handle. + */ + static OGLFT_API FT_Library& instance ( void ); + + protected: + /*! + * The constructor for this class is automatically called when + * this library is loaded. Access the instance through the instance() + * method. + */ + OGLFT_API Library ( void ); + /*! + * This destructor is automatically called when the program exits. + */ + OGLFT_API ~Library( void ); + + private: + static Library library; + static FT_Library library_; + }; + + //! Advance describes the "advance" of a glyph, namely the distance in + //! model space at which the NEXT glyph should be drawn. This class exists + //! to assist the computation of string metrics. + struct OGLFT_API Advance { + float dx_; //!< Advance increment in the X direction. + float dy_; //!< Advance increment in the Y direction. + + //! Default constructor. An otherwise uninitialized Advance contains zeros. + Advance ( float dx = 0, float dy = 0 ) : dx_( dx ), dy_( dy ) + {} + + //! Initialize an advance from a FreeType advance member. + Advance ( FT_Vector v ) + { + dx_ = v.x / 64.f; + dy_ = v.y / 64.f; + } + + //! Increment Advance with a FreeType advance member. + //! \return a reference to oneself. + Advance& operator+= ( const FT_Vector v ) + { + dx_ += v.x / 64.f; + dy_ += v.y / 64.f; + return *this; + } + }; + + //! Describe the metrics of a glyph or string relative to the origin + //! of the first character + struct OGLFT_API BBox { + float x_min_; //!< The left-most position at which "ink" appears. + float y_min_; //!< the bottom-most position at which "ink" appears. + float x_max_; //!< The right-most position at which "ink" appears. + float y_max_; //!< The top-most position at which "ink" appears. + Advance advance_; //!< The (total) advancement + + //! Default constructor is all zeros. + BBox () : x_min_( 0 ), y_min_( 0 ), x_max_( 0 ), y_max_( 0 ) + {} + + /*! + *(Partially) initialize a BBox from a FreeType bounding box member. + *(The advancement is initialized to zero by its default constructor). + * \param ft_bbox a FreeType bounding box as retrieved from + * \c FT_Glyph_Get_CBox. + */ + BBox ( FT_BBox ft_bbox ) + { + x_min_ = ft_bbox.xMin / 64.f; + y_min_ = ft_bbox.yMin / 64.f; + x_max_ = ft_bbox.xMax / 64.f; + y_max_ = ft_bbox.yMax / 64.f; + } + + //! Scale the bounding box by a constant. + //! \param k a constant to scale the bounding box by. + //! \return a reference to oneself. + BBox& operator*= ( float k ) + { + x_min_ *= k; + y_min_ *= k; + x_max_ *= k; + y_max_ *= k; + advance_.dx_ *= k; + advance_.dy_ *= k; + + return *this; + } + + /*! + * Merge a bounding box into the current one (not really addition). + * Each time a BBox is "added", the current BBox is expanded to include + * the metrics of the new BBox. May only work for horizontal fonts, though. + * \param b the bounding box to merge. + * \return a reference to oneself. + */ + BBox& operator+= ( const BBox& b ) + { + float new_value; + + new_value = b.x_min_ + advance_.dx_; + if ( new_value < x_min_ ) x_min_ = new_value; + + new_value = b.y_min_ + advance_.dy_; + if ( (b.advance_.dy_ != 0.) && new_value < y_min_ ) y_min_ = new_value; + + new_value = b.x_max_ + advance_.dx_; + if ( new_value > x_max_ ) x_max_ = new_value; + + new_value = b.y_max_ + advance_.dy_; + if ( (b.advance_.dy_ != 0.) && new_value > y_max_ ) y_max_ = new_value; + + advance_.dx_ += b.advance_.dx_; + advance_.dy_ += b.advance_.dy_; + + return *this; + } + }; + + //! During tesselation of a polygonal Face (outline, filled or solid), + //! an object which implements this interface can be used to compute a + //! different color for each vertex. + class OGLFT_API ColorTess { + public: + virtual ~ColorTess ( void ) {} + //! Compute a color for this position. Note that the position is + //! in the glyph's local coordinate system. + //! \param p vertex position in glyph's local coordinate system. Argument is + //! a GLdouble[3]. + //! \return GLfloat[4] (RGBA) color specification. + virtual GLfloat* color ( GLdouble* p ) = 0; + }; + + //! During tesselation of a polygonal Face (outline, filled or solid), + //! an object which implements this interface can be used to compute a + //! different texture coordinate for each vertex. + class OGLFT_API TextureTess { + public: + virtual ~TextureTess ( void ) {} + //! Compute a texture coordinate for this position. Note that the + //! position is in the glyph's local coordinate system. + //! \param p vertex position in glyph's local coordinate system. Argument is + //! a GLdouble[3]. + //! \return GLfloat[2] (s,t) texture coordinates. + virtual GLfloat* texCoord ( GLdouble* p ) = 0; + }; + + //! The argument to setCharacterDisplayLists is an STL vector of + //! OpenGL display list names (GLuints). + typedef std::vector DisplayLists; + + //! A convenience definition of an iterator for display list vectors. + typedef DisplayLists::const_iterator DLCI; + + //! A convenience definition of an iterator for display list vectors. + typedef DisplayLists::iterator DLI; + + //! A face (aka font) used to render text with OpenGL. + /*! + * This is an abstract class, but it does define most the functions that + * you are likely to call to manipulate the rendering of the text. + */ + class Face { + public: + //! Thanks to the standard formerly known as PHIGS. Horizontal text + //! justification constants. + enum OGLFT_API HorizontalJustification { + LEFT, //!< Left justified justification of text + ORIGIN, //!< Natural origin alignment of text (default) + CENTER, //!< Center justified alignment of text + RIGHT //!< Right justified alignment of text + }; + + //! Thanks to the standard formerly known as PHIGS. Vertical text + //! justification constants. + enum OGLFT_API VerticalJustification { + BOTTOM, //!< Descender alignment of text + BASELINE, //!< Baseline alignment of text (default) + MIDDLE, //!< Centered alignment of text + TOP //!< Ascender justification of text + }; + + //! Control how OpenGL display lists are created for individual glyphs. + //! The default mode is to create display lists for each glyph as it + //! is requested. Therefore, the Face drawing routines cannot themselves + //! be called from within an open display list. In IMMEDIATE mode, + //! cached glyphs will be drawn if available, otherwise the FreeType + //! data for a glyph is re-rendered each time. + enum OGLFT_API GlyphCompileMode { + COMPILE, //!< Compile new glyphs when seen for the first time. + IMMEDIATE //!< Do not \em create display lists for glyphs. + }; + + private: + //! We allow a Face to be constructed either from a file name + //! or passed in as an already opened FreeType FT_Face. In the case + //! of the later (already opened), we don't close the FT_Face on + //! destruction. This way you can share FT_Faces between related + //! OGLFT faces. Also, we're experimenting with being able to use + //! multiple FT_Faces in a single OGLFT Face, so this is represented + //! as a data structure. + struct FaceData { + FT_Face face_; + bool free_on_exit_; + FaceData ( FT_Face face, bool free_on_exit = true ) + : face_( face ), free_on_exit_( free_on_exit ) + {} + }; + protected: + //! The FreeType face - experimentally, this is now an array of + //! faces so that we can handle a wider range of UNICODE points + //! in case a face doesn't cover the points of interest. + std::vector< FaceData > faces_; + + //! Did a font load OK? + bool valid_; + + //! Glyph display list creation mode. + enum GlyphCompileMode compile_mode_; + + //! Nominal point size. + float point_size_; + + //! Display resolution in pixels per inch. + FT_UInt resolution_; + + //! Does rendering text affect the MODELVIEW matrix? + bool advance_; + + //! Foreground color (I really wanted to avoid this, but not really + //! possible without state queries, which you can't put into + //! display lists. Anyway, you'll be able to get even more fancy + //! by passing in a function to map the color with, so why balk at + //! this?) + GLfloat foreground_color_[4]; + + //! Background color (what modes would use this?) + GLfloat background_color_[4]; + + //! PHIGS-like horizontal positioning of text. + enum HorizontalJustification horizontal_justification_; + + //! PHIGS-like vertical positioning of text. + enum VerticalJustification vertical_justification_; + + //! Rotate an entire string in the Z plane + GLfloat string_rotation_; + + //! Let the user decide which character to use as the rotation reference. + //! Use "o" by default, I suppose. + FT_UInt rotation_reference_glyph_; + + //! The rotation reference character could be in any face. + FT_Face rotation_reference_face_; + + //! These are the translation offsets provided by the rotation reference + //! character; for whom, we've discovered, only the Y position is relevant. + GLfloat rotation_offset_y_; + + //! Type of the cache of defined glyph to display list mapping. + typedef std::map< FT_UInt, GLuint > GlyphDLists; + + //! A convenience definition of the iterator over the glyph to display + //! list map. + typedef GlyphDLists::const_iterator GDLCI; + + //! A convenience definition of the iterator over the glyph to display + //! list map. + typedef GlyphDLists::iterator GDLI; + + //! Cache of defined glyph display lists + GlyphDLists glyph_dlists_; + + //! The user can supply an array of display list which are invoked + //! before each glyph is rendered. + DisplayLists character_display_lists_; + + public: + /*! + * Construct a Face by loading a font from the given file. + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + Face ( const char* filename, float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * Construct a Face by loading a font from the given memory location. + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + Face ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * Alternatively, the user may have already opened a face and just + * wants to draw with it. This is useful for Multiple Master fonts or + * combining multiple files to increase UNICODE point coverage. + * \param face open Freetype FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + Face ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * Deleting a Face frees its FreeType face (and anything else it's + * styles have allocated). + */ + virtual ~Face ( void ); + + /*! + * Let the user test to see if the font was loaded OK. + * \return true if the FT_Face was successfully created. + */ + bool isValid ( void ) const { return valid_; } + + /*! + * Add another FT_Face to the OGLFT Face. Generally used to add more + * coverage of UNICODE points (at least that's the plan). This + * routine takes a filename and takes ownership of the FT_Face. + * \param filename name of file containing font face data. + * \return true if face was successfully added. + */ + bool addAuxiliaryFace ( const char* filename ); + + /*! + * Add another FT_Face to the OGLFT Face. Generally used to add more + * coverage of UNICODE points (at least that's the plan). This + * routine takes a memory location and takes ownership of the FT_Face. + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \return true if face was successfully added. + */ + bool addAuxiliaryFace ( const FT_Byte* data_base, const FT_Long data_size ); + + /*! + * Add another FT_Face to the OGLFT Face. Generally used to add more + * coverage of UNICODE points (at least that's the plan). This + * routine takes an already open FT_Face. The user is responsible + * for clean up. + * \param face open FreeType FT_Face + * \return true if face was successfully added. + */ + bool addAuxiliaryFace ( FT_Face face ); + + /*! + * By default, each time a new character is seen, its glyph is rendered + * into a display list. This means that a display list cannot already + * be open (since OpenGL doesn't allow nested display list creation). + * Rendering can be set into immediate mode in which case glyphs are + * rendered from display lists if available, but are otherwise generated + * anew each time. + * \param compile_mode the new compile mode. + */ + void setCompileMode ( enum GlyphCompileMode compile_mode ) + { + compile_mode_ = compile_mode; + } + + /*! + * \return the current glyph compile mode. + */ + enum GlyphCompileMode compileMode ( void ) const { return compile_mode_; } + + /*! + * For the rasterized styles (Monochrome, Grayscale, Translucent, Texture), + * glyphs are rendered at the pixel size given by: + * + * point_size [pts] * / 72 [pts/in] * resolution [dots/in] = [dots]. + * + * For the polygon styles (Outline, Filled, Solid), the "nominal" size of + * the glyphs is: + * + * point_size[pts] / 72 [pts/in] * resolution [dots/in] + * / units_per_EM [font unit/EM] = [dots * EM]. + * + * If the MODELVIEW and PROJECTION matrices are such that one screen pixel + * corresponds to one modeling unit, then polygonal Faces will + * be the same size as raster Faces. + * + * Note that changing the point size after Face creation will invalidate + * the cache of OpenGL display lists and any other information which + * the individual styles have cached. + * \param point_size the new point size in points (1/72-th inch). + */ + void setPointSize ( float point_size ); + + /*! + * \return the current point size. + */ + float pointSize ( void ) { return point_size_; } + + /*! + * For the rasterized styles (Monochrome, Grayscale, + * Translucent, Texture), the exact rendered size of the glyphs depends on + * the resolution of the display (as opposed to the polygon styles + * whose size is controlled by the viewing matrices). The Texture + * style is slightly different because the glyphs are texture-mapped + * onto an arbitrary rectangle; here, the resolution only controls + * how accurately the glyph is rendered. + * \param resolution the resolution in DPI (dots per inch). + */ + void setResolution ( FT_UInt resolution ); + + /*! + * \return the current raster resolution. + */ + FT_UInt resolution ( void ) { return resolution_; } + + /*! + * If advance is true, then the changes made to the MODELVIEW matrix + * to render a string are allowed to remain. Otherwise, the library + * pushes the current MODELVIEW matrix onto the matrix stack, renders + * the string and then pops it off again. Rendering a character always + * modifies the MODELVIEW matrix. + * \param advance whether or not the MODELVIEW matrix should be left + * translated by the advancement of a rendered string. + */ + void setAdvance ( bool advance ) { advance_ = advance; } + + /*! + * \return the advance value. + */ + bool advance ( void ) const { return advance_; } + + /*! + * This is the nominal color of the glyphs. A lot of other things + * can alter what you actually see! Note that changing the foreground + * color invalidates the glyph cache. + * \param red the red component of the foreground color. + * \param green the green component of the foreground color. + * \param blue the blue component of the foreground color. + * \param alpha the alpha component of the foreground color. + */ + void setForegroundColor ( GLfloat red = 0.0, + GLfloat green = 0.0, + GLfloat blue = 0.0, + GLfloat alpha = 1.0 ); + + /*! + * This is the nominal color of the glyphs. A lot of other things + * can alter what you actually see! Note that changing the foreground + * color invalidates the glyph cache. + * \param foreground_color an array of 4 values corresponding to the + * red, green, blue and alpha components of the foreground color. + */ + void setForegroundColor ( const GLfloat foreground_color[4] ); +#ifndef OGLFT_NO_QT + /*! + * This is the nominal color of the glyphs. A lot of other things + * can alter what you actually see! Note that changing the foreground + * color invalidates the glyph cache. + * \param foreground_color the foreground color as an unsigned int. + */ + void setForegroundColor ( const QRgb foreground_color ); +#endif /* OGLFT_NO_QT */ + /*! + * \return the red component of the foreground color + */ + GLfloat foregroundRed ( void ) const { return foreground_color_[R]; } + /*! + * \return the green component of the foreground color + */ + GLfloat foregroundGreen ( void ) const { return foreground_color_[G]; } + /*! + * \return the blue component of the foreground color + */ + GLfloat foregroundBlue ( void ) const { return foreground_color_[B]; } + /*! + * \return the alpha component of the foreground color + */ + GLfloat foregroundAlpha ( void ) const { return foreground_color_[A]; } + + /*! + * This is the nominal background color of the glyphs. A lot of other things + * can alter what you actually see! Note that changing the background + * color invalidates the glyph cache. + * \param red the red component of the background color. + * \param green the green component of the background color. + * \param blue the blue component of the background color. + * \param alpha the alpha component of the background color. + */ + void setBackgroundColor ( GLfloat red = 1.0, + GLfloat green = 1.0, + GLfloat blue = 1.0, + GLfloat alpha = 0.0 ); + + /*! + * This is the nominal background color of the glyphs. A lot of other things + * can alter what you actually see! Note that changing the background + * color invalidates the glyph cache. + * \param background_color an array of 4 values corresponding to the + * red, green, blue and alpha components of the background color. + */ + void setBackgroundColor ( const GLfloat background_color[4] ); +#ifndef OGLFT_NO_QT + /*! + * This is the nominal background color of the glyphs. A lot of other things + * can alter what you actually see! Note that changing the background + * color invalidates the glyph cache. + * \param background_color the background color as an unsigned int. + */ + void setBackgroundColor ( const QRgb background_color ); +#endif /* OGLFT_NO_QT */ + /*! + * \return the red component of the background color + */ + GLfloat backgroundRed ( void ) const { return background_color_[R]; } + /*! + * \return the green component of the background color + */ + GLfloat backgroundGreen ( void ) const { return background_color_[G]; } + /*! + * \return the blue component of the background color + */ + GLfloat backgroundBlue ( void ) const { return background_color_[B]; } + /*! + * \return the alpha component of the background color + */ + GLfloat backgroundAlpha ( void ) const { return background_color_[A]; } + + /*! + * Set the individual character rotation in the Z direction. + * \param character_rotation_z angle in degrees of z rotation. + */ + virtual void setCharacterRotationZ ( GLfloat character_rotation_z ) = 0; + + /*! + * \return the character rotation in the Z direction. + */ + virtual GLfloat characterRotationZ ( void ) const = 0; + + /*! + * The z rotation angle needs a center. Nominate a character whose + * center is to be the center of rotation. By default, use "o". + * \param c rotation reference character. + */ + void setCharacterRotationReference ( unsigned char c ); + + /*! + * Rotate an entire string through the given angle (in the Z plane only). + * (Somewhat pointless for the vector styles since you can do mostly + * the same thing with the MODELVIEW transform, however, for what its + * worth, this routine uses the FreeType rotation function to compute + * the "proper" metrics for glyph advance.) + * \param string_rotation angle in degrees of z rotation. + */ + void setStringRotation ( GLfloat string_rotation ); + + /*! + * \return the (Z plane) string rotation angle. + */ + GLfloat stringRotation ( void ) const { return string_rotation_; } + + /*! + * Set the horizontal justification. + * \param horizontal_justification the new horizontal justification. + */ + void setHorizontalJustification ( enum HorizontalJustification + horizontal_justification ) + { + horizontal_justification_ = horizontal_justification; + } + + /*! + * \return the horizontal justification. + */ + enum HorizontalJustification horizontalJustification ( void ) const + { return horizontal_justification_; } + + /*! + * Set the vertical justification. + * \param vertical_justification the new vertical justification + */ + void setVerticalJustification ( enum VerticalJustification + vertical_justification ) + { + vertical_justification_ = vertical_justification; + } + + /*! + * \return the vertical justification. + */ + enum VerticalJustification verticaljustification ( void ) + const { return vertical_justification_; } + + /*! + * Specify an OpenGL display list to be invoked before + * each character in a string. Face makes a copy of the argument. Pass + * an empty DisplayLists to disable this feature. + * \param character_display_lists STL vector containing a display + * list to invoke before each glyph in a string is drawn. + */ + void setCharacterDisplayLists ( const DisplayLists& character_display_lists ) + { + character_display_lists_ = character_display_lists; + } + + /*! + * \return a reference to the array of character display lists. This is + * the live list as stored in the Face. + */ + DisplayLists& characterDisplayLists ( void ) + { return character_display_lists_; } + + /*! + * \return the height (i.e., line spacing) at the current character size. + */ + virtual double height ( void ) const = 0; + + /*! + * Compute the bounding box info for a character. + * \param c the (latin1) character to measure. + * \return the bounding box of c. + */ + virtual BBox measure ( unsigned char c ) = 0; +#ifndef OGLFT_NO_QT + /*! + * Compute the bounding box info for a character. + * \param c the (UNICODE) character to measure. + * \return the bounding box of c. + */ + virtual BBox measure ( const QChar c ) = 0; +#endif /* OGLFT_NO_QT */ + /*! + * Compute the bounding box info for a string. + * \param s the (latin1) string to measure. + * \return the bounding box of s. + */ + virtual BBox measure ( const char* s ); + /*! + * Compute the bounding box info for a string without conversion + * to modeling coordinates. + * \param s the (latin1) string to measure. + * \return the bounding box of s. + */ + virtual BBox measureRaw ( const char* s ); +#ifndef OGLFT_NO_QT + /*! + * Compute the bounding box info for a string. + * \param s the (UNICODE) string to measure. + * \return the bounding box of s. + */ + virtual BBox measure ( const QString& s ); + /*! + * Compute the bounding box info for a real number formatted as specified. + * \param format (see draw for valid formats) + * \param number real number. + * \return the bounding box of the formatted number. + */ + virtual BBox measure ( const QString& format, double number ); + /*! + * Compute the bounding box info for a string without conversion + * to modeling coordinates. + * \param s the (UNICODE) string to measure. + * \return the bounding box of s. + */ + virtual BBox measureRaw ( const QString& s ); +#endif /* OGLFT_NO_QT */ + /*! + * Compile a string into an OpenGL display list for later + * rendering. Essentially, the string is rendered at the origin + * of the current MODELVIEW. Note: no other display lists should + * be open when this routine is called. Also, the Face does not + * keep track of these lists, so you must delete them in order + * to recover the memory. + * \param s the (latin1) string to compile. + * \return the display list name for the string. + */ + GLuint compile ( const char* s ); +#ifndef OGLFT_NO_QT + /*! + * Compile a string into an OpenGL display list for later + * rendering. Essentially, the string is rendered at the origin + * of the current MODELVIEW. Note: no other display lists should + * be open when this routine is called. Also, the Face does not + * keep track of these lists, so you must delete them in order + * to recover the memory. + * \param s the (UNICODE) string to compile. + * \return the display list name for the string. + */ + GLuint compile ( const QString& s ); +#endif /* OGLFT_NO_QT */ + /*! + * Compile a single character (glyph) into an OpenGL display list + * for later rendering. The Face \em does keep track of these + * display lists, so do not delete them. + * \param c the (latin1) character to compile. + * \return the display list name for the character. + */ + GLuint compile ( unsigned char c ); +#ifndef OGLFT_NO_QT + /*! + * Compile a single character (glyph) into an OpenGL display list + * for later rendering. The Face \em does keep track of these + * display lists, so do not delete them. + * \param c the (UNICODE) character to compile. + * \return the display list name for the character. + */ + GLuint compile ( const QChar c ); +#endif /* OGLFT_NO_QT */ + /*! + * Draw a (latin1) string using the current MODELVIEW matrix. If + * advance is true, then the final glyph advance changes to the + * MODELVIEW matrix are left in place. + * \param s the (latin1) string to draw. + */ + void draw ( const char* s ); +#ifndef OGLFT_NO_QT + /*! + * Draw a (UNICODE) string using the current MODELVIEW + * matrix. If advance is true, then the final glyph advance + * changes to the MODELVIEW matrix are left in place. + * \param s the (UNICODE) string to draw. + */ + void draw ( const QString& s ); +#endif /* OGLFT_NO_QT */ + /*! + * Draw the character using the current MODELVIEW matrix. Note that + * the MODELVIEW matrix is modified by the glyph advance. Draw a + * string if you don't want the MODELVIEW matrix changed. + * \param c the (latin1) character to draw. + */ + void draw ( unsigned char c ); + +#ifndef OGLFT_NO_QT + /*! + * Draw the character using the current MODELVIEW matrix. Note that + * the MODELVIEW matrix is modified by the glyph advance. Draw a + * string if you don't want the MODELVIEW matrix changed. + * \param c the (UNICODE) character to draw. + */ + void draw ( const QChar c ); +#endif /* OGLFT_NO_QT */ + /*! + * Draw the (latin1) character at the given 2D point. Note that + * the MODELVIEW matrix is modified by the glyph advance. Draw + * a string if you don't want the MODELVIEW matrix changed. + * \param x the X position. + * \param y the Y position. + * \param c the (latin1) character to draw. + */ + void draw ( GLfloat x, GLfloat y, unsigned char c ); + /*! + * Draw the (latin1) character at the given 3D point. Note that + * the MODELVIEW matrix is modified by the glyph advance. Draw + * a string if you don't want the MODELVIEW matrix changed. + * \param x the X position. + * \param y the Y position. + * \param z the Z position. + * \param c the (latin1) character to draw. + */ + void draw ( GLfloat x, GLfloat y, GLfloat z, unsigned char c ); +#ifndef OGLFT_NO_QT + /*! + * Draw the (UNICODE) character at the given 2D point. Note that + * the MODELVIEW matrix is modified by the glyph advance. Draw + * a string if you don't want the MODELVIEW matrix changed. + * \param x the X position. + * \param y the Y position. + * \param c the (UNICODE) character to draw. + */ + void draw ( GLfloat x, GLfloat y, QChar c ); + /*! + * Draw the (UNICODE) character at the given 3D point. Note that + * the MODELVIEW matrix is modified by the glyph advance. Draw + * a string if you don't want the MODELVIEW matrix changed. + * \param x the X position. + * \param y the Y position. + * \param z the Z position. + * \param c the (UNICODE) character to draw. + */ + void draw ( GLfloat x, GLfloat y, GLfloat z, QChar c ); +#endif /* OGLFT_NO_QT */ + /*! + * Draw a string at the given 2D point. + * \param x the X position. + * \param y the Y position. + * \param s the (latin1) string to draw. + */ + void draw ( GLfloat x, GLfloat y, const char* s ); + /*! + * Draw a string at the given 3D point. + * \param x the X position. + * \param y the Y position. + * \param z the Z position. + * \param s the (latin1) string to draw. + */ + void draw ( GLfloat x, GLfloat y, GLfloat z, const char* s ); +#ifndef OGLFT_NO_QT + /*! + * Draw a string at the given 2D point. + * \param x the X position. + * \param y the Y position. + * \param s the (UNICODE) string to draw. + */ + void draw ( GLfloat x, GLfloat y, const QString& s ); + /*! + * Draw a string at the given 3D point. + * \param x the X position. + * \param y the Y position. + * \param z the Z position. + * \param s the (UNICODE) string to draw. + */ + void draw ( GLfloat x, GLfloat y, GLfloat z, const QString& s ); + /*! + * Draw a real number per the given format at the given 2D point. + * \param x the X position. + * \param y the Y position. + * \param format Like a typical printf format. Regular text is printed + * while a '%' introduces the real number's format. Includes the + * following format flags: + * \li %%x.yf - floating point in field width x and precision y + * \li %%x.ye - scientific notation in field width x and precision y + * \li %%x.yg - pick best floating or scientific in field width x and + * precision y + * \li %%p - draw as a proper fraction, e.g. 1 1/2. Note: this currently + * requires a special font which encodes glyphs to be drawn for the + * numerator and demoninator in the UNICODE Private Area (0xE000). + * + * \param number the numeric value. + */ + void draw ( GLfloat x, GLfloat y, const QString& format, double number ); + /*! + * Draw a real number per the given format at the given 3D point. + * \param x the X position. + * \param y the Y position. + * \param z the Z position. + * \param format Like a typical printf format. Regular text is printed + * while a '%' introduces the real number's format. Includes the + * following format flags: + * \li %%x.yf - floating point in field width x and precision y + * \li %%x.ye - scientific notation in field width x and precision y + * \li %%x.yg - pick best floating or scientific in field width x and + * precision y + * \li %%p - draw as a proper fraction, e.g. 1 1/2. Note: this currently + * requires a special font which encodes glyphs to be drawn for the + * numerator and demoninator in the UNICODE Private Area (0xE000). + * + * \param number the numeric value. + */ + void draw ( GLfloat x, GLfloat y, GLfloat z, const QString& format, + double number ); +#endif /* OGLFT_NO_QT */ + /*! + * \return the face ascender, in point units. + */ + int ascender ( void ); + + /*! + * \return the face descender, in point units. + */ + int descender ( void ); + + protected: + // The various styles override these routines + + //! Some styles, in particular the Texture, need specialized steps + //! to compile a glyph into an OpenGL display list. + //! \param face the FT_Face containing the glyph. + //! \param glyph_index the index of the glyph in face. + //! \return the display list of the compiled glyph. + virtual GLuint compileGlyph ( FT_Face face, FT_UInt glyph_index ) = 0; + + //! Each style implements its own glyph rendering routine. + //! \param face the FT_Face containing the glyph. + //! \param glyph_index the index of the glyph in face. + virtual void renderGlyph ( FT_Face face, FT_UInt glyph_index ) = 0; + + //! There is a slight different between the way in which the polygonal + //! and raster styles select the character size for FreeType to generate. + virtual void setCharSize ( void ) = 0; + + //! The different styles have different caching needs (well, really only + //! the texture style currently has more than the display list cache). + virtual void clearCaches ( void ) = 0; + + //! The polygonal and raster styles compute different values for the + //! Z rotation offset. (It's in integer pixels for the raster styles and + //! in floating point pixels for the polygonal styles.) + virtual void setRotationOffset ( void ) = 0; + + private: + void init ( void ); + BBox measure_nominal ( const char* s ); +#ifndef OGLFT_NO_QT + BBox measure_nominal ( const QString& s ); + QString format_number ( const QString& format, double number ); +#endif /* OGLFT_NO_QT */ + }; + + //! This is the base class of the polygonal styles: outline, filled and solid. + /*! + * In the polygonal styles, the detailed geometric outlines of the glyphs + * are extracted from the font file and rendered as polygons. + */ + class Polygonal : public Face { + protected: + //! Angle of rotation of characters relative to text orientation. + struct { + bool active_; + GLfloat x_, y_, z_; + } character_rotation_; + + //! The tessellation of curves is pretty crude; regardless of length, + //! use the same number of increments (and as near as I can tell, this + //! is more than sufficient unless the glyph takes up the whole screen). + unsigned int tessellation_steps_; + + //! When curves are tessellated, we use the forward difference algorithm + //! from Foley and van Dam for parametric curves (pg. 511 of 2nd Ed. in C). + //! So, the step size, delta, is in the parametric variable which is always + //! on the interval [0,1]. Therefore, delta = 1/tessellation_steps + double delta_, delta2_, delta3_; + + //! For vector rendition modes, FreeType is allowed to generate the + //! lines and arcs at the original face definition resolution. To + //! get to the proper glyph size, the vertices are scaled before + //! they're passed to the GLU tessellation routines. + float vector_scale_; + + //! Callbacks for FreeType glyph decomposition into outlines + FT_Outline_Funcs interface_; + + //! Default number of steps to break TrueType and Type1 arcs into. + //! (Note: this looks good to me, anyway) + static const unsigned int DEFAULT_TESSELLATION_STEPS = 4; + + /*! + * VertexInfo is a private class which is used by the decomposition and + * tessellation routines to store the vertices and other data of the glyph's + * outline. Because of the "impedance mismatch" between the crazy + * 26.6 fixed point format of the FreeType library (well, don't + * blame them; look at what they have to work with) and OpenGL's preference + * for double precision, this simple vector has two constructors: one + * for 26.6 format and one for direct floating point. + * + * VertexInfo also contains (optional) pointers to objects which + * implement the ColorTess and TextureTess interfaces. + */ + struct VertexInfo { + double v_[3]; //!< Why is this double precision? Because the second + //!< argument to the routine gluTessVertex is a pointer + //!< to an array of doubles. Otherwise, we could use + //!< single precision everywhere. + + //! The user can provide a ColorTess object which computes a color + //! for each tesselated vertex. + ColorTess* color_tess_; + + //! The user can provide a TextureTess object which computes texture + //! coordinates for each tesselated vertex. + TextureTess* texture_tess_; + + //! Default constructor just initializes Vertex to zero. + //! \param color_tess optional color tesselation object. + //! \param texture_tess optional texture tesselation object. + VertexInfo ( ColorTess* color_tess = 0, TextureTess* texture_tess = 0 ) + : color_tess_( color_tess ), texture_tess_( texture_tess ) + { + v_[X] = v_[Y] = v_[Z] = 0.; + } + + /*! + * Construct a Vertex from a point in a FreeType contour. + * \param ft_v a FreeType FT_Vector, normally passed into the + * the decomposition callbacks. + * \param color_tess optional color tesselation object. + * \param texture_tess optional texture tesselation object. + */ + VertexInfo ( FT_Vector* ft_v, ColorTess* color_tess = 0, + TextureTess* texture_tess = 0 ) + : color_tess_( color_tess ), texture_tess_( texture_tess ) + { + v_[X] = (double)( ft_v->x / 64 ) + (double)( ft_v->x % 64 ) / 64.; + v_[Y] = (double)( ft_v->y / 64 ) + (double)( ft_v->y % 64 ) / 64.; + v_[Z] = 0.; + } + + /*! + * Construct a Vertex from a 2D point. + * \param p 2D array of doubles. + * \param color_tess optional color tesselation object. + * \param texture_tess optional texture tesselation object. + */ + VertexInfo ( double p[2], ColorTess* color_tess = 0, + TextureTess* texture_tess = 0 ) + : color_tess_( color_tess ), texture_tess_( texture_tess ) + { + v_[X] = p[X]; + v_[Y] = p[Y]; + v_[Z] = 0.; + } + + /*! + * Construct a Vertex from a 2D point. + * \param x the X coordinate. + * \param y the Y coordinate. + * \param color_tess optional color tesselation object. + * \param texture_tess optional texture tesselation object. + */ + VertexInfo ( double x, double y, ColorTess* color_tess = 0, + TextureTess* texture_tess = 0 ) + : color_tess_( color_tess ), texture_tess_( texture_tess ) + { + v_[X] = x; + v_[Y] = y; + v_[Z] = 0.; + } + + //! Treat the Vertex like a vector: Normalize its length in the + //! usual way. + void normalize ( void ) + { + double length = sqrt( v_[X] * v_[X] + v_[Y] * v_[Y] + v_[Z] * v_[Z] ); + v_[X] /= length; + v_[Y] /= length; + v_[Z] /= length; + } + }; + + /*! + * Buffers the last control point as the outline of a glyph is + * decomposed. + */ + VertexInfo last_vertex_; + + //! Normally, we will consider a list of vertices. + typedef std::list< VertexInfo* > VertexInfoList; + + //! A convenience definition of the iterator over the list of vertices. + typedef VertexInfoList::const_iterator VILCI; + + //! A convenience definition of the iterator over the list of vertices. + typedef VertexInfoList::iterator VILI; + + /*! + * As curves are decomposed out of the glyph, their vertices are passed + * along to the GLU tessellation functions. These vertices have to + * hang around until gluTessContourEnd is called. + */ + VertexInfoList vertices_; + + //! As GLU tessellation proceeds, new contours open with every call + //! to moveTo. + bool contour_open_; + + //! The user can provide a ColorTess object which computes a color + //! for each tesselated vertex. + ColorTess* color_tess_; + + //! The user can provide a TextureTess object which computes texture + //! coordinates for each tesselated vertex. + TextureTess* texture_tess_; + + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Polygonal ( const char* filename, float point_size = 12, + FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Polygonal ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100); + + /*! + * \param face open Freetype FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Polygonal ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * The Polygonal destructor doesn't do anything in particular. + */ + OGLFT_API virtual ~Polygonal ( void ); + + /*! + * TrueType and Type1 files describe the boundaries of glyphs with + * quadratic and cubic curves, respectively. Since OpenGL can only really + * draw straight lines, these curves have to be tessellated. The + * number of steps used is fixed for all glyphs in the face, + * but can be changed through this method. Other notes: This value is + * only applicable for Outline, Filled and Solid styles. Changing this value + * invalidates any cached display lists for glyphs in this face. + * + * \param tessellation_steps the number of steps to tessellate each curved + * segment of a glyph outline. + */ + OGLFT_API void setTessellationSteps ( unsigned int tessellation_steps ); + + /*! + * \return the number of steps used to tessellate curves in the + * polygonal font types. + */ + OGLFT_API unsigned int tessellationSteps ( void ) const { return tessellation_steps_; } + + /*! + * Set the individual character rotation in the X direction. + * \param character_rotation_x angle in degrees of the X rotation. + */ + OGLFT_API void setCharacterRotationX ( GLfloat character_rotation_x ); + + /*! + * Set the individual character rotation in the Y direction. + * \param character_rotation_y angle in degrees of the Y rotation. + */ + OGLFT_API void setCharacterRotationY ( GLfloat character_rotation_y ); + + /*! + * Set the individual character rotation in the Z direction. + * \param character_rotation_z angle in degrees of the Z rotation. + */ + OGLFT_API void setCharacterRotationZ ( GLfloat character_rotation_z ); + + /*! + * \return the character rotation in the X direction. + */ + OGLFT_API GLfloat characterRotationX ( void ) const { return character_rotation_.x_; } + + /*! + * \return the character rotation in the Y direction. + */ + OGLFT_API GLfloat characterRotationY ( void ) const { return character_rotation_.y_; } + + /*! + * \return the character rotation in the Z direction. + */ + OGLFT_API GLfloat characterRotationZ ( void ) const { return character_rotation_.z_; } + + /*! + * Set an optional color tesselation object. Each tesselated vertex + * is passed to this object, which returns a color for that position + * in space. + * \param color_tess the color tesselation object. + */ + OGLFT_API void setColorTess ( ColorTess* color_tess ); + /*! + * \return the color tesselation object. + */ + OGLFT_API ColorTess* colorTess ( void ) const { return color_tess_; } + /*! + * Set an optional texture coordinate tesselation object. Each + * tessellated vertex is passed to this object, which returns + * texture coordinates for that position in space. + * \param texture_tess the texture coordinate tesselation object. + */ + OGLFT_API void setTextureTess ( TextureTess* texture_tess ); + /*! + * \return the texture coordinate tesselation object. + */ + OGLFT_API TextureTess* textureTess ( void ) const { return texture_tess_; } + + /*! + * \return the height (i.e., line spacing) at the current character size. + */ + OGLFT_API double height ( void ) const; + + /*! + * Implement measuring a character in a polygonal face. + * \param c the (latin1) character to measure + * \return the bounding box of c. + */ + OGLFT_API BBox measure ( unsigned char c ); +#ifndef OGLFT_NO_QT + /*! + * Implement measuring a character in a polygonal face. + * \param c the (UNICODE) character to measure + * \return the bounding box of c. + */ + OGLFT_API BBox measure ( const QChar c ); +#endif /* OGLFT_NO_QT */ + /*! + * Measure a string of characters. Note: currently, this merely + * calls Face's measure routine. + * \param s string of (latin1) characters to measure + * \return the bounding box of s. + */ + OGLFT_API BBox measure ( const char* s ) { return Face::measure( s ); } +#ifndef OGLFT_NO_QT + /*! + * Implement measuring a formatted number + * \param format the format string + * \param number to value to format + * \return the bounding box of the formatted number + */ + OGLFT_API BBox measure ( const QString& format, double number ) + { return Face::measure( format, number ); } +#endif /* OGLFT_NO_QT */ + + private: + void init ( void ); + void setCharSize ( void ); + void setRotationOffset ( void ); + GLuint compileGlyph ( FT_Face face, FT_UInt glyph_index ); + protected: + void clearCaches ( void ); + }; + + //! Render text as a polygon outline. + /*! + * \image html outline_class.png + * Text is drawn as an outline of each glyph. The contours are extracted + * from the font file through FreeType. FreeType is used to scale the + * contours to a given size. Usually the outline is drawn in the foreground + * color, however, you can specify a ColorTess object to provide a color + * for each vertex individually. You can also use + * the per-glyph display list functionality to alter the attributes + * of each glyph. + * + * The only complexity to this style is selecting the point size. Since + * the outlines are drawn as a polygon, they are subject to the MODELVIEW + * transformation. The point size is nominally chosen to be the same as a + * raster image generated at the given resolution. Some experimentation + * with point size and resolution may be necessary to achieve the desired + * results. + */ + class Outline : public Polygonal { + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Outline ( const char* filename, float point_size = 12, + FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Outline ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param face open FreeType FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Outline ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * The destructor doesn't do anything in particular. + */ + ~Outline ( void ); + private: + void init ( void ); + void renderGlyph ( FT_Face face, FT_UInt glyph_index ); + static int moveToCallback ( FT_Vector* to, Outline* outline ); + static int lineToCallback ( FT_Vector* to, Outline* outline ); + static int conicToCallback ( FT_Vector* control, FT_Vector* to, Outline* outline ); + static int cubicToCallback ( FT_Vector* control1, FT_Vector* control2, + FT_Vector* to, Outline* outline ); + }; + + //! Render text as a filled polygons. + /*! + * \image html filled_class.png + * Each glyph is drawn as a filled polygon. The contours are extracted + * from the font file through FreeType. FreeType is used to scale the + * contours to the given size. Then the GLU tessellation routines are used + * to tessellate the contours into polygons (well, triangles). By default, + * these are drawn in GL_FILL polygon mode, but any other polygon mode + * can be specified. + * + * Usually, the polygons are drawn only in the + * foreground color, however, you may supply ColorTess and TextureTess + * objects which can alter the color or texture coordinates of each + * vertex individually. You can also use + * the per-glyph display list functionality to alter the attributes + * of each glyph. + * + * The only complexity to this style is selecting the point size. Since + * the glyphs are drawn as polygons, they are subject to the viewing and + * modeling transformations. The point size is nominally chosen to be the same + * as a raster image generated at the given resolution. Some experimentation + * with point size and resolution may be necessary to achieve the desired + * results. + */ + class Filled : public Polygonal { + //! 3D tessellation of glyphs is accomplished through the standard GLU + //! routines + GLUtesselator* tess_obj_; + + //! A place to store any extra vertices generated by the Combine callback + VertexInfoList extra_vertices_; + + protected: + //! Offset the glyph in the Z direction. Solely for the Solid subclass. + //! Until I can figure out how to shift the glyph outside the context + //! of this class, I guess this has got to stay (but it is redundant + //! to extrusion_.depth_) + GLfloat depth_offset_; + + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Filled ( const char* filename, float point_size = 12, + FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Filled ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param face open FreeType FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Filled ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); + /*! + * The destructor deletes the GLU tessellation object allocated in + * in the constructor. + */ + OGLFT_API virtual ~Filled ( void ); + + /*! + * \return the list of extra vertices created by the GLU tessellation + * combine callback. + */ + OGLFT_API VertexInfoList& extraVertices ( void ) { return extra_vertices_; } + + protected: + void renderGlyph ( FT_Face face, FT_UInt glyph_index ); + private: + void init ( void ); + static int moveToCallback ( FT_Vector* to, Filled* filled ); + static int lineToCallback ( FT_Vector* to, Filled* filled ); + static int conicToCallback ( FT_Vector* control, FT_Vector* to, Filled* filled); + static int cubicToCallback ( FT_Vector* control1, FT_Vector* control2, + FT_Vector* to, Filled* filled ); + static void vertexCallback ( VertexInfo* vertex ); + static void beginCallback ( GLenum which ); + static void endCallback ( void ); + static void combineCallback ( GLdouble coords[3], void* vertex_data[4], + GLfloat weight[4], void** out_data, + Filled* filled ); + static void errorCallback ( GLenum error_code ); + }; + +#ifndef OGLFT_NO_SOLID + //! Render text as solid letters. + /*! + * \image html solid_class.png + * Each glyph is drawn as a closed solid. The contours are extracted + * from the font file through FreeType. FreeType is used to scale the + * contours to the given size. The contours are passed to the GLE + * tubing and extrusion library to create the sides of the solid. + * Then the GLU tessellation routines are used + * to tessellate the contours into polygons which are used to cap the sides. + * + * Currently, the solids are drawn only in the foreground color. However, + * proper surface normals are computed so that the solids may be lighted. + * Eventually, you'll be able to supply a color/texture + * coordinate function to make glyphs more interesting. Note that you can use + * the per-glyph display list functionality to alter each glyph individually. + * + * Another TODO item is to improve the interaction with GLE. Currently, + * you can only create block solids. Eventually, we'll have the capability + * add bevels and rounds to the edges of the solids and maybe even more + * general extrusions (like, for example, the swooshing letters in the title + * sequence of the Salkind's 1978 "Superman" movie). + * + * The only complexity to this style is selecting the point size. Since + * the glyphs are drawn as a collection of polygons, they are subject to the + * viewing and modeling transformations. The point size is nominally chosen + * to be the same as a raster image generated at the given resolution. + * Some experimentation with point size and resolution may be necessary to + * achieve the desired results. + */ + class Solid : public Filled { + private: + + //! Callbacks for FreeType glyph decomposition into outlines (note: this + //! has the same name as the variable in Polygonal, but it is distinct since + //! the routines for the GLE contouring are different from the Filled + //! GLU tessellation routines. This may be too confusing?) + FT_Outline_Funcs interface_; + + //! For now, you can only get block extruded solids + static const unsigned int N_POLYLINE_PTS = 4; + + //! Data for the gleExtrusion routine + struct glePoint2D { + double p_[2]; + glePoint2D ( double p[2] ) { p_[X] = p[X]; p_[Y] = p[Y]; } + glePoint2D ( double x, double y ) { p_[X] = x; p_[Y] = y; } + glePoint2D ( const VertexInfo& v ) { p_[X] = v.v_[X]; p_[Y] = v.v_[Y]; } + }; + + //! Collect all the output from GLE in one of these structures. + struct { + double depth_; + struct { + int x_, y_; + } normal_sign_; + std::vector< glePoint2D > contour_; + std::vector< glePoint2D > contour_normals_; + gleDouble up_[3]; + int n_polyline_pts_; + gleDouble point_array_[N_POLYLINE_PTS][3]; + } extrusion_; + + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Solid ( const char* filename, float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Solid ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param face open FreeType FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Solid ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * The destructor doesn't do anything in particular. + */ + OGLFT_API ~Solid ( void ); + /*! + * Set the thickness of the solid + * \param depth thickness of the solid in model units. + */ + OGLFT_API void setDepth ( double depth ); + + /*! + * \return the solid extrusion depth. + */ + OGLFT_API double depth ( void ) const { return extrusion_.depth_; } + + private: + // It would be nice if C/C++ had real matrix notation (like Perl!) + void assign ( gleDouble a[3], double x, double y, double z ) + { + a[X] = x; + a[Y] = y; + a[Z] = z; + } + + void init ( void ); + void renderGlyph ( FT_Face face, FT_UInt glyph_index ); + static int moveToCallback ( FT_Vector* to, Solid* solid ); + static int lineToCallback ( FT_Vector* to, Solid* solid ); + static int conicToCallback ( FT_Vector* control, FT_Vector* to, Solid* solid ); + static int cubicToCallback ( FT_Vector* control1, FT_Vector* control2, + FT_Vector* to, Solid* solid ); + }; +#endif /* OGLFT_NO_SOLID */ + //! This is the base class of the raster styles: bitmap, grayscale and + //! translucent. + /*! + * In the raster styles, FreeType's rasterizer is used to generate raster + * images of each glyph. + */ + class Raster : public Face { + protected: + //! Raster glyph can be rotated in the Z plane (in addition to the string + //! rotation). + GLfloat character_rotation_z_; + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Raster ( const char* filename, float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Raster ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param face open FreeType FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Raster ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); + /*! + * The destructor doesn't do anything in particular. + */ + OGLFT_API virtual ~Raster ( void ); + /*! + * Set the individual character rotation in the Z direction. + * \param character_rotation_z angle in degrees of Z rotation. + */ + OGLFT_API void setCharacterRotationZ ( GLfloat character_rotation_z ); + /*! + * \return the character rotation in the Z direction. + */ + OGLFT_API GLfloat characterRotationZ ( void ) const { return character_rotation_z_; } + + /*! + * \return the height (i.e., line spacing) at the current character size. + */ + OGLFT_API double height ( void ) const; + + /*! + * Implement measuring a character in a raster face. + * \param c the (latin1) character to measure + * \return the bounding box of c. + */ + OGLFT_API BBox measure ( unsigned char c ); +#ifndef OGLFT_NO_QT + /*! + * Implement measuring a character in a raster face. + * \param c the (UNICODE) character to measure + * \return the bounding box of c. + */ + OGLFT_API BBox measure ( const QChar c ); +#endif /* OGLFT_NO_QT */ + /*! + * Measure a string of characters. Note: currently, this merely + * calls Face's measure routine. + * \param s string of (latin1) characters to measure + * \return the bounding box of s. + */ + OGLFT_API BBox measure ( const char* s ) { return Face::measure( s ); } +#ifndef OGLFT_NO_QT + /*! + * Implement measuring a formatted number + * \param format the format string + * \param number to value to format + * \return the bounding box of the formatted number + */ + OGLFT_API BBox measure ( const QString& format, double number ); +#endif /* OGLFT_NO_QT */ + + private: + void init ( void ); + GLuint compileGlyph ( FT_Face face, FT_UInt glyph_index ); + void setCharSize ( void ); + void setRotationOffset ( void ); + void clearCaches ( void ); + }; + + //! Render text as a monochrome raster image. + /*! + * \image html monochrome_class.png + * This is more or less the standard way in which text is intended to + * be rendered in OpenGL. It uses the \c glBitmap call to draw a sequence + * of monochrome bitmaps. Since FreeType is capable of rotating glyphs + * created from faces based on vector outlines, you can rotate (in the Z plane) + * both the text string as well as the individual characters in the string. + * + * Note: you \em must call + * \code + * glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + * \endcode + * before drawing in order for monochrome glyphs to be rendered properly. + * + * Another note: It is helpful to have the option + * \c GL_RASTER_POSITION_UNCLIPPED_IBM available if you intend to draw text + * at MODELVIEW based positions, otherwise if the initial text position is off + * the screen, the entire image is clipped. + */ + class Monochrome : public Raster { + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Monochrome ( const char* filename, float point_size = 12, + FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Monochrome ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param font open FreeType FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Monochrome ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); + /*! + * The destructor doesn't do anything in particular. + */ + OGLFT_API ~Monochrome ( void ); + private: + GLubyte* invertBitmap ( const FT_Bitmap& bitmap ); + void renderGlyph ( FT_Face face, FT_UInt glyph_index ); + }; + + //! Render text as a grayscale raster image. + /*! + * \image html grayscale_class.png + * The Grayscale style is similar to the Monochrome style. FreeType is used + * to rasterize a glyph and this is then drawn on the screen using + * \c glDrawPixels. The FreeType rasterization is done in anti-aliased mode. + * When Grayscale draws the glyph image, the resulting text is blended + * smoothly from the foreground color to the background color. The background + * of the glyph is opaque, so this style works best over a solid background. + * + * Note: you \em must call + * \code + * glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + * \endcode + * before drawing in order for grayscale glyphs to be rendered properly. + * + * Another note: It is helpful to have the option + * \c GL_RASTER_POSITION_UNCLIPPED_IBM available if you intend to draw text + * at MODELVIEW based positions, otherwise if the initial text position is off + * the screen, the entire image is clipped. + */ + class Grayscale : public Raster { + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Grayscale ( const char* filename, float point_size = 12, + FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Grayscale ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param face open FreeType FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Grayscale ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); + /*! + * The destructor doesn't do anything in particular. + */ + OGLFT_API ~Grayscale ( void ); + private: + GLubyte* invertPixmap ( const FT_Bitmap& bitmap ); + void renderGlyph ( FT_Face face, FT_UInt glyph_index ); + }; + + //! Render text as a translucent raster image. + /*! + * \image html translucent_class.png + * The Translucent style is similar to the Grayscale style. FreeType is used + * to rasterize a glyph and this is then drawn on the screen using + * \c glDrawPixels. The FreeType rasterization is done in anti-aliased mode. + * When Translucent draws the glyph image, the grayscale levels provided + * by FreeType are used as Alpha values in the raster image. This allows + * the glyphs to be smoothly blended into complicated backgrounds. + * + * Note: you \em must call + * \code + * glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + * \endcode + * before drawing in order for translucent glyphs to be rendered properly. + * Additionally, you need to activate blending in order to achieve the + * translucent effect: + * \code + * glEnable( GL_BLEND ); + * glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + * \endcode + * + * Another note: It is helpful to have the option + * \c GL_RASTER_POSITION_UNCLIPPED_IBM available if you intend to draw text + * at MODELVIEW based positions, otherwise if the initial text position is off + * the screen, the entire image is clipped. + */ + class Translucent : public Raster { + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Translucent ( const char* filename, float point_size = 12, + FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Translucent ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param face open FreeType FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Translucent ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * The destructor doesn't do anything in particular. + */ + OGLFT_API ~Translucent ( void ); + + private: + GLubyte* invertPixmapWithAlpha ( const FT_Bitmap& bitmap ); + void renderGlyph ( FT_Face face, FT_UInt glyph_index ); + }; + + //! This is the base class of the texture style. + class Texture : public Face { + protected: + //! Angle of rotation of characters relative to text orientation. + struct { + bool active_; //!< Is character rotation non-zero? (faster than checking all + //!< the other values.) + GLfloat x_, //!< Angle of rotation in the X direction. + y_, //!< Angle of rotation in the Y direction. + z_; //!< Angle of rotation in the Z direction. + } character_rotation_; + + /*! + * The textured glyphs need a little bit more infrastructure to draw + * since we have to remember the size of the texture object itself + * (at least implicitly). Also, we don't want to create any more + * texture objects than we have to, so they are always cached. + */ + struct TextureInfo { + GLuint texture_name_; //!< A bound texture name is an integer in OpenGL. + FT_Int left_bearing_, //!< The left bearing of the transformed glyph. + bottom_bearing_; //!< The bottom bearing of the transformed glyph. + int width_, //!< The 2**l width of the texture. + height_; //!< The 2**m height of the texture. + GLfloat texture_s_, //!< The fraction of the texture width occupied + //!< by the glyph. + texture_t_; //!< The fraction of the texture height occupied + //!< by the glyph. + FT_Vector advance_; //!< The advance vector of the transformed glyph. + }; + + //! Type of the cache of defined glyph to texture objects mapping. + typedef std::map< FT_UInt, TextureInfo > GlyphTexObjs; + + //! A convenience definition of the iterator over the glyph to texture + //! object map. + typedef GlyphTexObjs::const_iterator GTOCI; + + //! A convenience definition of the iterator over the glyph to texture + //! object map. + typedef GlyphTexObjs::iterator GTOI; + + //! Cache of defined glyph texture objects. + GlyphTexObjs glyph_texobjs_; + + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Texture ( const char* filename, float point_size = 12, + FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Texture ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param face open FreeType FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API Texture ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * The texture destructor doesn't really do anything. + */ + OGLFT_API virtual ~Texture ( void ); + /*! + * Set the individual character rotation in the X direction. + * \param character_rotation_x angle in degrees of X rotation. + */ + OGLFT_API void setCharacterRotationX ( GLfloat character_rotation_x ); + + /*! + * Set the individual character rotation in the Y direction. + * \param character_rotation_y angle in degrees of Y rotation. + */ + OGLFT_API void setCharacterRotationY ( GLfloat character_rotation_y ); + + /*! + * Set the individual character rotation in the Z direction. + * \param character_rotation_z angle in degrees of Z rotation. + */ + OGLFT_API void setCharacterRotationZ ( GLfloat character_rotation_z ); + + /*! + * \return the character rotation in the X direction. + */ + OGLFT_API GLfloat characterRotationX ( void ) const { return character_rotation_.x_; } + + /*! + * \return the character rotation in the Y direction. + */ + OGLFT_API GLfloat characterRotationY ( void ) const { return character_rotation_.y_; } + + /*! + * \return the character rotation in the Z direction. + */ + OGLFT_API GLfloat characterRotationZ ( void ) const { return character_rotation_.z_; } + + /*! + * \return the height (i.e., line spacing) at the current character size. + */ + OGLFT_API double height ( void ) const; + + /*! + * Implement measuring a character in a texture face. + * \param c the (latin1) character to measure + * \return the bounding box of c. + */ + OGLFT_API BBox measure ( unsigned char c ); +#ifndef OGLFT_NO_QT + /*! + * Implement measuring a character in a texture face. + * \param c the (UNICODE) character to measure + * \return the bounding box of c. + */ + OGLFT_API BBox measure ( const QChar c ); +#endif /* OGLFT_NO_QT */ + /*! + * Measure a string of characters. Note: currently, this merely + * calls Face's measure routine. + * \param s string of (latin1) characters to measure + * \return the bounding box of s. + */ + OGLFT_API BBox measure ( const char* s ) { return Face::measure( s ); } +#ifndef OGLFT_NO_QT + OGLFT_API BBox measure ( const QString& s ) + { return Face::measure( s ); } + + /*! + * Implement measuring a formatted number + * \param format the format string + * \param number to value to format + * \return the bounding box of the formatted number + */ + OGLFT_API BBox measure ( const QString& format, double number ) + { return Face::measure( format, number ); } +#endif /* OGLFT_NO_QT */ + + protected: + /*! + * OpenGL texture maps have to be a power of 2 in width and height (including + * apparently 1 = 2**0 ). This function returns the next higher power of + * 2 of the argument. If the argument is already a power of 2, you just + * get that back. + * \param a width or height of an image. + * \return value of a rounded to nearest, higher power of 2. + */ + unsigned int nearestPowerCeil ( unsigned int a ); + /*! + * This is all that distinguishes the various texture styles. Each subclass + * defines this method as appropriate. Once the texture is bound, it + * is rendered the same in all cases. + * \param face FT_Face containing the glyph to render. + * \param glyph_index index of glyph in face. + */ + virtual void bindTexture ( FT_Face face, FT_UInt glyph_index ) = 0; + + private: + void init ( void ); + void setCharSize ( void ); + void setRotationOffset ( void ); + GLuint compileGlyph ( FT_Face face, FT_UInt glyph_index ); + void renderGlyph ( FT_Face face, FT_UInt glyph_index ); + void clearCaches ( void ); + }; + + //! Render text as texture mapped monochrome quads. + /*! + * \image html texture_monochrome_class.png + * This style is similar to the Monochrome raster style, except instead + * of using \c glBitmap to draw the raster image, the image is used + * as a texture map on a quad. If drawing is confined to the Z plane, + * then you will see no difference between this style and Monochrome. + * However, because the quad is a 3D object, it can be transformed + * by the usual modeling operations; so, texture mapped glyphs can be + * rotated in the X and Y directions as well as Z direction. Also, + * if the viewing (or modeling) transformation has a non-unity scale or + * shear, the glyphs will also be scaled or sheared (unlike the raster + * styles). Also, there is no problem with clipping glyphs which lie + * off the screen; texture mapped quads are properly clipped to the + * screen boundary. + * + * If this is not convincing enough, the performance of texture mapped + * glyphs is generally as good as or better than the equivalent + * raster style (especially with hardware texture acceleration). However, + * they do take up more memory space. + * + * Note: you \em must call + * \code + * glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + * \endcode + * before drawing in order for textured glyphs to be rendered properly. + */ + class MonochromeTexture : public Texture { + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API MonochromeTexture ( const char* filename, float point_size = 12, + FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API MonochromeTexture ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param face open FreeType FT_Face + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API MonochromeTexture ( FT_Face face, float point_size = 12, + FT_UInt resolution = 100 ); + /*! + * The monochrome texture destructor doesn't really do anything. + */ + OGLFT_API ~MonochromeTexture ( void ); + private: + GLubyte* invertBitmap ( const FT_Bitmap& bitmap, int* width, int* height ); + void bindTexture ( FT_Face face, FT_UInt glyph_index ); + }; + + //! Render text as texture mapped grayscale quads. + /*! + * \image html texture_grayscale_class.png + * This style is similar to the Grayscale raster style, except instead + * of using \c glDrawPixels to draw the raster image, the image is used + * as a texture map on a quad. If drawing is confined to the Z plane, + * then you will see no difference between this style and Grayscale. + * However, because the quad is a 3D object, it can be transformed + * by the usual modeling operations; so, texture mapped glyphs can be + * rotated in the X and Y directions as well as Z direction. Also, + * if the viewing (or modeling) transformation has a non-unity scale or + * shear, the glyphs will also be scaled or sheared (unlike the raster + * styles). Also, there is no problem with clipping glyphs which lie + * off the screen; texture mapped quads are properly clipped to the + * screen boundary. + * + * If this is not convincing enough, the performance of texture mapped + * glyphs is generally as good as or better than the equivalent + * raster style (especially with hardware texture acceleration). However, + * they do consume more memory space. + * + * Note: you \em must call + * \code + * glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + * \endcode + * before drawing in order for textured glyphs to be rendered properly. + */ + class GrayscaleTexture : public Texture { + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API GrayscaleTexture ( const char* filename, float point_size = 12, + FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API GrayscaleTexture ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param face open FreeType FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API GrayscaleTexture ( FT_Face face, float point_size = 12, + FT_UInt resolution = 100 ); + /*! + * The grayscale texture destructor doesn't really do anything. + */ + OGLFT_API ~GrayscaleTexture ( void ); + private: + GLubyte* invertPixmap ( const FT_Bitmap& bitmap, int* width, int* height ); + void bindTexture ( FT_Face face, FT_UInt glyph_index ); + }; + + //! Render text as texture mapped translucent quads. + /*! + * \image html texture_translucent_class.png + * This style is similar to the Translucent raster style, except instead + * of using \c glDrawPixels to draw the raster image, the image is used + * as a texture map on a quad. If drawing is confined to the Z plane, + * then you will see no difference between this style and Translucent. + * However, because the quad is a 3D object, it can be transformed + * by the usual modeling operations; so, texture mapped glyphs can be + * rotated in the X and Y directions as well as Z direction. Also, + * if the viewing (or modeling) transformation has a non-unity scale or + * shear, the glyphs will also be scaled or sheared (unlike the raster + * styles). Also, there is no problem with clipping glyphs which lie + * off the screen; texture mapped quads are properly clipped to the + * screen boundary. + * + * If this is not convincing enough, the performance of texture mapped + * glyphs is generally as good as or better than the equivalent + * raster style (especially with hardware texture acceleration). However, + * they do consume more memory space. + * + * Note: you \em must call + * \code + * glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + * \endcode + * before drawing in order for textured glyphs to be rendered properly. + * Additionally, you need to activate blending in order to achieve the + * translucent effect: + * \code + * glEnable( GL_BLEND ); + * glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + * \endcode + */ + class TranslucentTexture : public Texture { + public: + /*! + * \param filename the filename which contains the font face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API TranslucentTexture ( const char* filename, float point_size = 12, + FT_UInt resolution = 100 ); + + /*! + * \param data_base the memory location (base pointer) which contains the font face. + * \param data_size the size (in bytes) of the font data found at \ref data_base. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API TranslucentTexture ( const FT_Byte* data_base, const FT_Long data_size, + float point_size = 12, FT_UInt resolution = 100 ); + + /*! + * \param face open FreeType FT_Face. + * \param point_size the initial point size of the font to generate. A point + * is essentially 1/72th of an inch. Defaults to 12. + * \param resolution the pixel density of the display in dots per inch (DPI). + * Defaults to 100 DPI. + */ + OGLFT_API TranslucentTexture ( FT_Face face, float point_size = 12, + FT_UInt resolution = 100 ); + /*! + * The translucent texture destructor doesn't really do anything. + */ + OGLFT_API ~TranslucentTexture ( void ); + private: + GLubyte* invertPixmap ( const FT_Bitmap& bitmap, int* width, int* height ); + void bindTexture ( FT_Face face, FT_UInt glyph_index ); + }; +} // Close OGLFT namespace +#endif /* OGLFT_H */