From 8e1b1bcfc171b7e7d9507cd7f72e36c2682d01c6 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 23 Oct 2001 19:51:39 +0000 Subject: [PATCH] First past integrat of Max Rhiener work on wrapping FTGL to create osgText library and demo. --- .../Demos/osgTextDemo/osgTextDemo.dsp | 102 +++ VisualStudio/osgText/osgText.dsp | 115 +++ include/osgText/Export | 25 + include/osgText/Text | 345 +++++++++ src/Demos/osgtext/main.cpp | 588 ++++++++++++++++ src/osgText/FTBitmapGlyph.cc | 76 ++ src/osgText/FTBitmapGlyph.h | 48 ++ src/osgText/FTCharmap.cc | 91 +++ src/osgText/FTCharmap.h | 109 +++ src/osgText/FTFace.cc | 110 +++ src/osgText/FTFace.h | 144 ++++ src/osgText/FTFont.cc | 148 ++++ src/osgText/FTFont.h | 179 +++++ src/osgText/FTGL.h | 7 + src/osgText/FTGLBitmapFont.cc | 70 ++ src/osgText/FTGLBitmapFont.h | 59 ++ src/osgText/FTGLOutlineFont.cc | 68 ++ src/osgText/FTGLOutlineFont.h | 37 + src/osgText/FTGLPixmapFont.cc | 66 ++ src/osgText/FTGLPixmapFont.h | 36 + src/osgText/FTGLPolygonFont.cc | 35 + src/osgText/FTGLPolygonFont.h | 35 + src/osgText/FTGLTextureFont.cc | 210 ++++++ src/osgText/FTGLTextureFont.h | 54 ++ src/osgText/FTGlyph.cc | 14 + src/osgText/FTGlyph.h | 76 ++ src/osgText/FTGlyphContainer.cc | 66 ++ src/osgText/FTGlyphContainer.h | 100 +++ src/osgText/FTLibrary.cc | 65 ++ src/osgText/FTLibrary.h | 102 +++ src/osgText/FTOutlineGlyph.cc | 83 +++ src/osgText/FTOutlineGlyph.h | 36 + src/osgText/FTPixmapGlyph.cc | 94 +++ src/osgText/FTPixmapGlyph.h | 35 + src/osgText/FTPolyGlyph.cc | 156 ++++ src/osgText/FTPolyGlyph.h | 38 + src/osgText/FTSize.cc | 91 +++ src/osgText/FTSize.h | 118 ++++ src/osgText/FTTextureGlyph.cc | 92 +++ src/osgText/FTTextureGlyph.h | 40 ++ src/osgText/FTVectoriser.cc | 227 ++++++ src/osgText/FTVectoriser.h | 104 +++ src/osgText/Makefile | 29 + src/osgText/Text.cpp | 665 ++++++++++++++++++ 44 files changed, 4988 insertions(+) create mode 100644 VisualStudio/Demos/osgTextDemo/osgTextDemo.dsp create mode 100644 VisualStudio/osgText/osgText.dsp create mode 100644 include/osgText/Export create mode 100644 include/osgText/Text create mode 100644 src/Demos/osgtext/main.cpp create mode 100644 src/osgText/FTBitmapGlyph.cc create mode 100644 src/osgText/FTBitmapGlyph.h create mode 100644 src/osgText/FTCharmap.cc create mode 100644 src/osgText/FTCharmap.h create mode 100644 src/osgText/FTFace.cc create mode 100644 src/osgText/FTFace.h create mode 100644 src/osgText/FTFont.cc create mode 100644 src/osgText/FTFont.h create mode 100644 src/osgText/FTGL.h create mode 100644 src/osgText/FTGLBitmapFont.cc create mode 100644 src/osgText/FTGLBitmapFont.h create mode 100644 src/osgText/FTGLOutlineFont.cc create mode 100644 src/osgText/FTGLOutlineFont.h create mode 100644 src/osgText/FTGLPixmapFont.cc create mode 100644 src/osgText/FTGLPixmapFont.h create mode 100644 src/osgText/FTGLPolygonFont.cc create mode 100644 src/osgText/FTGLPolygonFont.h create mode 100644 src/osgText/FTGLTextureFont.cc create mode 100644 src/osgText/FTGLTextureFont.h create mode 100644 src/osgText/FTGlyph.cc create mode 100644 src/osgText/FTGlyph.h create mode 100644 src/osgText/FTGlyphContainer.cc create mode 100644 src/osgText/FTGlyphContainer.h create mode 100644 src/osgText/FTLibrary.cc create mode 100644 src/osgText/FTLibrary.h create mode 100644 src/osgText/FTOutlineGlyph.cc create mode 100644 src/osgText/FTOutlineGlyph.h create mode 100644 src/osgText/FTPixmapGlyph.cc create mode 100644 src/osgText/FTPixmapGlyph.h create mode 100644 src/osgText/FTPolyGlyph.cc create mode 100644 src/osgText/FTPolyGlyph.h create mode 100644 src/osgText/FTSize.cc create mode 100644 src/osgText/FTSize.h create mode 100644 src/osgText/FTTextureGlyph.cc create mode 100644 src/osgText/FTTextureGlyph.h create mode 100644 src/osgText/FTVectoriser.cc create mode 100644 src/osgText/FTVectoriser.h create mode 100644 src/osgText/Makefile create mode 100644 src/osgText/Text.cpp diff --git a/VisualStudio/Demos/osgTextDemo/osgTextDemo.dsp b/VisualStudio/Demos/osgTextDemo/osgTextDemo.dsp new file mode 100644 index 000000000..9fbcc8ee3 --- /dev/null +++ b/VisualStudio/Demos/osgTextDemo/osgTextDemo.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="osgTextDemo" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=osgTextDemo - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "osgTextDemo.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "osgTextDemo.mak" CFG="osgTextDemo - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "osgTextDemo - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "osgTextDemo - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "osgTextDemo - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x807 /d "NDEBUG" +# ADD RSC /l 0x807 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 osgText.lib osgGlut.lib glut32.lib osgUtil.lib osgDB.lib osg.lib opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"../../../../osgDev/bin/osgTextDemo.exe" + +!ELSEIF "$(CFG)" == "osgTextDemo - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /vd0 /GR /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x807 /d "_DEBUG" +# ADD RSC /l 0x807 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 osgTextd.lib osgGlutd.lib glut32.lib osgUtild.lib osgDBd.lib osgd.lib opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../../osgDev/bin/osgTextDemoD.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "osgTextDemo - Win32 Release" +# Name "osgTextDemo - Win32 Debug" +# Begin Group "Quellcodedateien" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\src\Demos\osgText\main.cpp +# End Source File +# End Group +# Begin Group "Header-Dateien" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Ressourcendateien" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/VisualStudio/osgText/osgText.dsp b/VisualStudio/osgText/osgText.dsp new file mode 100644 index 000000000..34a621654 --- /dev/null +++ b/VisualStudio/osgText/osgText.dsp @@ -0,0 +1,115 @@ +# Microsoft Developer Studio Project File - Name="osgText" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=osgText - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "osgText.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "osgText.mak" CFG="osgText - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "osgText - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "osgText - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "osgText - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../../lib" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OSGTEXT_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OSGTEXT_LIBRARY" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x807 /d "NDEBUG" +# ADD RSC /l 0x807 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 ftglDllD.lib glu32.lib opengl32.lib osg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"../../../../osgDev/bin/osgText.dll" + +!ELSEIF "$(CFG)" == "osgText - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../../lib" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OSGTEXT_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /vd0 /GR /GX /ZI /Od /I "../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "OSGTEXT_LIBRARY" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x807 /d "_DEBUG" +# ADD RSC /l 0x807 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ftglDllD.lib glu32.lib opengl32.lib osgd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\development\osgDev\osgDev\bin\osgTextD.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "osgText - Win32 Release" +# Name "osgText - Win32 Debug" +# Begin Group "Quellcodedateien" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\src\osgText\Text.cpp +# End Source File +# End Group +# Begin Group "Header-Dateien" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\include\osgText\Export +# End Source File +# Begin Source File + +SOURCE=..\..\include\osgText\Text.h +# End Source File +# End Group +# Begin Group "Ressourcendateien" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/include/osgText/Export b/include/osgText/Export new file mode 100644 index 000000000..818222a6f --- /dev/null +++ b/include/osgText/Export @@ -0,0 +1,25 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGTEXT_EXPORT_ +#define OSGTEXT_EXPORT_ 1 + +#ifdef WIN32 + #pragma warning( disable : 4251 ) + #pragma warning( disable : 4275 ) + #pragma warning( disable : 4786 ) + +#endif + +#if defined(_MSC_VER) + # ifdef OSGTEXT_LIBRARY + # define OSGTEXT_EXPORT __declspec(dllexport) + # else + # define OSGTEXT_EXPORT __declspec(dllimport) + # endif /* OSGTEXT_LIBRARY */ +#else + # define OSGTEXT_EXPORT +#endif + +#endif diff --git a/include/osgText/Text b/include/osgText/Text new file mode 100644 index 000000000..7238f3791 --- /dev/null +++ b/include/osgText/Text @@ -0,0 +1,345 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +/* -------------------------------------------------------------------------- + * + * openscenegraph textLib / FTGL wrapper + * + * -------------------------------------------------------------------------- + * + * prog: max rheiner;mrn@paus.ch + * date: 4/25/2001 (m/d/y) + * + * -------------------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + */ + + +#ifndef OSGTEXT_TEXT +#define OSGTEXT_TEXT 1 + +#include + +#include +#include +#include +#include +#include + +// http://homepages.paradise.net.nz/henryj/code/ +/* +#include +#include +#include +#include +#include +#include +*/ +#include + +class FTFont; + +namespace osgText { + +using namespace osg; + +/////////////////////////////////////////////////////////////////////////////// +// Font - FontBaseClass +class OSGTEXT_EXPORT Font:public Object +{ +public: + + Font(); + + + virtual bool open(const std::string& font); + + virtual bool create(int pointSize, const unsigned int res = 72 ); + virtual bool create(); + virtual void output(const char* text); + + virtual bool isOk(void) const { return _init; } + virtual bool isCreated(void) const { return isOk() && _created; } + + virtual float getWidth(const char* text) const; + virtual int getHeight() const; + virtual int getDescender() const; + virtual int getAscender() const; + + int getPointSize(void) const { return _pointSize; } + const std::string& getFontName(); + + FTFont* getFont(void) { return _font; } + +protected: + + virtual ~Font(); + + virtual void clear(); + + virtual FTFont* createFontObj(void)=0; + + bool init(const std::string& font); + + bool _init; + bool _created; + + FTFont* _font; + std::string _fontName; + int _pointSize; + int _res; +}; +// Font +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// RasterFont +class OSGTEXT_EXPORT RasterFont:public Font +{ +public: + RasterFont():Font(){;} + RasterFont(const std::string& font):Font(){;} + +protected: + +}; + +// RasterFont +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// VectorFont +class OSGTEXT_EXPORT VectorFont:public Font +{ +public: + VectorFont():Font(){;} + VectorFont(const std::string& font):Font(){;} + +protected: + double _precision; +}; + +// VectorFont +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// BitmapFont +class OSGTEXT_EXPORT BitmapFont:public RasterFont +{ +public: + + + BitmapFont() {;} + + BitmapFont(const std::string& font, + int point_size); + + META_Object(BitmapFont); + +protected: + + + virtual FTFont* createFontObj(void); +}; + +// BitmapFont +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// PixmapFont +class OSGTEXT_EXPORT PixmapFont:public RasterFont +{ +public: + + PixmapFont() {;} + + PixmapFont(const std::string& font, + int point_size); + + META_Object(PixmapFont); + +protected: + + virtual FTFont* createFontObj(void); + +}; +// PixmapFont +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// TextureFont + +class OSGTEXT_EXPORT TextureFont:public RasterFont +{ +public: + + TextureFont() {;} + + TextureFont(const std::string& font, + int point_size); + + META_Object(TextureFont); + +protected: + + virtual FTFont* createFontObj(void); + +}; +// PixmapFont +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// OutlineFont +class OSGTEXT_EXPORT OutlineFont:public VectorFont +{ +public: + + OutlineFont() {;} + + OutlineFont(const std::string& font, + int point_size, + double precision); + + META_Object(OutlineFont); + +protected: + + virtual FTFont* createFontObj(void); + + +}; +// OutlineFont +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// PolygonFont +class OSGTEXT_EXPORT PolygonFont:public VectorFont +{ +public: + + PolygonFont() {;} + + PolygonFont(const std::string& font, + int point_size, + double precision); + + META_Object(PolygonFont); + +protected: + + virtual FTFont* createFontObj(void); + +}; +// PolygonFont +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Text +class OSGTEXT_EXPORT Text:public Drawable +{ +public: + + enum AlignmentType + { // from left to right, top to bottom + LEFT_TOP, + LEFT_CENTER, + LEFT_BOTTOM, + + CENTER_TOP, + CENTER_CENTER, + CENTER_BOTTOM, + + RIGHT_TOP, + RIGHT_CENTER, + RIGHT_BOTTOM, + }; + + enum BoundingBoxType + { + GEOMETRY, + GLYPH, + }; + + enum DrawModeType + { // from left to right, top to bottom + TEXT = 1<<0, + BOUNDINGBOX = 1<<1, + ALIGNEMENT = 1<<2, + DEFAULT = TEXT, + }; + + Text(); + Text(Font* font); + + META_Object(Text); + + void setPosition(const Vec3& pos); + void setPosition(const Vec2& pos); + + void setDrawMode(int mode) { _drawMode=mode; } + int getDrawMode(void) { return _drawMode; } + + void setBoundingBox(int mode); + int getBoundingBox(void) { return _boundingBoxType; } + + void setAlignement(int alignement); + int getAlignement(void) { return _alignement; } + + void setFont(Font* font); + Font* getFont(void); + + void setText(const char* text) { _text=text; } + void setText(std::string& text) { _text=text; } + const std::string& getText() const { return _text; } + + virtual void drawImmediateMode(State& state); + virtual void drawBoundingBox(void); + virtual void drawAlignement(void); + + const Vec3& getPosition() { return _pos; } + const Vec3& getAlignementPos() { return _alignementPos; }; + + +protected: + + enum FontType + { + UNDEF, + BITMAP, + PIXMAP, + OUTLINE, + POLYGON, + TEXTURE, + }; + + virtual ~Text(); + + virtual void setDefaults(void); + virtual const bool computeBound(void) const; + virtual void calcBounds(Vec3* min,Vec3* max) const; + void initAlignement(Vec3* min,Vec3* max); + bool initAlignement(void); + + ref_ptr _font; + + bool _init; + bool _initAlignement; + std::string _text; + int _fontType; + int _alignement; + int _drawMode; + int _boundingBoxType; + + Vec3 _pos; + Vec3 _alignementPos; +}; +// Text +/////////////////////////////////////////////////////////////////////////////// + +}; + +#endif // _OSG_TEXT_H diff --git a/src/Demos/osgtext/main.cpp b/src/Demos/osgtext/main.cpp new file mode 100644 index 000000000..f33fbb77c --- /dev/null +++ b/src/Demos/osgtext/main.cpp @@ -0,0 +1,588 @@ +/* -------------------------------------------------------------------------- + * + * osgText demo + * + * -------------------------------------------------------------------------- + * + * prog: max rheiner;mrn@paus.ch + * date: 4/26/2001 (m/d/y) + * + * -------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + + +/////////////////////////////////////////////////////////////////////////////// +// globals +#define TEXT_POLYGON "Polygon Font - jygq" +#define TEXT_OUTLINE "Outline Font - jygq" +#define TEXT_TEXTURE "Texture Font - jygq" +#define TEXT_BITMAP "Bitmap Font - jygq" +#define TEXT_PIXMAP "Pixmap Font - jygq" + +#define TEXT_COL_2D osg::Vec4(.9,.9,.9,1) +#define TEXT_COL_3D osg::Vec4(.99,.3,.2,1) + +std::string ttfPath("./fonts/times.ttf"); +std::string ttfPath1("./fonts/verdana.ttf"); + +int gFontSize=18; +int gFontSize1=24; +std::vector > gTextList; +osgText::Text::AlignmentType gAlignement=osgText::Text::AlignmentType::LEFT_BOTTOM; + + +void set2dScene(osg::Group* rootNode) +{ + osgText::Text* text; + osg::Geode* geode; + osg::Material* textMaterial; + osg::Vec4 textColor; + osg::StateSet* textState; + double xOffset=250; + double yOffset=gFontSize+10; + + /////////////////////////////////////////////////////////////////////////// + // setup the texts + + /////////////////////////////////////////////////////////////////////////// + // BitmapFont + osgText::BitmapFont* bitmapFont=new osgText::BitmapFont(ttfPath, + gFontSize1); + text=new osgText::Text(bitmapFont); + gTextList.push_back(text); + text->setText(std::string("2d ")+std::string(TEXT_BITMAP)); + text->setPosition(osg::Vec3(xOffset,yOffset,0)); + text->setDrawMode( osgText::Text::DrawModeType::TEXT | + osgText::Text::DrawModeType::BOUNDINGBOX | + osgText::Text::DrawModeType::ALIGNEMENT ); + text->setAlignement(gAlignement); + geode = new osg::Geode(); + geode->setName("BitmapFont"); + geode->addDrawable( text ); + + textMaterial = new osg::Material(); + textMaterial->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE); + textMaterial->setDiffuse( osg::Material::FRONT_AND_BACK, TEXT_COL_2D); + textState = new osg::StateSet(); + textState->setAttribute(textMaterial ); + geode->setStateSet( textState ); + + rootNode->addChild(geode); + + xOffset+=90; + yOffset+=120; + + /////////////////////////////////////////////////////////////////////////// + // PixmapFont + osgText::PixmapFont* pixmapFont=new osgText::PixmapFont(ttfPath, + gFontSize1); + text=new osgText::Text(pixmapFont); + gTextList.push_back(text); + text->setText(std::string("2d ")+std::string(TEXT_PIXMAP)); + text->setPosition(osg::Vec3(xOffset,yOffset,0)); + text->setDrawMode( osgText::Text::DrawModeType::TEXT | + osgText::Text::DrawModeType::BOUNDINGBOX | + osgText::Text::DrawModeType::ALIGNEMENT ); + text->setAlignement(gAlignement); + geode = new osg::Geode(); + geode->setName("PixmapFont"); + geode->addDrawable( text ); + + textMaterial = new osg::Material(); + textMaterial->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE); + textMaterial->setDiffuse( osg::Material::FRONT_AND_BACK,TEXT_COL_2D); + // to get antiaA pixmapFonts we have to draw them with blending + osg::Transparency *transp=new osg::Transparency(); + transp->setFunction(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + textState = new osg::StateSet(); + textState->setAttribute(textMaterial ); + textState->setAttribute(transp); + textState->setMode(GL_BLEND,osg::StateAttribute::ON); + textState->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + geode->setStateSet( textState ); + + rootNode->addChild(geode); + + xOffset+=90; + yOffset+=120; + + /////////////////////////////////////////////////////////////////////////// + // TextureFont + osgText::TextureFont* textureFont=new osgText::TextureFont(ttfPath1, + gFontSize1); + text=new osgText::Text(textureFont); + gTextList.push_back(text); + text->setText(std::string("2d ")+std::string(TEXT_TEXTURE)); + text->setPosition(osg::Vec3(xOffset,yOffset,0)); + text->setDrawMode( osgText::Text::DrawModeType::TEXT | + osgText::Text::DrawModeType::BOUNDINGBOX | + osgText::Text::DrawModeType::ALIGNEMENT ); + text->setAlignement(gAlignement); + geode = new osg::Geode(); + geode->setName("TextureFont"); + geode->addDrawable( text ); + + textMaterial = new osg::Material(); + textMaterial->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE); + textMaterial->setDiffuse( osg::Material::FRONT_AND_BACK, TEXT_COL_2D); + // to get antiaA pixmapFonts we have to draw them with blending + transp=new osg::Transparency(); + transp->setFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + textState = new osg::StateSet(); + textState->setAttribute(textMaterial ); + textState->setAttribute(transp); + + textState->setMode(GL_TEXTURE_2D,osg::StateAttribute::ON); + textState->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + geode->setStateSet( textState ); + + rootNode->addChild(geode); + + xOffset+=90; + yOffset+=120; + + /////////////////////////////////////////////////////////////////////////// + // PolygonFont + osgText::PolygonFont* polygonFont=new osgText::PolygonFont(ttfPath, + gFontSize1, + 3); + text=new osgText::Text(polygonFont); + gTextList.push_back(text); + text->setText(std::string("2d ")+std::string("TEXT_POLYGON")); + text->setPosition(osg::Vec3(xOffset,yOffset,0)); + text->setDrawMode( osgText::Text::DrawModeType::TEXT | + osgText::Text::DrawModeType::BOUNDINGBOX | + osgText::Text::DrawModeType::ALIGNEMENT ); + text->setAlignement(gAlignement); + geode = new osg::Geode(); + geode->setName("PolygonFont"); + geode->addDrawable( text ); + + textMaterial = new osg::Material(); + textMaterial->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE); + textMaterial->setDiffuse( osg::Material::FRONT_AND_BACK, TEXT_COL_2D); + textState = new osg::StateSet(); + textState->setAttribute(textMaterial ); + geode->setStateSet( textState ); + + rootNode->addChild(geode); + + xOffset+=90; + yOffset+=120; + + /////////////////////////////////////////////////////////////////////////// + // OutlineFont + osgText::OutlineFont* outlineFont=new osgText::OutlineFont(ttfPath, + gFontSize1, + 3); + + text=new osgText::Text(outlineFont); + gTextList.push_back(text); + text->setText(std::string("2d ")+std::string(TEXT_OUTLINE)); + text->setPosition(osg::Vec3(xOffset,yOffset,0)); + text->setDrawMode( osgText::Text::DrawModeType::TEXT | + osgText::Text::DrawModeType::BOUNDINGBOX | + osgText::Text::DrawModeType::ALIGNEMENT ); + text->setAlignement(gAlignement); + geode = new osg::Geode(); + geode->setName("OutlineFont"); + geode->addDrawable( text ); + + textMaterial = new osg::Material(); + textMaterial->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE); + textMaterial->setDiffuse( osg::Material::FRONT_AND_BACK, TEXT_COL_2D); + textState = new osg::StateSet(); + textState->setAttribute(textMaterial ); + geode->setStateSet( textState ); + + rootNode->addChild(geode); +} + +void setScene(osg::Group* rootNode) +{ + osgText::Text* text; + osg::Geode* geode; + osg::Material* textMaterial; + osg::Vec4 textColor; + osg::StateSet* textState; + double xOffset=0; + double yOffset=0; + + /////////////////////////////////////////////////////////////////////////// + // setup the texts + /////////////////////////////////////////////////////////////////////////// + // BitmapFont + osgText::BitmapFont* bitmapFont=new osgText::BitmapFont(ttfPath, + gFontSize); + text=new osgText::Text(bitmapFont); + gTextList.push_back(text); + text->setText(std::string(TEXT_BITMAP)); + text->setPosition(osg::Vec3(xOffset,yOffset,0)); + text->setDrawMode( osgText::Text::DrawModeType::TEXT | + osgText::Text::DrawModeType::BOUNDINGBOX | + osgText::Text::DrawModeType::ALIGNEMENT ); + text->setAlignement(gAlignement); + geode = new osg::Geode(); + geode->setName("BitmapFont"); + geode->addDrawable( text ); + + textMaterial = new osg::Material(); + textMaterial->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE); + textMaterial->setDiffuse( osg::Material::FRONT_AND_BACK,TEXT_COL_3D); + textState = new osg::StateSet(); + textState->setAttribute(textMaterial ); + geode->setStateSet( textState ); + + rootNode->addChild(geode); + + yOffset+=gFontSize+5; + + /////////////////////////////////////////////////////////////////////////// + // PixmapFont + osgText::PixmapFont* pixmapFont=new osgText::PixmapFont(ttfPath, + gFontSize); + text=new osgText::Text(pixmapFont); + gTextList.push_back(text); + text->setText(std::string(TEXT_PIXMAP)); + text->setPosition(osg::Vec3(xOffset,yOffset,0)); + text->setDrawMode( osgText::Text::DrawModeType::TEXT | + osgText::Text::DrawModeType::BOUNDINGBOX | + osgText::Text::DrawModeType::ALIGNEMENT ); + text->setAlignement(gAlignement); + geode = new osg::Geode(); + geode->setName("PixmapFont"); + geode->addDrawable( text ); + + textMaterial = new osg::Material(); + textMaterial->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE); + textMaterial->setDiffuse( osg::Material::FRONT_AND_BACK,TEXT_COL_3D); + // to get antiaA pixmapFonts we have to draw them with blending + osg::Transparency *transp=new osg::Transparency(); + transp->setFunction(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + textState = new osg::StateSet(); + textState->setAttribute(textMaterial ); + textState->setAttribute(transp); + textState->setMode(GL_BLEND,osg::StateAttribute::ON); + textState->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + geode->setStateSet( textState ); + + rootNode->addChild(geode); + + yOffset+=gFontSize+5; + + /////////////////////////////////////////////////////////////////////////// + // TextureFont + osgText::TextureFont* textureFont=new osgText::TextureFont(ttfPath, + gFontSize); + text=new osgText::Text(textureFont); + gTextList.push_back(text); + text->setText(std::string(TEXT_TEXTURE)); + text->setPosition(osg::Vec3(xOffset,yOffset,0)); + text->setDrawMode( osgText::Text::DrawModeType::TEXT | + osgText::Text::DrawModeType::BOUNDINGBOX | + osgText::Text::DrawModeType::ALIGNEMENT ); + text->setAlignement(gAlignement); + geode = new osg::Geode(); + geode->setName("TextureFont"); + geode->addDrawable( text ); + + textMaterial = new osg::Material(); + textMaterial->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE); + textMaterial->setDiffuse( osg::Material::FRONT_AND_BACK,TEXT_COL_3D); + // to get antiaA pixmapFonts we have to draw them with blending + transp=new osg::Transparency(); + transp->setFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + textState = new osg::StateSet(); + textState->setAttribute(textMaterial ); + textState->setAttribute(transp); + +// textState->setMode(GL_BLEND,osg::StateAttribute::ON); + textState->setMode(GL_TEXTURE_2D,osg::StateAttribute::ON); + textState->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + geode->setStateSet( textState ); + + rootNode->addChild(geode); + + yOffset+=gFontSize+5; + + /////////////////////////////////////////////////////////////////////////// + // PolygonFont + osgText::PolygonFont* polygonFont=new osgText::PolygonFont(ttfPath, + gFontSize, + 3); + text=new osgText::Text(polygonFont); + gTextList.push_back(text); + text->setText(std::string(TEXT_POLYGON)); + text->setPosition(osg::Vec3(xOffset,yOffset,0)); + text->setDrawMode( osgText::Text::DrawModeType::TEXT | + osgText::Text::DrawModeType::BOUNDINGBOX | + osgText::Text::DrawModeType::ALIGNEMENT ); + text->setAlignement(gAlignement); + geode = new osg::Geode(); + geode->setName("PolygonFont"); + geode->addDrawable( text ); + + textMaterial = new osg::Material(); + textMaterial->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE); + textMaterial->setDiffuse( osg::Material::FRONT_AND_BACK,TEXT_COL_3D); + textState = new osg::StateSet(); + textState->setAttribute(textMaterial ); + geode->setStateSet( textState ); + + rootNode->addChild(geode); + + yOffset+=gFontSize+5; + + /////////////////////////////////////////////////////////////////////////// + // OutlineFont + osgText::OutlineFont* outlineFont=new osgText::OutlineFont(ttfPath, + gFontSize, + 3); + + text=new osgText::Text(outlineFont); + gTextList.push_back(text); + text->setText(std::string(TEXT_OUTLINE)); + text->setPosition(osg::Vec3(xOffset,yOffset,0)); + text->setDrawMode( osgText::Text::DrawModeType::TEXT | + osgText::Text::DrawModeType::BOUNDINGBOX | + osgText::Text::DrawModeType::ALIGNEMENT ); + text->setAlignement(gAlignement); + geode = new osg::Geode(); + geode->setName("OutlineFont"); + geode->addDrawable( text ); + + textMaterial = new osg::Material(); + textMaterial->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE); + textMaterial->setDiffuse( osg::Material::FRONT_AND_BACK,TEXT_COL_3D); + textState = new osg::StateSet(); + textState->setAttribute(textMaterial ); + geode->setStateSet( textState ); + + rootNode->addChild(geode); + +} + +class TextViewer: public osgGLUT::Viewer +{ +public: + + virtual float app(unsigned int viewport) + { + float ret; + ret=Viewer::app(viewport); + if(_hudSceneView.valid() && viewport>=_viewportList.size()-1) + { + _hudSceneView->app(); + } + return ret; + } + + virtual float cull(unsigned int viewport) + { + float ret; + ret=Viewer::cull(viewport); + if(_hudSceneView.valid() && viewport>=_viewportList.size()-1) + _hudSceneView->cull(); + return ret; + } + + virtual float draw(unsigned int viewport) + { + float ret; + ret=Viewer::draw(viewport); + if(_hudSceneView.valid() && viewport>=_viewportList.size()-1) + _hudSceneView->draw(); + return ret; + } + + void addHUD(osg::Node* rootnode) + { + _hudSceneView = new osgUtil::SceneView; + _hudSceneView->setDefaults(); + _hudSceneView->setSceneData(rootnode); + + } + + virtual void reshape(GLint w, GLint h) + { + Viewer::reshape(w,h); + + if(_hudSceneView.valid()) + { + _hudSceneView->setViewport(0,0,w,h); + _hudCam->setOrtho2D(0,w,0,h); + } + } + + virtual bool open() + { + bool ret=Viewer::open(); + + // set the clear flag / after the visualReq.Visitor + if(_hudSceneView.valid()) + { + _hudSceneView->getRenderStage()->setClearMask(0); + _hudSceneView->getCullVisitor()->setCullingMode(osgUtil::CullViewState::NO_CULLING); + _hudSceneView->setCalcNearFar(false); + + _hudCam=new osg::Camera; + + // leftBottom + _hudSceneView->setCamera(_hudCam.get()); + } + + return ret; + } + + +protected: + + osg::ref_ptr _hudCam; + osg::ref_ptr _hudSceneView; + + virtual void keyboard(unsigned char key, int x, int y) + { + switch(key) + { + case '1': + { // change DrawMode + std::vector >::iterator itr=gTextList.begin(); + for(;itr!=gTextList.end();itr++) + (*itr)->setDrawMode(osgText::Text::DrawModeType::TEXT ^ (*itr)->getDrawMode()); + } + return; + case '2': + { // change DrawMode + std::vector >::iterator itr=gTextList.begin(); + for(;itr!=gTextList.end();itr++) + (*itr)->setDrawMode(osgText::Text::DrawModeType::BOUNDINGBOX ^ (*itr)->getDrawMode()); + } + return; + case '3': + { // change DrawMode + std::vector >::iterator itr=gTextList.begin(); + for(;itr!=gTextList.end();itr++) + (*itr)->setDrawMode(osgText::Text::DrawModeType::ALIGNEMENT ^ (*itr)->getDrawMode()); + } + return; + /////////////////////////////////////////////////////////////////// + case '4': + { // change BoundingBoxType to GEOMETRY + std::vector >::iterator itr=gTextList.begin(); + osgText::Text::BoundingBoxType type=(*itr)->getBoundingBox()==osgText::Text::BoundingBoxType::GLYPH ? + osgText::Text::BoundingBoxType::GEOMETRY : + osgText::Text::BoundingBoxType::GLYPH; + for(;itr!=gTextList.end();itr++) + (*itr)->setBoundingBox(type); + } + return; + /////////////////////////////////////////////////////////////////// + case '5': + { // change the textAlignement + gAlignement=(osgText::Text::AlignmentType)((int)gAlignement+1); + if(gAlignement>osgText::Text::AlignmentType::RIGHT_BOTTOM) + gAlignement=osgText::Text::AlignmentType::LEFT_TOP; + + std::vector >::iterator itr=gTextList.begin(); + for(;itr!=gTextList.end();itr++) + (*itr)->setAlignement(gAlignement); + } + return; + default: + Viewer::keyboard(key,x,y); + }; + } + +}; + +int main( int argc, char **argv ) +{ + // initialize the GLUT + glutInit( &argc, argv ); + + // get the fontName + if(argc > 1) + ttfPath=argv[1]; + if(argc > 2) + ttfPath1=argv[2]; + if(argc > 3) + { + gFontSize=atoi(argv[3]); + if(gFontSize<=4) + gFontSize=8; + } + if(argc > 4) + { + gFontSize1=atoi(argv[3]); + if(gFontSize1<=4) + gFontSize1=8; + } + + osg::Group* rootNode = new osg::Group; + osg::Group* scene2d = new osg::Group; + osg::Transform* textGroup = new osg::Transform; + + // set the name for the hole group + rootNode->setName("sceneGroup"); + + // turn off the culling + // turn off the light + osg::StateSet* gstate = new osg::StateSet; + gstate->setMode(GL_CULL_FACE,osg::StateAttribute::OFF); + gstate->setMode(GL_LIGHTING,osg::StateAttribute::OFF); + gstate->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF); + rootNode->setStateSet(gstate); + scene2d->setStateSet(gstate); + + // setup the sceneData + setScene(textGroup); + textGroup->preRotate(-90,1,0,0); + rootNode->addChild(textGroup); + + // setup the 2dNode + set2dScene(scene2d); + + // initialize the viewer. + TextViewer viewer; +/* + viewer.addViewport( rootNode ); + viewer.getViewportSceneView(0)->setBackgroundColor(osg::Vec4(.2,.2,.2,1)); +*/ + viewer.addViewport( rootNode,0.0,0.0,0.5,0.5); + viewer.addViewport( rootNode,0.5,0.0,0.5,0.5); + viewer.addViewport( rootNode,0.0,0.5,1.0,0.5); + viewer.addHUD(scene2d); + + // register trackball, flight and drive. + viewer.registerCameraManipulator(new osgUtil::TrackballManipulator); + viewer.registerCameraManipulator(new osgUtil::FlightManipulator); + viewer.registerCameraManipulator(new osgUtil::DriveManipulator); + + viewer.open(); + viewer.run(); + + return 0; +} diff --git a/src/osgText/FTBitmapGlyph.cc b/src/osgText/FTBitmapGlyph.cc new file mode 100644 index 000000000..07af04acd --- /dev/null +++ b/src/osgText/FTBitmapGlyph.cc @@ -0,0 +1,76 @@ +#include "GL/gl.h" + +#include "FTBitmapGlyph.h" +#include "FTGL.h" + + +FTBitmapGlyph::FTBitmapGlyph( FT_Glyph glyph) +: FTGlyph(), + destWidth(0), + destHeight(0), + data(0) +{ + // This function will always fail if the glyph's format isn't scalable???? + FT_Error err = FT_Glyph_To_Bitmap( &glyph, ft_render_mode_mono, 0, 1); + if( err || ft_glyph_format_bitmap != glyph->format) + {return;} + + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; + FT_Bitmap* source = &bitmap->bitmap; + + //check the pixel mode + //ft_pixel_mode_grays + + int srcWidth = source->width; + int srcHeight = source->rows; + int srcPitch = source->pitch; + + advance = glyph->advance.x >> 16; + + pos.x = bitmap->left; + pos.y = srcHeight - bitmap->top; + + // FIXME What about dest alignment? + destWidth = srcWidth; + destHeight = srcHeight; + + data = new unsigned char[srcPitch * destHeight]; + + for(int y = 0; y < srcHeight; ++y) + { + --destHeight; + for(int x = 0; x < srcPitch; ++x) + { + *( data + ( destHeight * srcPitch + x)) = *( source->buffer + ( y * srcPitch) + x); + } + } + + destHeight = srcHeight; + + // discard glyph image (bitmap or not) + // Is this the right place to do this? + FT_Done_Glyph( glyph ); +} + + +FTBitmapGlyph::~FTBitmapGlyph() +{ + delete[] data; +} + + +float FTBitmapGlyph::Render( const FT_Vector& pen) +{ + if( data != 0 ) + { + // Move the glyph origin + glBitmap( 0, 0, 0.0, 0.0, pen.x + pos.x, pen.y - pos.y, (const GLubyte *)0 ); + + glBitmap( destWidth, destHeight, 0.0f, 0.0, 0.0, 0.0, (const GLubyte *)data); + + // Restore the glyph origin + glBitmap( 0, 0, 0.0, 0.0, -pen.x - pos.x, -pen.y + pos.y, (const GLubyte *)0 ); + } + + return advance; +} diff --git a/src/osgText/FTBitmapGlyph.h b/src/osgText/FTBitmapGlyph.h new file mode 100644 index 000000000..d650ba576 --- /dev/null +++ b/src/osgText/FTBitmapGlyph.h @@ -0,0 +1,48 @@ +#ifndef __FTBitmapGlyph__ +#define __FTBitmapGlyph__ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGlyph.h" + + +class FTBitmapGlyph : public FTGlyph +{ + public: + /** + * Constructor + * + * @param + */ + FTBitmapGlyph( FT_Glyph glyph); + + /** + * + */ + virtual ~FTBitmapGlyph(); + + /** + * + * @param pen + * + * @return + */ + virtual float Render( const FT_Vector& pen); + + // attributes + + private: + // methods + + // attributes + int destWidth; + int destHeight; + + unsigned char* data; + +}; + + +#endif // __FTBitmapGlyph__ diff --git a/src/osgText/FTCharmap.cc b/src/osgText/FTCharmap.cc new file mode 100644 index 000000000..31107c6b0 --- /dev/null +++ b/src/osgText/FTCharmap.cc @@ -0,0 +1,91 @@ +#include "FTCharmap.h" + + +FTCharmap::FTCharmap( FT_Face face) +: err(0), + ftFace( face) +{ + ftEncoding = face->charmap->encoding; +} + + +FTCharmap::~FTCharmap() +{ + charMap.clear(); +} + + +bool FTCharmap::CharMap( FT_Encoding encoding) +{ + if( ftEncoding == encoding) + { + return true; + } + + err = FT_Select_Charmap( ftFace, encoding ); + + if( !err) + { + ftEncoding = encoding; + charMap.clear(); + } + + return !err; +} + + +bool FTCharmap::CharMap( FT_UShort platform, FT_UShort encoding) +{ + FT_CharMap found = 0; + FT_CharMap charmap; + + for( int n = 0; n < ftFace->num_charmaps; n++ ) + { + charmap = ftFace->charmaps[n]; + + if( charmap->platform_id == platform && charmap->encoding_id == encoding) + { + found = charmap; + break; + } + } + + if( !found ) + { + return false; + } + + if( ftEncoding == found->encoding) + { + return true; + } + + /* now, select the charmap for the face object */ + err = FT_Set_Charmap( ftFace, found ); + + if( !err) + { + ftEncoding = found->encoding; + charMap.clear(); + } + + return !err; +} + + +unsigned int FTCharmap::CharIndex( unsigned int index ) +{ + CharacterMap::const_iterator result = charMap.find( index); + + if( result == charMap.end()) + { + unsigned int glyph = FT_Get_Char_Index( ftFace, index); + charMap.insert( CharacterMap::value_type( index, glyph)); + return glyph; + } + else + { + return result->second; + } + +} diff --git a/src/osgText/FTCharmap.h b/src/osgText/FTCharmap.h new file mode 100644 index 000000000..db0edd8de --- /dev/null +++ b/src/osgText/FTCharmap.h @@ -0,0 +1,109 @@ +#ifndef __FTCharmap__ +#define __FTCharmap__ + +#include + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +//#include "FTGL.h" + +using namespace std; + + +/** + * FTCharmap + * + * + */ +class FTCharmap +{ + public: + /** + * Constructor + */ + FTCharmap( FT_Face ftFace); + + /** + * Destructor + */ + virtual ~FTCharmap(); + + /** + * Queries for the current character map code. + * + * @return The current character map code. + */ + FT_Encoding Encoding() const { return ftEncoding;} + + /** + * Sets the character map for the face. + * Valid encodings as at Freetype 2.0.4 + * ft_encoding_none + * ft_encoding_symbol + * ft_encoding_unicode + * ft_encoding_latin_2 + * ft_encoding_sjis + * ft_encoding_gb2312 + * ft_encoding_big5 + * ft_encoding_wansung + * ft_encoding_johab + * ft_encoding_adobe_standard + * ft_encoding_adobe_expert + * ft_encoding_adobe_custom + * ft_encoding_apple_roman + * + * @param encoding the Freetype encoding symbol. See above. + * @return true if charmap was valid + * and set correctly + */ + bool CharMap( FT_Encoding encoding); + + /** + * Sets the character map for the face. + * + * @param encoding the Freetype encoding symbol. See above. + * @return true if charmap was valid + * and set correctly + */ + bool CharMap( FT_UShort platform, FT_UShort encoding); + + /** + * Get the glyph index of the input character. + * + * @param index The character code of the requested glyph in the + * current encoding eg apple roman. + * @return The glyph index for the character. + */ + unsigned int CharIndex( unsigned int index ); + + /** + * Queries for errors. + * + * @return The current error code. + */ + FT_Error Error() const { return err;} + + protected: + /** + * Current character map code. + */ + FT_Encoding ftEncoding; + + FT_Face ftFace; + + typedef map< unsigned long, unsigned long> CharacterMap; + CharacterMap charMap; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; + + private: + +}; + + +#endif // __FTCharmap__ diff --git a/src/osgText/FTFace.cc b/src/osgText/FTFace.cc new file mode 100644 index 000000000..ad47ca332 --- /dev/null +++ b/src/osgText/FTFace.cc @@ -0,0 +1,110 @@ +#include "FTFace.h" +#include "FTLibrary.h" +#include "FTCharmap.h" +#include "FTGL.h" + + +FTFace::FTFace() +: ftFace(0), + numCharMaps(0), + charMap(0), + numGlyphs(0), + err(0) +{} + + +FTFace::~FTFace() +{ + delete charMap; + charMap = 0; + Close(); +} + + +bool FTFace::Open( const char* filename) +{ + ftFace = new FT_Face; + err = FT_New_Face( *FTLibrary::Instance().GetLibrary(), filename, 0, ftFace); + + if( err) + { + delete ftFace; + ftFace = 0; + return false; + } + else + { + charMap = new FTCharmap( *ftFace); + return true; + } +} + + +void FTFace::Close() +{ + if( ftFace) + { + FT_Done_Face( *ftFace); + delete ftFace; + ftFace = 0; + } +} + + +FTSize& FTFace::Size( const unsigned int size, const unsigned int res) +{ + if( !charSize.CharSize( ftFace, size, res, res)) + { + err = charSize.Error(); + } + + return charSize; +} + + +bool FTFace::CharMap( FT_Encoding encoding) +{ + return charMap->CharMap( encoding); +} + + +unsigned int FTFace::CharIndex( unsigned int index) const +{ + return charMap->CharIndex( index); +} + + +FT_Vector& FTFace::KernAdvance( unsigned int index1, unsigned int index2) +{ + kernAdvance.x = 0; kernAdvance.y = 0; + + if( FT_HAS_KERNING((*ftFace)) && index1 && index2) + { + err = FT_Get_Kerning( *ftFace, index1, index2, ft_kerning_unfitted, &kernAdvance); + if( !err) + { + kernAdvance.x /= 64; kernAdvance.y /= 64; + } + } + + return kernAdvance; +} + + +FT_Glyph* FTFace::Glyph( unsigned int index, FT_Int load_flags) +{ + err = FT_Load_Glyph( *ftFace, index, load_flags); + err = FT_Get_Glyph( (*ftFace)->glyph, &ftGlyph); + + if( !err) + { + return &ftGlyph; + } + else + { + return NULL; + } +} + + + diff --git a/src/osgText/FTFace.h b/src/osgText/FTFace.h new file mode 100644 index 000000000..9ba7514cc --- /dev/null +++ b/src/osgText/FTFace.h @@ -0,0 +1,144 @@ +#ifndef __FTFace__ +#define __FTFace__ + +//#include "FTGL.h" + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTSize.h" + +class FTCharmap; + +/** + * FTFace class provides an abstraction layer for the Freetype Face. + * + * @see "Freetype 2 Documentation - 2.0.4" + * + */ +class FTFace +{ + public: + /** + * Default Constructor + */ + FTFace(); + + /** + * Destructor + * + * Disposes of the current Freetype Face. + */ + virtual ~FTFace(); + + /** + * Opens and reads a face file. + * + * @param fontname font file name. + * @return true if file has opened + * successfully. + */ + bool Open( const char* filename); + + /** + * Disposes of the face + */ + void Close(); + + /** + * Sets the char size for the current face. + * + * This doesn't guarantee that the size was set correctly. Clients + * should check errors. + * + * @param size the face size in points (1/72 inch) + * @param res the resolution of the target device. + * @return FTSize object + */ + FTSize& Size( const unsigned int size, const unsigned int res); + + /** + * Sets the character map for the face. + * + * @param encoding the Freetype encoding symbol. See above. + * @return true if charmap was valid + * and set correctly + */ + bool CharMap( FT_Encoding encoding); + + /** + * Get the glyph index of the input character. + * + * @param index The character code of the requested glyph in the + * current encoding eg apple roman. + * @return The glyph index for the character. + */ + unsigned int CharIndex( unsigned int index ) const; + + /** + * Gets the kerning vector between two glyphs + */ + FT_Vector& KernAdvance( unsigned int index1, unsigned int index2); + + /** + * Loads and creates a Freetype glyph. + */ + FT_Glyph* Glyph( unsigned int index, FT_Int load_flags); + + /** + * Gets the current Freetype face. + */ + FT_Face* Face() const { return ftFace;} + + /** + * Queries for errors. + * + * @return The current error code. + */ + FT_Error Error() const { return err; } + + private: + /** + * The size object associated with this face + */ + FTSize charSize; + + /** + * The Character Map object associated with this face + */ + FTCharmap* charMap; + + /** + * The Freetype face + */ + FT_Face* ftFace; + + /** + * Temporary variable to hold a glyph + */ + FT_Glyph ftGlyph; + + /** + * The number of character maps in this face. + */ + int numCharMaps; + + /** + * The number of glyphs in this face + */ + int numGlyphs; + + /** + * Temporary variable to holding a kerning vector. + */ + FT_Vector kernAdvance; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; +}; + + +#endif // __FTFace__ diff --git a/src/osgText/FTFont.cc b/src/osgText/FTFont.cc new file mode 100644 index 000000000..fb9321378 --- /dev/null +++ b/src/osgText/FTFont.cc @@ -0,0 +1,148 @@ +#include "FTFace.h" +#include "FTFont.h" +#include "FTGlyphContainer.h" +#include "FTGL.h" + + +FTFont::FTFont() +: numFaces(0), + glyphList(0), + err(0) +{ + pen.x = 0; + pen.y = 0; +} + + +FTFont::~FTFont() +{ + Close(); +} + + +bool FTFont::Open( const char* fontname ) +{ + if( face.Open( fontname)) + { + FT_Face* ftFace = face.Face(); + numGlyphs = (*ftFace)->num_glyphs; + + return true; + } + else + { + err = face.Error(); + return false; + } +} + + +void FTFont::Close() +{ + delete glyphList; +} + + +bool FTFont::FaceSize( const unsigned int size, const unsigned int res ) +{ + charSize = face.Size( size, res); + + if( glyphList) + delete glyphList; + + glyphList = new FTGlyphContainer( &face, numGlyphs); + + if( MakeGlyphList()) + { + return true; + } + else + { + return false; + } +} + + +bool FTFont::CharMap( FT_Encoding encoding) +{ + err = face.CharMap( encoding); + return !err; +} + + +int FTFont::Ascender() const +{ + return charSize.Ascender(); +} + + +int FTFont::Descender() const +{ + return charSize.Descender(); +} + + +float FTFont::Advance( const wchar_t* string) +{ + const wchar_t* c = string; // wchar_t IS unsigned? + float width = 0; + + while( *c) + { + width += glyphList->Advance( *c, *(c + 1)); + ++c; + } + + return width; +} + + +float FTFont::Advance( const char* string) +{ + const unsigned char* c = (unsigned char*)string; // This is ugly, what is the c++ way? + float width = 0; + + while( *c) + { + width += glyphList->Advance( *c, *(c + 1)); + ++c; + } + + return width; +} + + +void FTFont::render( const char* string ) +{ + const unsigned char* c = (unsigned char*)string; // This is ugly, what is the c++ way? + FT_Vector kernAdvance; + pen.x = 0; pen.y = 0; + + while( *c) + { + kernAdvance = glyphList->render( *c, *(c + 1), pen); + + pen.x += kernAdvance.x; + pen.y += kernAdvance.y; + + ++c; + } +} + + +void FTFont::render( const wchar_t* string ) +{ + const wchar_t* c = string; // wchar_t IS unsigned? + FT_Vector kernAdvance; + pen.x = 0; pen.y = 0; + + while( *c) + { + kernAdvance = glyphList->render( *c, *(c + 1), pen); + + pen.x += kernAdvance.x; + pen.y += kernAdvance.y; + + ++c; + } +} diff --git a/src/osgText/FTFont.h b/src/osgText/FTFont.h new file mode 100644 index 000000000..70650c236 --- /dev/null +++ b/src/osgText/FTFont.h @@ -0,0 +1,179 @@ +#ifndef __FTFont__ +#define __FTFont__ + +#include + +#include +#include FT_FREETYPE_H + +#include "FTFace.h" +#include "FTGL.h" + + +class FTGlyphContainer; + +using namespace std; + + + +/** + * FTFont is the public interface for the FTGL library. + * + * Specific font classes are derived from this class. It uses the helper + * classes FTFace and FTSize to access the Freetype library. This class + * is abstract and deriving classes must implement the protected + * MakeGlyphList function to build a glyphList with the + * appropriate glyph type. + * + * @see FTFace + * @see FTSize + * @see FTGlyphContainer + * @see FTGlyph + */ +class FTFont +{ + public: + /** + * Default Constructor + */ + FTFont(); + + /** + * Destructor + */ + virtual ~FTFont(); + + /** + * Opens and reads a font file. + * + * @param fontname font file name. + * @return true if file has opened + * successfully. + */ + virtual bool Open( const char* fontname ); + + /** + * Disposes of the font + */ + virtual void Close(); + + /** + * Sets the char size for the current face. + * + * @param size the face size in points (1/72 inch) + * @param res the resolution of the target device. + * @return true if size was set correctly + */ + virtual bool FaceSize( const unsigned int size, const unsigned int res = 72 ); + + /** + * Sets the character map for the face. + * + * @param encoding Freetype enumerate for char map code. + * @return true if charmap was valid and + * set correctly + */ + virtual bool CharMap( FT_Encoding encoding ); + + /** + * Gets the global ascender height for the face. + * + * @return Ascender height + */ + virtual int Ascender() const; + + /** + * Gets the global descender height for the face. + * + * @return Descender height + */ + virtual int Descender() const; + + /** + * Gets the advance width for a string. + * + * param string a wchar_t string + * @return advance width + */ + float Advance( const wchar_t* string); + + /** + * Gets the advance width for a string. + * + * param string a char string + * @return advance width + */ + float Advance( const char* string); + + /** + * Renders a string of characters + * + * @param string 'C' style string to be output. + */ + virtual void render( const char* string ); + + /** + * Renders a string of characters + * + * @param string wchar_t string to be output. + */ + virtual void render( const wchar_t* string ); + + + /** + * Queries the Font for errors. + * + * @return The current error code. + */ + virtual FT_Error Error() const { return err;} + + + protected: + /** + * Constructs the internal glyph cache. + * + * This a list of glyphs processed for openGL rendering NOT + * freetype glyphs + */ + virtual bool MakeGlyphList() = 0; + + /** + * Current face object + */ + FTFace face; + /** + * Number of faces in this font + */ + int numFaces; + + /** + * Current size object + */ + FTSize charSize; + + /** + * An object that holds a list of glyphs + */ + FTGlyphContainer* glyphList; + + /** + * The number of glyphs in this font + */ + int numGlyphs; + + /** + * Current pen or cursor position; + */ + FT_Vector pen; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; + + private: + +}; + + +#endif // __FTFont__ diff --git a/src/osgText/FTGL.h b/src/osgText/FTGL.h new file mode 100644 index 000000000..789d33d6f --- /dev/null +++ b/src/osgText/FTGL.h @@ -0,0 +1,7 @@ +#ifndef __FTGL__ +#define __FTGL__ + +// For Future? + + +#endif // __FTGL__ diff --git a/src/osgText/FTGLBitmapFont.cc b/src/osgText/FTGLBitmapFont.cc new file mode 100644 index 000000000..c85e18c46 --- /dev/null +++ b/src/osgText/FTGLBitmapFont.cc @@ -0,0 +1,70 @@ +#include "GL/gl.h" + +#include "FTGLBitmapFont.h" +#include "FTGlyphContainer.h" +#include "FTBitmapGlyph.h" + + +FTGLBitmapFont::FTGLBitmapFont() +: tempGlyph(0) +{} + + +FTGLBitmapFont::~FTGLBitmapFont() +{} + + +// OPSignature: bool FTGlyphContainer:MakeGlyphList() +bool FTGLBitmapFont::MakeGlyphList() +{ +// if( preCache) + for( unsigned int c = 0; c < numGlyphs; ++c) + { + FT_Glyph* ftGlyph = face.Glyph( c, FT_LOAD_DEFAULT); +// FT_HAS_VERTICAL(face) + + if( ftGlyph) + { + tempGlyph = new FTBitmapGlyph( *ftGlyph); + glyphList->Add( tempGlyph); + } + else + { + err = face.Error(); + } + } + + return !err; +} + + +void FTGLBitmapFont::render( const char* string) +{ + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT); + + // doing this every frame is a bad? + glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1); + + FTFont::render( string); + + glPopClientAttrib(); + +} + + +void FTGLBitmapFont::render( const wchar_t* string) +{ + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT); + + // doing this every frame is a bad? + glPixelStorei( GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei( GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1); + + FTFont::render( string); + + glPopClientAttrib(); + +} diff --git a/src/osgText/FTGLBitmapFont.h b/src/osgText/FTGLBitmapFont.h new file mode 100644 index 000000000..cf827af8e --- /dev/null +++ b/src/osgText/FTGLBitmapFont.h @@ -0,0 +1,59 @@ +#ifndef __FTGLBitmapFont__ +#define __FTGLBitmapFont__ + + +#include "FTFont.h" + +class FTBitmapGlyph; + +/** + * FTGLBitmapFont is a specialisation of the FTFont class for handling + * Bitmap fonts + * + * @see FTFont + */ +class FTGLBitmapFont : public FTFont +{ + public: + /** + * Constructor + */ + FTGLBitmapFont(); + + /** + * Destructor + */ + ~FTGLBitmapFont(); + + /** + * Renders a string of characters + * + * @param string 'C' style string to be output. + */ + void render( const char* string); + + /** + * Renders a string of characters + * + * @param string 'C' style string to be output. + */ + void render( const wchar_t* string); + + // attributes + + private: + /** + * Constructs the internal glyph cache. + * + * This a list of glyphs processed for openGL rendering NOT + * freetype glyphs + */ + bool MakeGlyphList(); + + /** + * Temp variable for a FTBitmapGlyph + */ + FTBitmapGlyph* tempGlyph; + +}; +#endif // __FTGLBitmapFont__ diff --git a/src/osgText/FTGLOutlineFont.cc b/src/osgText/FTGLOutlineFont.cc new file mode 100644 index 000000000..9a06af92b --- /dev/null +++ b/src/osgText/FTGLOutlineFont.cc @@ -0,0 +1,68 @@ +#include "GL/gl.h" + +#include "FTGLOutlineFont.h" +#include "FTGlyphContainer.h" +#include "FTGL.h" +#include "FTOutlineGlyph.h" + + +FTGLOutlineFont::FTGLOutlineFont() +: tempGlyph(0) +{} + + +FTGLOutlineFont::~FTGLOutlineFont() +{} + + +bool FTGLOutlineFont::MakeGlyphList() +{ + for( unsigned int n = 0; n < numGlyphs; ++n) + { + FT_Glyph* ftGlyph = face.Glyph( n, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP); + + if( ftGlyph) + { + tempGlyph = new FTOutlineGlyph( *ftGlyph); + glyphList->Add( tempGlyph); + } + else + { + err = face.Error(); + } + } + + return !err; +} + + +void FTGLOutlineFont::render( const char* string) +{ + glPushAttrib( GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_PIXEL_MODE_BIT); + + glEnable( GL_LINE_SMOOTH); + glHint( GL_LINE_SMOOTH_HINT, GL_DONT_CARE); + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE + + FTFont::render( string); + + glPopAttrib(); + +} + + +void FTGLOutlineFont::render( const wchar_t* string) +{ + glPushAttrib( GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_PIXEL_MODE_BIT); + + glEnable( GL_LINE_SMOOTH); + glHint( GL_LINE_SMOOTH_HINT, GL_DONT_CARE); + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE + + FTFont::render( string); + + glPopAttrib(); + +} diff --git a/src/osgText/FTGLOutlineFont.h b/src/osgText/FTGLOutlineFont.h new file mode 100644 index 000000000..172100aba --- /dev/null +++ b/src/osgText/FTGLOutlineFont.h @@ -0,0 +1,37 @@ +#ifndef __FTGLOutlineFont +#define __FTGLOutlineFont + + +#include "FTFont.h" +#include "FTGL.h" + + +class FTOutlineGlyph; + +/** + * FTGLOutlineFont is a specialisation of the FTFont class for handling + * Vector Outline fonts + * + * @see FTFont + */ +class FTGLOutlineFont : public FTFont +{ + public: + // methods + FTGLOutlineFont(); + ~FTGLOutlineFont(); + + void render( const char* string); + void render( const wchar_t* string); + + // attributes + + private: + // methods + bool MakeGlyphList(); + + // attributes + FTOutlineGlyph* tempGlyph; + +}; +#endif diff --git a/src/osgText/FTGLPixmapFont.cc b/src/osgText/FTGLPixmapFont.cc new file mode 100644 index 000000000..e00d1f9ad --- /dev/null +++ b/src/osgText/FTGLPixmapFont.cc @@ -0,0 +1,66 @@ +#include "GL/gl.h" + +#include "FTGLPixmapFont.h" +#include "FTGlyphContainer.h" +#include "FTPixmapGlyph.h" + + +FTGLPixmapFont::FTGLPixmapFont() +: tempGlyph(0) +{} + + +FTGLPixmapFont::~FTGLPixmapFont() +{} + + +// OPSignature: bool FTGlyphContainer:MakeGlyphList() +bool FTGLPixmapFont::MakeGlyphList() +{ +// if( preCache) + for( unsigned int c = 0; c < numGlyphs; ++c) + { + FT_Glyph* ftGlyph = face.Glyph( c, FT_LOAD_DEFAULT); +// FT_HAS_VERTICAL(face) + + if( ftGlyph) + { + tempGlyph = new FTPixmapGlyph( *ftGlyph); + glyphList->Add( tempGlyph); + } + else + { + err = face.Error(); + } + } + + return !err; +} + + +void FTGLPixmapFont::render( const char* string) +{ + glPushAttrib( GL_ENABLE_BIT | GL_PIXEL_MODE_BIT); + + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + FTFont::render( string); + + glPopAttrib(); + +} + + +void FTGLPixmapFont::render( const wchar_t* string) +{ + glPushAttrib( GL_ENABLE_BIT | GL_PIXEL_MODE_BIT); + + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + FTFont::render( string); + + glPopAttrib(); + +} diff --git a/src/osgText/FTGLPixmapFont.h b/src/osgText/FTGLPixmapFont.h new file mode 100644 index 000000000..d0422bdd9 --- /dev/null +++ b/src/osgText/FTGLPixmapFont.h @@ -0,0 +1,36 @@ +#ifndef __FTGLPixmapFont__ +#define __FTGLPixmapFont__ + + +#include "FTFont.h" + +class FTPixmapGlyph; + +/** + * FTGLPixmapFont is a specialisation of the FTFont class for handling + * Pixmap (Grey Scale) fonts + * + * @see FTFont + */ +class FTGLPixmapFont : public FTFont +{ + public: + // methods + FTGLPixmapFont(); + ~FTGLPixmapFont(); + + void render( const char* string); + void render( const wchar_t* string); + + + private: + // methods + bool MakeGlyphList(); + + // attributes + FTPixmapGlyph* tempGlyph; + +}; + + +#endif // __FTGLPixmapFont__ diff --git a/src/osgText/FTGLPolygonFont.cc b/src/osgText/FTGLPolygonFont.cc new file mode 100644 index 000000000..7cbb1ed67 --- /dev/null +++ b/src/osgText/FTGLPolygonFont.cc @@ -0,0 +1,35 @@ +#include "FTGLPolygonFont.h" +#include "FTGlyphContainer.h" +#include "FTGL.h" +#include "FTPolyGlyph.h" + + + +FTGLPolygonFont::FTGLPolygonFont() +: tempGlyph(0) +{} + + +FTGLPolygonFont::~FTGLPolygonFont() +{} + + +bool FTGLPolygonFont::MakeGlyphList() +{ + for( unsigned int n = 0; n < numGlyphs; ++n) + { + FT_Glyph* ftGlyph = face.Glyph( n, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP); + + if( ftGlyph) + { + tempGlyph = new FTPolyGlyph( *ftGlyph); + glyphList->Add( tempGlyph); + } + else + { + err = face.Error(); + } + } + + return !err; +} diff --git a/src/osgText/FTGLPolygonFont.h b/src/osgText/FTGLPolygonFont.h new file mode 100644 index 000000000..27c41ce60 --- /dev/null +++ b/src/osgText/FTGLPolygonFont.h @@ -0,0 +1,35 @@ +#ifndef __FTGLPolygonFont__ +#define __FTGLPolygonFont__ + +#include "FTFont.h" + +#include "FTGL.h" + + +class FTPolyGlyph; + +/** + * FTGLPolygonFont is a specialisation of the FTFont class for handling + * tesselated Polygon Mesh fonts + * + * @see FTFont + */ +class FTGLPolygonFont : public FTFont +{ + public: + // methods + FTGLPolygonFont(); + ~FTGLPolygonFont(); + + // attributes + + private: + // methods + bool MakeGlyphList(); + + // attributes + FTPolyGlyph* tempGlyph; + + +}; +#endif // __FTGLPolygonFont__ diff --git a/src/osgText/FTGLTextureFont.cc b/src/osgText/FTGLTextureFont.cc new file mode 100644 index 000000000..8a3e21d5a --- /dev/null +++ b/src/osgText/FTGLTextureFont.cc @@ -0,0 +1,210 @@ +#include "GL/gl.h" + +#include "FTGLTextureFont.h" +#include "FTGlyphContainer.h" +#include "FTGL.h" +#include "FTTextureGlyph.h" + +using namespace std; + +typedef unsigned long UInt32; // a mac thing? + +inline UInt32 NextPowerOf2( UInt32 in) +{ + in -= 1; + + in |= in >> 16; + in |= in >> 8; + in |= in >> 4; + in |= in >> 2; + in |= in >> 1; + + return in + 1; +} + + +FTGLTextureFont::FTGLTextureFont() +: numTextures(1), + textMem(0), + padding(1), + tempGlyph(0), + maxTextSize(0), + textureWidth(0), + textureHeight(0), + glyphHeight(0), + glyphWidth(0) +{} + + +FTGLTextureFont::~FTGLTextureFont() +{ + glDeleteTextures( numTextures, (const GLuint*)glTextureID); +} + + +bool FTGLTextureFont::MakeGlyphList() +{ + if( !maxTextSize) + glGetIntegerv( GL_MAX_TEXTURE_SIZE, (GLint*)&maxTextSize); + + glyphHeight = ( charSize.Height()) + padding; + glyphWidth = ( charSize.Width()) + padding; + + GetSize(); + int totalMem; + + if( textureHeight > maxTextSize) + { + numTextures = static_cast( textureHeight / maxTextSize) + 1; + if( numTextures > 15) // FIXME + numTextures = 15; + + int heightRemain = NextPowerOf2( textureHeight % maxTextSize); + totalMem = ((maxTextSize * ( numTextures - 1)) + heightRemain) * textureWidth; + + glGenTextures( numTextures, (GLuint*)&glTextureID[0]); + + textMem = new unsigned char[totalMem]; // GL_ALPHA texture; + memset( textMem, 0, totalMem); + + unsigned int glyphNum = 0; + unsigned char* currTextPtr = textMem; + + for( int x = 0; x < numTextures - 1; ++x) + { + glyphNum = FillGlyphs( glyphNum, glTextureID[x], textureWidth, maxTextSize, currTextPtr); + + CreateTexture( x, textureWidth, maxTextSize, currTextPtr); + + currTextPtr += ( textureWidth * maxTextSize); + ++glyphNum; + } + + glyphNum = FillGlyphs( glyphNum, glTextureID[numTextures - 1], textureWidth, heightRemain, currTextPtr); + CreateTexture( numTextures - 1, textureWidth, heightRemain, currTextPtr); + } + else + { + textureHeight = NextPowerOf2( textureHeight); + totalMem = textureWidth * textureHeight; + + glGenTextures( numTextures, (GLuint*)&glTextureID[0]); + + textMem = new unsigned char[totalMem]; // GL_ALPHA texture; + std::memset( textMem, 0, totalMem); + + FillGlyphs( 0, glTextureID[0], textureWidth, textureHeight, textMem); + CreateTexture( 0, textureWidth, textureHeight, textMem); + } + + delete [] textMem; + return !err; +} + + +unsigned int FTGLTextureFont::FillGlyphs( unsigned int glyphStart, int id, int width, int height, unsigned char* textdata) +{ + int currentTextX = padding; + int currentTextY = padding;// + padding; + + float currTextU = (float)padding / (float)width; + float currTextV = (float)padding / (float)height; + +// numGlyphs = 256; // FIXME hack + unsigned int n; + + for( n = glyphStart; n <= numGlyphs; ++n) + { + FT_Glyph* ftGlyph = face.Glyph( n, FT_LOAD_NO_HINTING); + + if( ftGlyph) + { + unsigned char* data = textdata + (( currentTextY * width) + currentTextX); + + currTextU = (float)currentTextX / (float)width; + + tempGlyph = new FTTextureGlyph( *ftGlyph, id, data, width, height, currTextU, currTextV); + glyphList->Add( tempGlyph); + + currentTextX += glyphWidth; + if( currentTextX > ( width - glyphWidth)) + { + currentTextY += glyphHeight; + if( currentTextY > ( height - glyphHeight)) + return n; + + currentTextX = padding; + currTextV = (float)currentTextY / (float)height; + } + } + else + { + err = face.Error(); + } + } + + return n; +} + + +void FTGLTextureFont::GetSize() +{ + //work out the max width. Most likely maxTextSize + textureWidth = NextPowerOf2( numGlyphs * glyphWidth); + if( textureWidth > maxTextSize) + { + textureWidth = maxTextSize; + } + + int h = static_cast( textureWidth / glyphWidth); + textureHeight = (( numGlyphs / h) + 1) * glyphHeight; +} + + +void FTGLTextureFont::CreateTexture( int id, int width, int height, unsigned char* data) +{ + glPixelStorei( GL_UNPACK_ALIGNMENT, 1); //What does this do exactly? + glBindTexture( GL_TEXTURE_2D, glTextureID[id]); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + 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_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data); +} + + +void FTGLTextureFont::render( const char* string) +{ + glPushAttrib( GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_PIXEL_MODE_BIT); + + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE + + glBindTexture( GL_TEXTURE_2D, (GLuint)FTTextureGlyph::activeTextureID); + + // QUADS are faster!? Less function call overhead? + glBegin( GL_QUADS); + FTFont::render( string); + glEnd(); + + glPopAttrib(); +} + + +void FTGLTextureFont::render( const wchar_t* string) +{ + glPushAttrib( GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_PIXEL_MODE_BIT); + + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE + + glBindTexture( GL_TEXTURE_2D, (GLuint)FTTextureGlyph::activeTextureID); + + // QUADS are faster!? Less function call overhead? + glBegin( GL_QUADS); + FTFont::render( string); + glEnd(); + + glPopAttrib(); +} diff --git a/src/osgText/FTGLTextureFont.h b/src/osgText/FTGLTextureFont.h new file mode 100644 index 000000000..81e296bff --- /dev/null +++ b/src/osgText/FTGLTextureFont.h @@ -0,0 +1,54 @@ +#ifndef __FTGLTextureFont +#define __FTGLTextureFont +#include "FTFont.h" + +#include "FTGL.h" + +class FTTextureGlyph; + +/** + * FTGLTextureFont is a specialisation of the FTFont class for handling + * Texture mapped fonts + * + * @see FTFont + */ +class FTGLTextureFont : public FTFont +{ + public: + // methods + FTGLTextureFont(); + virtual ~FTGLTextureFont(); + + virtual int TextureWidth() const { return textureWidth;} + virtual int TextureHeight() const { return textureHeight;} + + virtual void render( const char* string); + virtual void render( const wchar_t* string); + + + private: + // attributes + FTTextureGlyph* tempGlyph; + + long maxTextSize; + int textureWidth; + int textureHeight; + + unsigned long glTextureID[16]; + int numTextures; + unsigned char* textMem; + + int glyphHeight; + int glyphWidth; + + int padding; + + // methods + bool MakeGlyphList(); + void CreateTexture( int id, int width, int height, unsigned char* data); + void GetSize(); + unsigned int FillGlyphs( unsigned int glyphStart, int textID, int textureWidth, int textureHeight, unsigned char* textMem); + + +}; +#endif diff --git a/src/osgText/FTGlyph.cc b/src/osgText/FTGlyph.cc new file mode 100644 index 000000000..de8d87833 --- /dev/null +++ b/src/osgText/FTGlyph.cc @@ -0,0 +1,14 @@ +#include "FTGlyph.h" + + +FTGlyph::FTGlyph() +: advance(0), + err(0) +{ + pos.x = 0; + pos.y = 0; +} + + +FTGlyph::~FTGlyph() +{} diff --git a/src/osgText/FTGlyph.h b/src/osgText/FTGlyph.h new file mode 100644 index 000000000..5002d06df --- /dev/null +++ b/src/osgText/FTGlyph.h @@ -0,0 +1,76 @@ +#ifndef __FTGlyph__ +#define __FTGlyph__ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +//#include "FTGL.h" + +/** + * FTGlyph is the base clas for FTGL glyphs. + * + * It provides the interface between Freetype glyphs and their openGL + * renderable counterparts. This is an abstract class and derived classes + * must implement the render function. + * + * @see FTGlyphContainer + * + */ +class FTGlyph +{ + public: + /** + * Constructor + */ + FTGlyph(); + + /** + * Destructor + */ + virtual ~FTGlyph(); + + /** + * Renders this glyph at the current pen position. + * + * @param pen The current pen position. + * @return The advance distance for this glyph. + */ + virtual float Render( const FT_Vector& pen) = 0; + + /** + * Return the advance width for this glyph. + * + * @return advance width. + */ + float Advance() const { return advance;} + + /** + * Queries for errors. + * + * @return The current error code. + */ + FT_Error Error() const { return err;} + + protected: + /** + * The advance distance for this glyph + */ + float advance; + + /** + * Vector from the pen position to the topleft corner of the glyph + */ + FT_Vector pos; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; + + private: + +}; + + +#endif // __FTGlyph__ diff --git a/src/osgText/FTGlyphContainer.cc b/src/osgText/FTGlyphContainer.cc new file mode 100644 index 000000000..33ea20e51 --- /dev/null +++ b/src/osgText/FTGlyphContainer.cc @@ -0,0 +1,66 @@ +#include "FTGlyphContainer.h" +#include "FTGlyph.h" +#include "FTFace.h" + + +FTGlyphContainer::FTGlyphContainer( FTFace* f, int g, bool p) +: preCache( p), + numGlyphs( g), + face( f), + err( 0) +{ + glyphs.reserve( g); +} + + + +FTGlyphContainer::~FTGlyphContainer() +{ + vector::iterator iter; + for( iter = glyphs.begin(); iter != glyphs.end(); ++iter) + { + delete *iter; + } + + glyphs.clear(); +} + + +bool FTGlyphContainer::Add( FTGlyph* tempGlyph) +{ + // At the moment we are using a vector. Vectors don't return bool. + glyphs.push_back( tempGlyph); + return true; +} + + +float FTGlyphContainer::Advance( unsigned int index, unsigned int next) +{ + unsigned int left = face->CharIndex( index); + unsigned int right = face->CharIndex( next); + + float width = face->KernAdvance( left, right).x; + width += glyphs[left]->Advance(); + + return width; +} + + +FT_Vector& FTGlyphContainer::render( unsigned int index, unsigned int next, FT_Vector pen) +{ + kernAdvance.x = 0; kernAdvance.y = 0; + + unsigned int left = face->CharIndex( index); + unsigned int right = face->CharIndex( next); + + kernAdvance = face->KernAdvance( left, right); + + if( !face->Error()) + { + advance = glyphs[left]->Render( pen); + } + + kernAdvance.x = advance + kernAdvance.x; // FIXME float to long +// kernAdvance.y = advance.y + kernAdvance.y; + return kernAdvance; +} diff --git a/src/osgText/FTGlyphContainer.h b/src/osgText/FTGlyphContainer.h new file mode 100644 index 000000000..c2d3a930c --- /dev/null +++ b/src/osgText/FTGlyphContainer.h @@ -0,0 +1,100 @@ +#ifndef __FTGlyphContainer__ +#define __FTGlyphContainer__ + +#include + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +//#include "FTGL.h" +class FTFace; +class FTGlyph; + +using namespace std; + +/** + * FTGlyphContainer + * + * @see FTGlyph + */ +class FTGlyphContainer +{ + public: + /** + * Constructor + */ + FTGlyphContainer( FTFace* face, int numGlyphs, bool p = false); + + /** + * Destructor + */ + ~FTGlyphContainer(); + + /** + * Adds a glyph to this glyph list. + * + * @param glyph + * @return true + */ + bool Add( FTGlyph* glyph); + + /** + * Returns the kerned advance width for a glyph. + * + * param index glyph index of the character + * param next the next glyph in a string + * return advance width + * + */ + float Advance( unsigned int index, unsigned int next); + + /** + * renders a character + */ + FT_Vector& render( unsigned int index, unsigned int next, FT_Vector pen); + + private: + /** + * + */ + FT_Error err; + + /** + * + */ + bool preCache; + + /** + * + */ + int numGlyphs; + + /** + * + */ + FTFace* face; + + + /** + * + */ + FT_Vector kernAdvance; + + /** + * + */ + float advance; + + /** + * + */ + vector glyphs; +// typedef pair CHARREF; // glyphIndex, glyph +// vector glyphs; +// map< int, FTGlyph*> CHARREF; // charCode, glyph + +}; + + +#endif // __FTGlyphContainer__ diff --git a/src/osgText/FTLibrary.cc b/src/osgText/FTLibrary.cc new file mode 100644 index 000000000..5a6369c1f --- /dev/null +++ b/src/osgText/FTLibrary.cc @@ -0,0 +1,65 @@ +#include "FTLibrary.h" +#include "FTGL.h" + + +FTLibrary& FTLibrary::Instance() +{ + static FTLibrary ftlib; + return ftlib; +} + + +FTLibrary::~FTLibrary() +{ + if( lib != 0) + { + FT_Done_FreeType( *lib); + + delete lib; + lib= 0; + } + +// if( manager != 0) +// { +// FTC_Manager_Done( manager ); +// +// delete manager; +// manager= 0; +// } +} + + +FTLibrary::FTLibrary() +: lib(0), + err(0) +{ + Init(); +} + + +bool FTLibrary::Init() +{ + if( lib != 0 ) + return true; + + lib = new FT_Library; + + err = FT_Init_FreeType( lib); + if( err) + { + delete lib; + lib = 0; + return false; + } + +// FTC_Manager* manager; +// +// if( FTC_Manager_New( lib, 0, 0, 0, my_face_requester, 0, manager ) +// { +// delete manager; +// manager= 0; +// return false; +// } + + return true; +} diff --git a/src/osgText/FTLibrary.h b/src/osgText/FTLibrary.h new file mode 100644 index 000000000..ce922b9c2 --- /dev/null +++ b/src/osgText/FTLibrary.h @@ -0,0 +1,102 @@ +#ifndef __FTLibrary__ +#define __FTLibrary__ + + +#include +#include FT_FREETYPE_H +//#include FT_CACHE_H + +#include "FTGL.h" + + +/** + * FTLibrary class is the global accessor for the Freetype library. + * + * This class encapsulates the Freetype Library. This is a singleton class + * and ensures that only one FT_Library is in existence at any one time. + * All constructors are private therefore clients cannot create or + * instantiate this class themselves and must access it's methods via the + * static FTLibrary::Instance() function. + * + * Just because this class returns a valid FTLibrary object + * doesn't mean that the Freetype Library has been successfully initialised. + * Clients should check for errors. You can initialse the library AND check + * for errors using the following code... + * err = FTLibrary::Instance().Error(); + * + * @see "Freetype 2 Documentation - 2.0.4" + * + */ +class FTLibrary +{ + public: + // methods + /** + * Global acces point to the single FTLibrary object. + * + * @return The global FTLibrary object. + */ + static FTLibrary& Instance(); + + /** + * Gets a pointer to the native Freetype library. + * + * @return A handle to a FreeType library instance. + */ + FT_Library* GetLibrary() const { return lib;} + + /** + * Queries the library for errors. + * + * @return The current error code. + */ + virtual FT_Error Error() const { return err;} + + /** + * Destructor + * + * Disposes of the Freetype library + */ + virtual ~FTLibrary(); + + // attributes + + private: + // methods + /** + * Default constructors. + * + * Made private to stop clients creating there own FTLibrary + * objects. + */ + FTLibrary(); + FTLibrary( const FT_Library&){} + FTLibrary& operator=( const FT_Library&){} + + /** + * Initialises the Freetype library + * + * Even though this function indicates success via the return value, + * clients can't see this so must check the error codes. + * + * @return true if the Freetype library was + * successfully initialised, false + * otherwise. + */ + bool Init(); + + // attributes + /** + * Freetype library handle. + */ + FT_Library* lib; +// FTC_Manager* manager; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; + + +}; +#endif // __FTLibrary__ diff --git a/src/osgText/FTOutlineGlyph.cc b/src/osgText/FTOutlineGlyph.cc new file mode 100644 index 000000000..8e5387112 --- /dev/null +++ b/src/osgText/FTOutlineGlyph.cc @@ -0,0 +1,83 @@ +#include "GL/gl.h" + +#include "FTOutlineGlyph.h" +#include "FTVectoriser.h" +#include "FTGL.h" + + + +FTOutlineGlyph::FTOutlineGlyph( FT_Glyph glyph) +: FTGlyph(), + vectoriser(0), + numPoints(0), + numContours(0), + contourLength(0), + data(0), + glList(0) +{ + if( ft_glyph_format_outline != glyph->format) + { + return; + } + + vectoriser = new FTVectoriser( glyph); + + vectoriser->Ingest(); + numContours = vectoriser->contours(); + contourLength = new int[ numContours]; + + for( int cn = 0; cn < numContours; ++cn) + { + contourLength[cn] = vectoriser->contourSize( cn); + } + + numPoints = vectoriser->points(); + data = new double[ numPoints * 3]; + vectoriser->Output( data); + + advance = glyph->advance.x >> 16; + + delete vectoriser; + + if ( ( numContours < 1) || ( numPoints < 3)) + return; + + glList = glGenLists(1); + int d = 0; + + glNewList( glList, GL_COMPILE); + for( int c = 0; c < numContours; ++c) + { + glBegin( GL_LINE_LOOP); + for( int p = 0; p < ( contourLength[c]); ++p) + { + glVertex2dv( data + d); + d += 3; + } + glEnd(); + } + glEndList(); + + // discard glyph image (bitmap or not) + FT_Done_Glyph( glyph); // Why does this have to be HERE +} + + +FTOutlineGlyph::~FTOutlineGlyph() +{ + delete [] data; + delete [] contourLength; +} + + +float FTOutlineGlyph::Render( const FT_Vector& pen) +{ + if( glList) + { + glTranslatef( pen.x, pen.y, 0); + glCallList( glList); + glTranslatef( -pen.x, -pen.y, 0); + } + + return advance; +} diff --git a/src/osgText/FTOutlineGlyph.h b/src/osgText/FTOutlineGlyph.h new file mode 100644 index 000000000..eb2dd37e2 --- /dev/null +++ b/src/osgText/FTOutlineGlyph.h @@ -0,0 +1,36 @@ +#ifndef __FTOutlineGlyph__ +#define __FTOutlineGlyph__ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGlyph.h" + +class FTVectoriser; + +class FTOutlineGlyph : public FTGlyph +{ + public: + // methods + FTOutlineGlyph( FT_Glyph glyph); + virtual ~FTOutlineGlyph(); + virtual float Render( const FT_Vector& pen); + + // attributes + + private: + // methods + + // attributes + FTVectoriser* vectoriser; + int numPoints; + int numContours; + int* contourLength; + double* data; + int glList; + +}; + + +#endif // __FTOutlineGlyph__ diff --git a/src/osgText/FTPixmapGlyph.cc b/src/osgText/FTPixmapGlyph.cc new file mode 100644 index 000000000..1970be9ff --- /dev/null +++ b/src/osgText/FTPixmapGlyph.cc @@ -0,0 +1,94 @@ +#include "GL/gl.h" + +#include "FTPixmapGlyph.h" +#include "FTGL.h" + + +FTPixmapGlyph::FTPixmapGlyph( FT_Glyph glyph) +: FTGlyph(), + destWidth(0), + destHeight(0), + numGreys(0), + data(0) +{ + // This function will always fail if the glyph's format isn't scalable???? + FT_Error err = FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1); + if( err || ft_glyph_format_bitmap != glyph->format) + { + return; + } + + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; + FT_Bitmap* source = &bitmap->bitmap; + + //check the pixel mode + //ft_pixel_mode_grays + + int srcWidth = source->width; + int srcHeight = source->rows; + int srcPitch = source->pitch; + + numGreys = source->num_grays; + advance = glyph->advance.x >> 16; + + pos.x = bitmap->left; + pos.y = srcHeight - bitmap->top; + + // FIXME What about dest alignment? + destWidth = srcWidth; + destHeight = srcHeight; + + data = new unsigned char[destWidth * destHeight * 4]; + + // Get the current glColor. + float ftglColour[4]; + glGetFloatv( GL_CURRENT_COLOR, ftglColour); + + for(int y = 0; y < srcHeight; ++y) + { + --destHeight; + for(int x = 0; x < srcWidth; ++x) + { + *( data + ( destHeight * destWidth + x) * 4 + 0) = static_cast( ftglColour[0] * 255.0f); + *( data + ( destHeight * destWidth + x) * 4 + 1) = static_cast( ftglColour[1] * 255.0f); + *( data + ( destHeight * destWidth + x) * 4 + 2) = static_cast( ftglColour[2] * 255.0f); + *( data + ( destHeight * destWidth + x) * 4 + 3) = static_cast( ftglColour[3] * (*( source->buffer + ( y * srcPitch) + x))); + } + } + + destHeight = srcHeight; + + // discard glyph image (bitmap or not) + // Is this the right place to do this? + FT_Done_Glyph( glyph ); +} + + +FTPixmapGlyph::~FTPixmapGlyph() +{ + delete[] data; +} + + +float FTPixmapGlyph::Render( const FT_Vector& pen) +{ + if( data != 0 ) + { + glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT); + + // Move the glyph origin + glBitmap( 0, 0, 0.0, 0.0, pen.x + pos.x, pen.y - pos.y, (const GLubyte *)0); + + glPixelStorei( GL_UNPACK_ROW_LENGTH, destWidth); + + glDrawPixels( destWidth, destHeight, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)data); + + + // Restore the glyph origin + glBitmap( 0, 0, 0.0, 0.0, -pen.x - pos.x, -pen.y + pos.y, (const GLubyte *)0); + + glPopClientAttrib(); + } + + return advance; +} diff --git a/src/osgText/FTPixmapGlyph.h b/src/osgText/FTPixmapGlyph.h new file mode 100644 index 000000000..3485e8d87 --- /dev/null +++ b/src/osgText/FTPixmapGlyph.h @@ -0,0 +1,35 @@ +#ifndef __FTPixmapGlyph__ +#define __FTPixmapGlyph__ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGlyph.h" + + +class FTPixmapGlyph : public FTGlyph +{ + public: + // methods + FTPixmapGlyph( FT_Glyph glyph); + virtual ~FTPixmapGlyph(); + virtual float Render( const FT_Vector& pen); + + // attributes + + private: + // methods + + // attributes + int destWidth; + int destHeight; + + int numGreys; + + unsigned char* data; + +}; + + +#endif // __FTPixmapGlyph__ diff --git a/src/osgText/FTPolyGlyph.cc b/src/osgText/FTPolyGlyph.cc new file mode 100644 index 000000000..f400bbecd --- /dev/null +++ b/src/osgText/FTPolyGlyph.cc @@ -0,0 +1,156 @@ +#include "GL/gl.h" +#include "GL/glu.h" + +#include "FTPolyGlyph.h" +#include "FTVectoriser.h" +#include "FTGL.h" + + +#ifndef CALLBACK +#define CALLBACK +#endif + + +void CALLBACK ftglError( GLenum errCode) +{ +// const GLubyte* estring; +// estring = gluErrorString( errCode); +// fprintf( stderr, "ERROR : %s\n", estring); +// exit(1); +} + +void CALLBACK ftglVertex( void* data) +{ + glVertex3dv( (double*)data); +} + + +void CALLBACK ftglBegin( GLenum type) +{ + glBegin( type); +} + + +void CALLBACK ftglEnd() +{ + glEnd(); +} + + +void CALLBACK ftglCombine( GLdouble coords[3], void* vertex_data[4], GLfloat weight[4], void** outData) +{ + double* vertex = new double[3]; // FIXME MEM LEAK + + vertex[0] = coords[0]; + vertex[1] = coords[1]; + vertex[2] = coords[2]; + + *outData = vertex; +} + + +FTPolyGlyph::FTPolyGlyph( FT_Glyph glyph) +: FTGlyph(), + vectoriser(0), + numPoints(0), + numContours(0), + contourLength(0), + data(0), + glList(0) +{ + if( ft_glyph_format_outline != glyph->format) + { return;} + + vectoriser = new FTVectoriser( glyph); + + vectoriser->Ingest(); + numContours = vectoriser->contours(); + contourLength = new int[ numContours]; + + for( int c = 0; c < numContours; ++c) + { + contourLength[c] = vectoriser->contourSize( c); + } + + numPoints = vectoriser->points(); + data = new double[ numPoints * 3]; + vectoriser->Output( data); + + contourFlag = vectoriser->ContourFlag(); + advance = glyph->advance.x >> 16; + + delete vectoriser; + + if ( ( numContours < 1) || ( numPoints < 3)) + return; + + Tesselate(); + + // discard glyph image (bitmap or not) + FT_Done_Glyph( glyph); // Why does this have to be HERE +} + + +void FTPolyGlyph::Tesselate() +{ + glList = glGenLists(1); + GLUtesselator* tobj = gluNewTess(); + int d = 0; + + gluTessCallback( tobj, GLU_TESS_BEGIN, (void (CALLBACK*)())ftglBegin); + gluTessCallback( tobj, GLU_TESS_VERTEX, (void (CALLBACK*)())ftglVertex); + gluTessCallback( tobj, GLU_TESS_COMBINE, (void (CALLBACK*)())ftglCombine); + gluTessCallback( tobj, GLU_TESS_END, ftglEnd); + gluTessCallback( tobj, GLU_TESS_ERROR, (void (CALLBACK*)())ftglError); + + glNewList( glList, GL_COMPILE); + + if( contourFlag & ft_outline_even_odd_fill) // ft_outline_reverse_fill + { + gluTessProperty( tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); + } + else + { + gluTessProperty( tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); + } + + gluTessProperty( tobj, GLU_TESS_TOLERANCE, 0); + gluTessBeginPolygon( tobj, NULL); + + for( int c = 0; c < numContours; ++c) + { + gluTessBeginContour( tobj); + for( int p = 0; p < ( contourLength[c]); ++p) + { + gluTessVertex( tobj, data + d, data + d); + d += 3; + } + gluTessEndContour( tobj); + } + + gluTessEndPolygon( tobj); + + glEndList(); + + gluDeleteTess( tobj); +} + + +FTPolyGlyph::~FTPolyGlyph() +{ + delete [] data; + delete [] contourLength; +} + + +float FTPolyGlyph::Render( const FT_Vector& pen) +{ + if( glList) + { + glTranslatef( pen.x, pen.y, 0); + glCallList( glList); + glTranslatef( -pen.x, -pen.y, 0); + } + + return advance; +} diff --git a/src/osgText/FTPolyGlyph.h b/src/osgText/FTPolyGlyph.h new file mode 100644 index 000000000..7682fcda2 --- /dev/null +++ b/src/osgText/FTPolyGlyph.h @@ -0,0 +1,38 @@ +#ifndef __FTPolyGlyph__ +#define __FTPolyGlyph__ + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGlyph.h" + +class FTVectoriser; + +class FTPolyGlyph : public FTGlyph +{ + public: + // methods + FTPolyGlyph( FT_Glyph glyph); + virtual ~FTPolyGlyph(); + virtual float Render( const FT_Vector& pen); + + // attributes + + private: + // methods + void Tesselate(); + + // attributes + FTVectoriser* vectoriser; + int numPoints; + int numContours; + int contourFlag; + int* contourLength; + double* data; + int glList; + +}; + + +#endif // __FTPolyGlyph__ diff --git a/src/osgText/FTSize.cc b/src/osgText/FTSize.cc new file mode 100644 index 000000000..f5bf65f89 --- /dev/null +++ b/src/osgText/FTSize.cc @@ -0,0 +1,91 @@ +#include "FTSize.h" +#include "FTGL.h" + + +FTSize::FTSize() +: size(0), + ftFace(0), + err(0) +{} + + +FTSize::~FTSize() +{} + + +bool FTSize::CharSize( FT_Face* face, unsigned int point_size, unsigned int x_resolution, unsigned int y_resolution ) +{ + ftFace = face; + size = point_size; + err = FT_Set_Char_Size( *ftFace, 0L, point_size * 64, x_resolution, y_resolution); + + ftSize = (*ftFace)->size; + + return !err; +} + + +int FTSize::Ascender() const +{ + return ftSize->metrics.ascender >> 6; +} + + +int FTSize::Descender() const +{ + return ftSize->metrics.descender >> 6; +} + + +int FTSize::Height() const +{ + if( FT_IS_SCALABLE((*ftFace))) + { + float height; + if( FT_IS_SFNT((*ftFace))) // Don't think this is correct + { + height = (*ftFace)->bbox.yMax - (*ftFace)->bbox.yMin; // bbox.yMax-bbox.yMin + } + else + { + height = (*ftFace)->bbox.yMax - (*ftFace)->bbox.yMin >> 16; // bbox.yMax-bbox.yMin + } + + height = height * ( (float)ftSize->metrics.y_ppem / (float)(*ftFace)->units_per_EM); + return static_cast(height); + } + else + { + return ftSize->metrics.height >> 6; + } +} + + +int FTSize::Width() const +{ + if( FT_IS_SCALABLE((*ftFace))) + { + float width; + if( FT_IS_SFNT((*ftFace))) // Don't think this is correct + { + width = ((*ftFace)->bbox.xMax - (*ftFace)->bbox.xMin); // bbox.xMax-bbox.xMin + } + else + { + width = ((*ftFace)->bbox.xMax - (*ftFace)->bbox.xMin) >> 16; // bbox.xMax-bbox.xMin + } + + width = width * ( (float)ftSize->metrics.x_ppem / (float)(*ftFace)->units_per_EM); + return static_cast(width); + } + else + { + return ftSize->metrics.max_advance >> 6; + } +} + + +int FTSize::Underline() const +{ + return 0; +} diff --git a/src/osgText/FTSize.h b/src/osgText/FTSize.h new file mode 100644 index 000000000..774c8d95e --- /dev/null +++ b/src/osgText/FTSize.h @@ -0,0 +1,118 @@ +#ifndef __FTSize__ +#define __FTSize__ + +#include +#include FT_FREETYPE_H + +#include "FTGL.h" + + +/** + * FTSize class provides an abstraction layer for the Freetype Size. + * + * @see "Freetype 2 Documentation - 2.0.4" + * + */ +class FTSize +{ + public: + /** + * Default Constructor + */ + FTSize(); + + /** + * Destructor + */ + virtual ~FTSize(); + + /** + * Sets the char size for the current face. + * + * This doesn't guarantee that the size was set correctly. Clients + * should check errors. + * + * @param point_size the face size in points (1/72 inch) + * @param x_resolution the horizontal resolution of the target device. + * @param y_resolution the vertical resolution of the target device. + * @return true if the size has been set. Clients should check Error() for more information if this function returns false() + */ + bool CharSize( FT_Face* face, unsigned int point_size, unsigned int x_resolution, unsigned int y_resolution ); + + /** + * Gets the global ascender height for the face in pixels. + * + * @return Ascender height + */ + int Ascender() const; + + /** + * Gets the global descender height for the face in pixels. + * + * @return Ascender height + */ + int Descender() const; + + /** + * Gets the global face height for the face. + * + * If the face is scalable this returns the height of the global + * bounding box which ensures that any glyph will be less than or + * equal to this height. If the font isn't scalable there is no + * guarantee that glyphs will not be taller than this value. + * + * @return height in pixels. + */ + int Height() const; + + /** + * Gets the global face width for the face. + * + * If the face is scalable this returns the width of the global + * bounding box which ensures that any glyph will be less than or + * equal to this width. If the font isn't scalable this value is + * the max_advance for the face. + * + * @return width in pixels. + */ + int Width() const; + + /** + * Gets the underline position for the face. + * + * @return underline position in pixels + */ + int Underline() const; + + + /** + * Queries for errors. + * + * @return The current error code. + */ + FT_Error Error() const { return err; } + + private: + /** + * The current Freetype face that this FTSize object relates to. + */ + FT_Face* ftFace; + + /** + * The Freetype size. + */ + FT_Size ftSize; + + /** + * The size in points. + */ + unsigned int size; + + /** + * Current error code. Zero means no error. + */ + FT_Error err; + +}; + +#endif // __FTSize__ diff --git a/src/osgText/FTTextureGlyph.cc b/src/osgText/FTTextureGlyph.cc new file mode 100644 index 000000000..d15f8787d --- /dev/null +++ b/src/osgText/FTTextureGlyph.cc @@ -0,0 +1,92 @@ +#include "GL/gl.h" + +#include "FTTextureGlyph.h" +#include "FTGL.h" + + +int FTTextureGlyph::activeTextureID = 0; + +FTTextureGlyph::FTTextureGlyph( FT_Glyph glyph, int id, unsigned char* data, int stride, int height, float u, float v) +: FTGlyph(), + destWidth(0), + destHeight(0), + numGreys(0), + glTextureID(id) +{ + // This function will always fail if the glyph's format isn't scalable???? + err = FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1); + if( err || glyph->format != ft_glyph_format_bitmap) + { + return; + } + + FT_BitmapGlyph bitmap = ( FT_BitmapGlyph)glyph; + FT_Bitmap* source = &bitmap->bitmap; + + //check the pixel mode + //ft_pixel_mode_grays + + int srcWidth = source->width; + int srcHeight = source->rows; + int srcPitch = source->pitch; + + numGreys = source->num_grays; + advance = glyph->advance.x >> 16; + + pos.x = bitmap->left; + pos.y = bitmap->top; + + destWidth = srcWidth; + destHeight = srcHeight; + + for(int y = 0; y < srcHeight; ++y) + { + for(int x = 0; x < srcWidth; ++x) + { + *( data + ( y * stride + x)) = *( source->buffer + ( y * srcPitch) + x); + } + } + +// 0 +// +----+ +// | | +// | | +// | | +// +----+ +// 1 + + uv[0].x = u; + uv[0].y = v; + uv[1].x = uv[0].x + ( (float)destWidth / (float)stride); + uv[1].y = uv[0].y + ( (float)destHeight / (float)height); + + // discard glyph image (bitmap or not) + // Is this the right place to do this? + FT_Done_Glyph( glyph); +} + + +FTTextureGlyph::~FTTextureGlyph() +{ + +} + + +float FTTextureGlyph::Render( const FT_Vector& pen) +{ + // This could be really ugly!! + if( activeTextureID != glTextureID) + { + glEnd(); + glBindTexture( GL_TEXTURE_2D, (GLuint)glTextureID); + activeTextureID = glTextureID; + glBegin( GL_QUADS); + } + + glTexCoord2f( uv[0].x, uv[0].y); glVertex2f( pen.x + pos.x, pen.y + pos.y); + glTexCoord2f( uv[1].x, uv[0].y); glVertex2f( pen.x + destWidth + pos.x, pen.y + pos.y); + glTexCoord2f( uv[1].x, uv[1].y); glVertex2f( pen.x + destWidth + pos.x, pen.y + pos.y - destHeight); + glTexCoord2f( uv[0].x, uv[1].y); glVertex2f( pen.x + pos.x, pen.y + pos.y - destHeight); + + return advance; +} diff --git a/src/osgText/FTTextureGlyph.h b/src/osgText/FTTextureGlyph.h new file mode 100644 index 000000000..bac8d4c9c --- /dev/null +++ b/src/osgText/FTTextureGlyph.h @@ -0,0 +1,40 @@ +#ifndef __FTTextureGlyph__ +#define __FTTextureGlyph__ + + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGlyph.h" + + +class FTTextureGlyph : public FTGlyph +{ + public: + // methods + FTTextureGlyph( FT_Glyph glyph, int id, unsigned char* data, int stride, int height, float u, float v); + virtual ~FTTextureGlyph(); + virtual float Render( const FT_Vector& pen); + + static int activeTextureID; + private: + // attributes + // What about the other point class in vectoriser? + struct FTPoint + { + float x; + float y; + }; + + int destWidth; + int destHeight; + + int numGreys; + + FTPoint uv[2]; + int glTextureID; +}; + + +#endif // __FTTextureGlyph__ diff --git a/src/osgText/FTVectoriser.cc b/src/osgText/FTVectoriser.cc new file mode 100644 index 000000000..54c66ac15 --- /dev/null +++ b/src/osgText/FTVectoriser.cc @@ -0,0 +1,227 @@ +#include "FTVectoriser.h" +#include "FTGL.h" + + +FTContour::FTContour() +: kMAXPOINTS( 1000) +{ + pointList.reserve( kMAXPOINTS); +} + + +FTContour::~FTContour() +{ + pointList.clear(); +} + + +void FTContour::AddPoint( const float x, const float y) +{ + ftPoint point( x, y, 0.0); + + // Eliminate duplicate points. + if( pointList.empty() || ( pointList[pointList.size() - 1] != point && pointList[0] != point)) + { + pointList.push_back( point); + } +} + + +FTVectoriser::FTVectoriser( const FT_Glyph glyph) +: contourFlag(0), + contour(0), + kBSTEPSIZE( 0.2) +{ + FT_OutlineGlyph outline = (FT_OutlineGlyph)glyph; + ftOutline = outline->outline; + + contourList.reserve( ftOutline.n_contours); +} + + +FTVectoriser::~FTVectoriser() +{ + for( int c = 0; c < contours(); ++c) + { + delete contourList[c]; + } + + contourList.clear(); +} + + +int FTVectoriser::points() +{ + int s = 0; + for( int c = 0; c < contours(); ++c) + { + s += contourList[c]->size(); + } + + return s; +} + + +bool FTVectoriser::Ingest() +{ + short first = 0; + short last; + const short cont = ftOutline.n_contours; + + for( short c = 0; c < cont; ++c) + { + contour = new FTContour; + contourFlag = ftOutline.flags; + last = ftOutline.contours[c]; + + for( short p = first; p <= last; ++p) + { + switch( ftOutline.tags[p]) + { + case FT_Curve_Tag_Conic: + p += Conic( p, first, last); + break; + case FT_Curve_Tag_Cubic: + p += Cubic( p, first, last); + break; + case FT_Curve_Tag_On: + default: + contour->AddPoint( ftOutline.points[p].x, ftOutline.points[p].y); + } + } + + contourList.push_back( contour); + first = last + 1; + } + + return true; +} + + +int FTVectoriser::Conic( const int index, const int first, const int last) +{ + int next = index + 1; + int prev = index - 1; + + if( index == last) + next = first; + + if( index == first) + prev = last; + + if( ftOutline.tags[next] != FT_Curve_Tag_Conic) + { + ctrlPtArray[0][0] = ftOutline.points[prev].x; ctrlPtArray[0][1] = ftOutline.points[prev].y; + ctrlPtArray[1][0] = ftOutline.points[index].x; ctrlPtArray[1][1] = ftOutline.points[index].y; + ctrlPtArray[2][0] = ftOutline.points[next].x; ctrlPtArray[2][1] = ftOutline.points[next].y; + + evaluateCurve( 2); + return 1; + } + else + { + int next2 = next + 1; + if( next == last) + next2 = first; + + //create a phantom point + float x = ( ftOutline.points[index].x + ftOutline.points[next].x) / 2; + float y = ( ftOutline.points[index].y + ftOutline.points[next].y) / 2; + + // process first curve + ctrlPtArray[0][0] = ftOutline.points[prev].x; ctrlPtArray[0][1] = ftOutline.points[prev].y; + ctrlPtArray[1][0] = ftOutline.points[index].x; ctrlPtArray[1][1] = ftOutline.points[index].y; + ctrlPtArray[2][0] = x; ctrlPtArray[2][1] = y; + + evaluateCurve( 2); + + // process second curve + ctrlPtArray[0][0] = x; ctrlPtArray[0][1] = y; + ctrlPtArray[1][0] = ftOutline.points[next].x; ctrlPtArray[1][1] = ftOutline.points[next].y; + ctrlPtArray[2][0] = ftOutline.points[next2].x; ctrlPtArray[2][1] = ftOutline.points[next2].y; + evaluateCurve( 2); + + return 2; + } +} + + +int FTVectoriser::Cubic( const int index, const int first, const int last) +{ + int next = index + 1; + int prev = index - 1; + + if( index == last) + next = first; + + int next2 = next + 1; + + if( next == last) + next2 = first; + + if( index == first) + prev = last; + + ctrlPtArray[0][0] = ftOutline.points[prev].x; ctrlPtArray[0][1] = ftOutline.points[prev].y; + ctrlPtArray[1][0] = ftOutline.points[index].x; ctrlPtArray[1][1] = ftOutline.points[index].y; + ctrlPtArray[2][0] = ftOutline.points[next].x; ctrlPtArray[2][1] = ftOutline.points[next].y; + ctrlPtArray[3][0] = ftOutline.points[next2].x; ctrlPtArray[3][1] = ftOutline.points[next2].y; + + evaluateCurve( 3); + return 2; +} + + +// De Casteljau algorithm contributed by Jed Soane +void FTVectoriser::deCasteljau( const float t, const int n) +{ + //Calculating successive b(i)'s using de Casteljau algorithm. + for( int i = 1; i <= n; i++) + for( int k = 0; k <= (n - i); k++) + { + bValues[i][k][0] = (1 - t) * bValues[i - 1][k][0] + t * bValues[i - 1][k + 1][0]; + bValues[i][k][1] = (1 - t) * bValues[i - 1][k][1] + t * bValues[i - 1][k + 1][1]; + } + + //Specify next vertex to be included on curve + contour->AddPoint( bValues[n][0][0], bValues[n][0][1]); +} + + +// De Casteljau algorithm contributed by Jed Soane +void FTVectoriser::evaluateCurve( const int n) +{ + // setting the b(0) equal to the control points + for( int i = 0; i <= n; i++) + { + bValues[0][i][0] = ctrlPtArray[i][0]; + bValues[0][i][1] = ctrlPtArray[i][1]; + } + + float t; //parameter for curve point calc. [0.0, 1.0] + + for( int m = 0; m <= ( 1 / kBSTEPSIZE); m++) + { + t = m * kBSTEPSIZE; + deCasteljau( t, n); //calls to evaluate point on curve att. + } +} + + +void FTVectoriser::Output( double* data) +{ + int i = 0; + + for( int c= 0; c < contours(); ++c) + { + const FTContour* contour = contourList[c]; + + for( int p = 0; p < contour->size(); ++p) + { + data[i] = static_cast(contour->pointList[p].x / 64.0f); // is 64 correct? + data[i + 1] = static_cast(contour->pointList[p].y / 64.0f); + data[i + 2] = 0.0; // static_cast(contour->pointList[p].z / 64.0f); + i += 3; + } + } +} diff --git a/src/osgText/FTVectoriser.h b/src/osgText/FTVectoriser.h new file mode 100644 index 000000000..fb2d8b660 --- /dev/null +++ b/src/osgText/FTVectoriser.h @@ -0,0 +1,104 @@ +#ifndef __FTVectoriser__ +#define __FTVectoriser__ + +#include + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include "FTGlyph.h" + +using namespace std; + +class ftPoint +{ + public: + ftPoint() + : x(0), y(0), z(0) + {} + + ftPoint( const float X, const float Y, const float Z) + : x(X), y(Y), z(Z) + {} + + friend bool operator == ( const ftPoint &a, const ftPoint &b) + { + return((a.x == b.x) && (a.y == b.y) && (a.z == b.z)); + } + + friend bool operator != ( const ftPoint &a, const ftPoint &b) + { + return((a.x != b.x) || (a.y != b.y) || (a.z != b.z)); + } + + float x, y, z; // FIXME make private + + private: +}; + + +class FTContour +{ + public: + // methods + FTContour(); + ~FTContour(); + + void AddPoint( const float x, const float y); + + int size() const { return pointList.size();} + + // attributes + vector< ftPoint> pointList; + float ctrlPtArray[4][2]; + + private: + // methods + + // attributes + const unsigned int kMAXPOINTS; +}; + + +class FTVectoriser +{ + public: + // methods + FTVectoriser( FT_Glyph glyph); + virtual ~FTVectoriser(); + + bool Ingest(); + void Output( double* d); + int points(); + int contours() const { return contourList.size();} + int contourSize( int c) const { return contourList[c]->size();} + int ContourFlag() const { return contourFlag;} + + // attributes + + private: + // methods + int Conic( const int index, const int first, const int last); + int Cubic( const int index, const int first, const int last); + void deCasteljau( const float t, const int n); + void evaluateCurve( const int n); + + // attributes + vector< const FTContour*> contourList; + + FTContour* contour; + int contourFlag; + + FT_Outline ftOutline; + + // Magic numbers -- #define MAX_DEG 4 + float bValues[4][4][2]; //3D array storing values of de Casteljau algorithm. + float ctrlPtArray[4][2]; // Magic numbers + + const float kBSTEPSIZE; + +}; + + +#endif // __FTVectoriser__ diff --git a/src/osgText/Makefile b/src/osgText/Makefile new file mode 100644 index 000000000..13ee5a95c --- /dev/null +++ b/src/osgText/Makefile @@ -0,0 +1,29 @@ +#!smake +include ../../Make/makedefs + +C++FILES = \ + GLUTEventAdapter.cpp\ + Version.cpp\ + Window.cpp\ + Viewer.cpp\ + +TARGET_BASENAME = osgGLUT + + +LIBS = -L../../lib -losgDB -losgUtil -losg $(GLUTLIB) -lGLU -lGL -lm + +LIB = ../../lib/lib$(TARGET_BASENAME).so +#LIB = ../../lib/lib$(TARGET_BASENAME).a + +TARGET_LIB_FILES = lib$(TARGET_BASENAME).so +TARGET_INCLUDE_FILES = \ + osgGLUT/Export\ + osgGLUT/GLUTEventAdapter\ + osgGLUT/Version\ + osgGLUT/Window\ + osgGLUT/Viewer\ + +C++FLAGS += -I ../../include + +include ../../Make/makerules + diff --git a/src/osgText/Text.cpp b/src/osgText/Text.cpp new file mode 100644 index 000000000..7196d3d82 --- /dev/null +++ b/src/osgText/Text.cpp @@ -0,0 +1,665 @@ +/* -------------------------------------------------------------------------- + * + * openscenegraph textLib / FTGL + * + * -------------------------------------------------------------------------- + * + * prog: max rheiner;mrn@paus.ch + * date: 4/25/2001 (m/d/y) + * + * ---------------------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + */ + + +#include + +using namespace osgText; + + +/////////////////////////////////////////////////////////////////////////////// +// Font +Font:: +Font() +{ + _init=false; + _font=NULL; + _created=false; + + _pointSize=14; + _res=72; +} + +bool Font:: +init(const std::string& font) +{ + _font=NULL; + _created=false; + + open(font); + + if(_font!=NULL) + return true; + else + return false; +} + +Font:: +~Font() +{ + clear(); +} + +bool Font:: +open(const std::string& font) +{ + clear(); + + _font=createFontObj(); + if( _font!=NULL && _font->Open(font.c_str()) ) + { + _init=true; + _fontName=font; + return true; + } + else + return false; +} + +bool Font:: +create(int pointSize,const unsigned int res) +{ + _pointSize=pointSize; + _res=res; + + return create(); +} + +bool Font:: +create() +{ + if(_init) + { + if(_font->FaceSize(_pointSize,_res)) + { + _created=true; + return true; + } + else + return false; + } + else + return false; +} + +void Font:: +output(const char* text) +{ + if(_created) + _font->render(text); + else + create(_pointSize); +} + +void Font:: +clear() +{ + _init=false; + + if(_font) + { + delete _font; + _font=NULL; + } + + _fontName=""; +} + +float Font:: +getWidth(const char* text) const +{ + if(_init && _created) + return _font->Advance(text); + else + return -1; +} + +int Font:: +getHeight() const +{ + if(_init && _created) + return _pointSize; + else + return -1; +} + +int Font:: +getDescender() const +{ + if(_init && _created) + return _font->Descender(); + else + return -1; +} + +int Font:: +getAscender() const +{ + if(_init && _created) + return _font->Ascender(); + else + return -1; +} + + +// Font +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// BitmapFont + +BitmapFont:: +BitmapFont(const std::string& font, + int point_size): +RasterFont() +{ + if(init(font)) + { + } + _pointSize=point_size; +} + +FTFont* BitmapFont:: +createFontObj(void) +{ + return (FTFont*)(new FTGLBitmapFont); +} + +// BitmapFont +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// PixmapFont + +PixmapFont:: +PixmapFont(const std::string& font, + int point_size): +RasterFont(font) +{ + if(init(font)) + { + } + _pointSize=point_size; +} + + +FTFont* PixmapFont:: +createFontObj(void) +{ + return (FTFont*)(new FTGLPixmapFont); +} + +// PixmapFont +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// PixmapFont + +TextureFont:: +TextureFont(const std::string& font, + int point_size): +RasterFont(font) +{ + if(init(font)) + { + } + _pointSize=point_size; +} + + +FTFont* TextureFont:: +createFontObj(void) +{ + return (FTFont*)(new FTGLTextureFont); +} + +// PixmapFont +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// _FTGLOutlineFont + +OutlineFont:: +OutlineFont(const std::string& font, + int point_size, + double precision): +VectorFont(font) +{ + if(init(font)) + { + } + _pointSize=point_size; + _precision=precision; +} + + +FTFont* OutlineFont:: +createFontObj(void) +{ + return (FTFont*)(new FTGLOutlineFont); +} + +// _FTGLOutlineFont +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// PolygonFont + +PolygonFont:: +PolygonFont(const std::string& font, + int point_size, + double precision): +VectorFont(font) +{ + if(init(font)) + { + } + _pointSize=point_size; + _precision=precision; +} + +FTFont* PolygonFont:: +createFontObj(void) +{ + return (FTFont*)(new FTGLPolygonFont); +} + + +// PolygonFont +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Text +Text:: +Text() +{ + setDefaults(); +} + +Text:: +Text(Font* font) +{ + setDefaults(); + + if(font && font->isOk()) + { + _init=true; + _font=font; + + if(dynamic_cast(_font.get())) + _fontType=POLYGON; + else if(dynamic_cast(_font.get())) + _fontType=BITMAP; + else if(dynamic_cast(_font.get())) + _fontType=PIXMAP; + else if(dynamic_cast(_font.get())) + _fontType=TEXTURE; + else if(dynamic_cast(_font.get())) + _fontType=OUTLINE; + + } +} + +Text:: +~Text() +{ +} + +void Text:: +setDefaults() +{ + _init=false; + + _pos.set(0,0,0); + _alignementPos.set(0,0,0); + + _fontType=UNDEF; + _alignement=LEFT_BOTTOM; + _drawMode=DrawModeType::DEFAULT; + + _boundingBoxType=GLYPH; + _boundingBoxType=GEOMETRY; + + _initAlignement=false; + + _useDisplayList=false; +} + +const bool Text:: +computeBound() const +{ + if(!_init) + { + _bbox_computed=false; + return true; + } + + // culling + if(_font->isCreated()) + { // ready to get the siz + _bbox.init(); + + Vec3 min,max; + calcBounds(&min,&max); + + _bbox.expandBy(min); + _bbox.expandBy(max); + + _bbox_computed=true; + } + else + { // have to wait for the init. + _bbox.init(); + + // to be sure that the obj isn't culled + _bbox.expandBy(_pos + Vec3(-100,-100,-100)); + _bbox.expandBy(_pos + Vec3(100,100,100)); + /* + _bbox.expandBy(Vec3(-FLT_MAX,-FLT_MAX,-FLT_MAX)); + _bbox.expandBy(Vec3(FLT_MAX,FLT_MAX,FLT_MAX)); + */ + _bbox_computed=true; + + } + return true; +} + +void Text:: +drawImmediateMode(State& state) +{ + if(!_init) + return; + + if(!_font->isCreated()) + { + _font->create(); + dirtyBound(); + } + + if(!_initAlignement) + initAlignement(); + + // draw boundingBox + if(_drawMode & BOUNDINGBOX) + drawBoundingBox(); + // draw alignement + if(_drawMode & ALIGNEMENT) + drawAlignement(); + + // draw boundingBox + if(_drawMode & TEXT) + { + Vec3 drawPos(_pos+_alignementPos); + glPushMatrix(); + switch(_fontType) + { + case POLYGON: + glTranslatef(drawPos.x(),drawPos.y(),drawPos.z()); + _font->output(_text.c_str()); + break; + case OUTLINE: + glTranslatef(drawPos.x(),drawPos.y(),drawPos.z()); + _font->output(_text.c_str()); + break; + case BITMAP: + glRasterPos3f(drawPos.x(),drawPos.y(),drawPos.z()); + _font->output(_text.c_str()); + break; + case PIXMAP: + glRasterPos3f(drawPos.x(),drawPos.y(),drawPos.z()); + _font->output(_text.c_str()); + break; + case TEXTURE: + glTranslatef(drawPos.x(),drawPos.y(),drawPos.z()); + _font->output(_text.c_str()); + break; + + }; + glPopMatrix(); + } +} + +void Text:: +drawBoundingBox(void) +{ + if(!_init) + return; + + glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT ); + glDisable(GL_TEXTURE_2D); + glColor3f(0,1,0); + glBegin(GL_LINE_LOOP); + glVertex3f(_bbox.xMin(),_bbox.yMin(),_bbox.zMin()); + glVertex3f(_bbox.xMax(),_bbox.yMin(),_bbox.zMin()); + glVertex3f(_bbox.xMax(),_bbox.yMax(),_bbox.zMin()); + glVertex3f(_bbox.xMin(),_bbox.yMax(),_bbox.zMin()); + glEnd(); + glPopAttrib(); +} + +void Text:: +drawAlignement(void) +{ + if(!_init) + return; + + double size=_font->getPointSize()/4; + + glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT ); + glDisable(GL_TEXTURE_2D); + glColor3f(1,0,0); + glBegin(GL_LINES); + glVertex3f(_pos.x() - size,_pos.y(),_pos.z()); + glVertex3f(_pos.x() + size,_pos.y(),_pos.z()); + + glVertex3f(_pos.x(),_pos.y() - size,_pos.z()); + glVertex3f(_pos.x(),_pos.y() + size,_pos.z()); + + glEnd(); + glPopAttrib(); +} + +void Text:: +setPosition(const Vec3& pos) +{ + _pos=pos; +} + +void Text:: +setPosition(const Vec2& pos) +{ + setPosition(Vec3(pos.x(),pos.y(),0)); +} + +void Text:: +calcBounds(Vec3* min,Vec3* max) const +{ + if(!_init) + return; + + int h=_font->getHeight(); + int w=_font->getWidth(_text.c_str()); + int descender=_font->getDescender(); + + min->set(0,descender,0); + max->set(w,h + descender ,0); +} + +bool Text:: +initAlignement(void) +{ + if(!_init) + return false; + + // culling + if(_font->isCreated()) + { // ready to get the siz + _bbox.init(); + + Vec3 min,max; + initAlignement(&min,&max); + + _bbox.expandBy(min); + _bbox.expandBy(max); + + _bbox_computed=true; + + _initAlignement=true; + } + else + { // have to wait for the init. + _bbox.init(); + + // to be sure that the obj isn't culled + _bbox.expandBy(Vec3(-FLT_MAX,-FLT_MAX,-FLT_MAX)); + _bbox.expandBy(Vec3(FLT_MAX,FLT_MAX,FLT_MAX)); + + _bbox_computed=true; + } + + return true; +} + +void Text:: +initAlignement(Vec3* min,Vec3* max) +{ + if(!_init) + return; + + int h=_font->getHeight(); + int w=_font->getWidth(_text.c_str()); + int descender=_font->getDescender(); + + min->set(0,descender,0); + max->set(w,h + descender ,0); + + switch(_boundingBoxType) + { + case GLYPH: + h+=descender; + switch(_alignement) + { + case LEFT_TOP: + _alignementPos.set(0,h,0); + break; + case LEFT_CENTER: + _alignementPos.set(0,h/2,0); + break; + case LEFT_BOTTOM: + _alignementPos.set(0,0,0); + break; + + case CENTER_TOP: + _alignementPos.set(w/2,h,0); + break; + case CENTER_CENTER: + _alignementPos.set(w/2,h/2,0); + break; + case CENTER_BOTTOM: + _alignementPos.set(w/2,0,0); + break; + + case RIGHT_TOP: + _alignementPos.set(w,h,0); + break; + case RIGHT_CENTER: + _alignementPos.set(w,h/2,0); + break; + case RIGHT_BOTTOM: + _alignementPos.set(w,0,0); + break; + }; + _alignementPos=-_alignementPos; + + *min+=_pos+_alignementPos; + *max+=_pos+_alignementPos; + break; + + case GEOMETRY: + switch(_alignement) + { + case LEFT_TOP: + _alignementPos.set(0,h + descender,0); + break; + case LEFT_CENTER: + _alignementPos.set(0,(max->y()-min->y()) /2 + descender,0); + break; + case LEFT_BOTTOM: + _alignementPos.set(0,descender,0); + break; + + case CENTER_TOP: + _alignementPos.set(w/2,h + descender,0); + break; + case CENTER_CENTER: + _alignementPos.set(w/2,(max->y()-min->y()) /2 + descender,0); + break; + case CENTER_BOTTOM: + _alignementPos.set(w/2,descender,0); + break; + + case RIGHT_TOP: + _alignementPos.set(w,h + descender,0); + break; + case RIGHT_CENTER: + _alignementPos.set(w,(max->y()-min->y()) /2 + descender,0); + break; + case RIGHT_BOTTOM: + _alignementPos.set(w,descender,0); + break; + }; + _alignementPos=-_alignementPos; + + *min+=_pos+_alignementPos; + *max+=_pos+_alignementPos; + break; + }; + + + + switch(_fontType) + { + case BITMAP: + break; + case PIXMAP: + break; + + }; +} + + +void Text:: +setAlignement(int alignement) +{ + _alignement=alignement; + + if(!_init || !_font->isCreated()) + return; + + initAlignement(); +} + +void Text:: +setBoundingBox(int mode) +{ + _boundingBoxType=mode; + + if(!_init || !_font->isCreated()) + return; + + initAlignement(); +} + +// Text +///////////////////////////////////////////////////////////////////////////////