source: OGRE/trunk/ogrenew/OgreMain/src/OgreFont.cpp @ 657

Revision 657, 15.9 KB checked in by mattausch, 18 years ago (diff)

added ogre dependencies and patched ogre sources

Line 
1/*-------------------------------------------------------------------------
2This source file is a part of OGRE
3(Object-oriented Graphics Rendering Engine)
4
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This library is free software; you can redistribute it and/or modify it
11under the terms of the GNU Lesser General Public License (LGPL) as
12published by the Free Software Foundation; either version 2.1 of the
13License, or (at your option) any later version.
14
15This library is distributed in the hope that it will be useful, but
16WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
18License for more details.
19
20You should have received a copy of the GNU Lesser General Public License
21along with this library; if not, write to the Free Software Foundation,
22Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA or go to
23http://www.gnu.org/copyleft/lesser.txt
24-------------------------------------------------------------------------*/
25#include "OgreStableHeaders.h"
26
27#include "OgreFont.h"
28#include "OgreMaterialManager.h"
29#include "OgreTextureManager.h"
30#include "OgreTexture.h"
31#include "OgreResourceGroupManager.h"
32#include "OgreLogManager.h"
33#include "OgreStringConverter.h"
34#include "OgreRenderWindow.h"
35#include "OgreException.h"
36#include "OgreBlendMode.h"
37#include "OgreTextureUnitState.h"
38#include "OgreTechnique.h"
39#include "OgrePass.h"
40#include "OgreMaterial.h"
41#include <ft2build.h>
42#include FT_FREETYPE_H
43#include FT_GLYPH_H
44
45
46
47namespace Ogre
48{
49    //---------------------------------------------------------------------
50        Font::CmdType Font::msTypeCmd;
51        Font::CmdSource Font::msSourceCmd;
52        Font::CmdSize Font::msSizeCmd;
53        Font::CmdResolution Font::msResolutionCmd;
54
55    //---------------------------------------------------------------------
56        Font::Font(ResourceManager* creator, const String& name, ResourceHandle handle,
57                const String& group, bool isManual, ManualResourceLoader* loader)
58                :Resource (creator, name, handle, group, isManual, loader),
59                mType(FT_TRUETYPE), mTtfSize(0), mTtfResolution(0), mAntialiasColour(false)
60    {
61
62                if (createParamDictionary("Font"))
63                {
64                        ParamDictionary* dict = getParamDictionary();
65                        dict->addParameter(
66                                ParameterDef("type", "'truetype' or 'image' based font", PT_STRING),
67                                &msTypeCmd);
68                        dict->addParameter(
69                                ParameterDef("source", "Filename of the source of the font.", PT_STRING),
70                                &msSourceCmd);
71                        dict->addParameter(
72                                ParameterDef("size", "True type size", PT_REAL),
73                                &msSizeCmd);
74                        dict->addParameter(
75                                ParameterDef("resolution", "True type resolution", PT_UNSIGNED_INT),
76                                &msResolutionCmd);
77                }
78
79    }
80    //---------------------------------------------------------------------
81    Font::~Font()
82    {
83        // have to call this here reather than in Resource destructor
84        // since calling virtual methods in base destructors causes crash
85        unload();
86    }
87    //---------------------------------------------------------------------
88    void Font::setType(FontType ftype)
89    {
90        mType = ftype;
91    }
92    //---------------------------------------------------------------------
93    FontType Font::getType(void) const
94    {
95        return mType;
96    }
97    //---------------------------------------------------------------------
98    void Font::setSource(const String& source)
99    {
100        mSource = source;
101    }
102    //---------------------------------------------------------------------
103    void Font::setTrueTypeSize(Real ttfSize)
104    {
105        mTtfSize = ttfSize;
106    }
107    //---------------------------------------------------------------------
108    void Font::setTrueTypeResolution(uint ttfResolution)
109    {
110        mTtfResolution = ttfResolution;
111    }
112    //---------------------------------------------------------------------
113    const String& Font::getSource(void) const
114    {
115        return mSource;
116    }
117    //---------------------------------------------------------------------
118    Real Font::getTrueTypeSize(void) const
119    {
120        return mTtfSize;
121    }
122    //---------------------------------------------------------------------
123    uint Font::getTrueTypeResolution(void) const
124    {
125        return mTtfResolution;
126    }
127    //---------------------------------------------------------------------
128    std::pair< uint, uint > Font::StrBBox( const String & text, Real char_height, RenderWindow & window )
129    {
130        std::pair< uint, uint > ret( 0, 0 );
131        Real vsX, vsY;
132        unsigned int w, h;
133       
134        // These are not used, but are required byt the function calls.
135        unsigned int cdepth;
136                int left, top;
137
138        window.getMetrics( w, h, cdepth, left, top );
139
140        for( uint i = 0; i < text.length(); i++ )
141        {
142            // Calculate view-space width and height of char
143            vsY = char_height;
144                        if (text[i] == ' ') // assume capital A is space width
145                                vsX = getGlyphAspectRatio( 'A' ) * char_height;
146                        else
147                    vsX = getGlyphAspectRatio( text[ i ] ) * char_height;
148
149            ret.second += vsX * w;
150            if( vsY * h > ret.first || ( i && text[ i - 1 ] == '\n' ) )
151                ret.first += vsY * h;
152        }
153
154        return ret;
155    }
156    //---------------------------------------------------------------------
157    void Font::loadImpl()
158    {
159        // Create a new material
160        mpMaterial =  MaterialManager::getSingleton().create(
161                        "Fonts/" + mName,  mGroup);
162
163                if (mpMaterial.isNull())
164        {
165            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
166                "Error creating new material!", "Font::load" );
167        }
168
169        TextureUnitState *texLayer;
170        bool blendByAlpha = true;
171        if (mType == FT_TRUETYPE)
172        {
173            createTextureFromFont();
174            texLayer = mpMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0);
175            // Always blend by alpha
176            blendByAlpha = true;
177        }
178        else
179        {
180                        // Manually load since we need to load to get alpha
181                        mTexture = TextureManager::getSingleton().load(mSource, mGroup, TEX_TYPE_2D, 0);
182            blendByAlpha = mTexture->hasAlpha();
183            texLayer = mpMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(mSource);
184        }
185        // Clamp to avoid fuzzy edges
186        texLayer->setTextureAddressingMode( TextureUnitState::TAM_CLAMP );
187                // Allow min/mag filter, but no mip
188                texLayer->setTextureFiltering(FO_LINEAR, FO_LINEAR, FO_NONE);
189               
190
191        // Set up blending
192        if (blendByAlpha)
193        {
194            mpMaterial->setSceneBlending( SBT_TRANSPARENT_ALPHA );
195        }
196        else
197        {
198            // Use add if no alpha (assume black background)
199            mpMaterial->setSceneBlending(SBT_ADD);
200        }
201    }
202    //---------------------------------------------------------------------
203    void Font::unloadImpl()
204    {
205                // Cascade to the texture we created
206        mTexture->unload();
207    }
208    //---------------------------------------------------------------------
209    void Font::createTextureFromFont(void)
210    {
211
212                // Just create the texture here, and point it at ourselves for when
213                // it wants to (re)load for real
214                String texName = mName + "Texture";
215                // Create, setting isManual to true and passing self as loader
216                mTexture = TextureManager::getSingleton().create(
217                        texName, mGroup, true, this);
218                mTexture->setTextureType(TEX_TYPE_2D);
219                mTexture->setNumMipmaps(0);
220                mTexture->load();
221
222                TextureUnitState* t = mpMaterial->getTechnique(0)->getPass(0)->createTextureUnitState( texName );
223                // Allow min/mag filter, but no mip
224                t->setTextureFiltering(FO_LINEAR, FO_LINEAR, FO_NONE);
225
226        }
227        //---------------------------------------------------------------------
228        void Font::loadResource(Resource* res)
229        {
230                // ManualResourceLoader implementation - load the texture
231                FT_Library ftLibrary;
232                // Init freetype
233        if( FT_Init_FreeType( &ftLibrary ) )
234            OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Could not init FreeType library!",
235            "Font::Font");
236
237                uint i, l, m, n;
238        int j, k;
239
240        FT_Face face;
241        // Add a gap between letters vert and horz
242        // prevents nasty artefacts when letters are too close together
243        uint char_spacer = 5;
244
245        // Locate ttf file, load it pre-buffered into memory by wrapping the
246                // original DataStream in a MemoryDataStream
247                DataStreamPtr dataStreamPtr =
248                        ResourceGroupManager::getSingleton().openResource(mSource, mGroup);
249                MemoryDataStream ttfchunk(dataStreamPtr);
250               
251        // Load font
252        if( FT_New_Memory_Face( ftLibrary, ttfchunk.getPtr(), (FT_Long)ttfchunk.size() , 0, &face ) )
253            OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR,
254            "Could not open font face!", "Font::createTextureFromFont" );
255
256
257        // Convert our point size to freetype 26.6 fixed point format
258        FT_F26Dot6 ftSize = (FT_F26Dot6)(mTtfSize * (1 << 6));
259        if( FT_Set_Char_Size( face, ftSize, 0, mTtfResolution, mTtfResolution ) )
260            OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR,
261            "Could not set char size!", "Font::createTextureFromFont" );
262
263        FILE *fo_def = stdout;
264
265        int max_height = 0, max_width = 0, max_bear = 0;
266
267        uint startGlyph = 33;
268        uint endGlyph = 167;
269
270        // Calculate maximum width, height and bearing
271        for( i = startGlyph, l = 0, m = 0, n = 0; i < endGlyph; i++ )
272        {
273            FT_Load_Char( face, i, FT_LOAD_RENDER );
274
275            if( ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY ) > max_height )
276                max_height = ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY );
277            if( face->glyph->metrics.horiBearingY > max_bear )
278                max_bear = face->glyph->metrics.horiBearingY;
279
280            if( (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 ) > max_width)
281                max_width = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
282        }
283
284                // Now work out how big our texture needs to be
285                size_t rawSize = (max_width + char_spacer) *
286                                                        ((max_height >> 6) + char_spacer) *
287                                                        (endGlyph - startGlyph + 1);
288
289                size_t tex_side = Math::Sqrt(rawSize);
290                // just in case the size might chop a glyph in half, add another glyph width/height
291                tex_side += std::max(max_width, (max_height>>6));
292                // Now round up to nearest power of two, max out at 4096
293                size_t roundUpSize = 0;
294                for (i = 0; i < 12 && roundUpSize < tex_side; ++i)
295                        roundUpSize = 1 << i;
296               
297                tex_side = roundUpSize;
298                const size_t pixel_bytes = 2;
299                size_t data_width = tex_side * pixel_bytes;
300
301                LogManager::getSingleton().logMessage("Font " + mName + "using texture size " +
302                        StringConverter::toString(tex_side) + "x" + StringConverter::toString(tex_side));
303
304        uchar* imageData = new uchar[tex_side * tex_side * pixel_bytes];
305                // Reset content (White, transparent)
306        for (i = 0; i < tex_side * tex_side * pixel_bytes; i += pixel_bytes)
307        {
308            imageData[i + 0] = 0xFF; // luminance
309            imageData[i + 1] = 0x00; // alpha
310        }
311
312        for( i = startGlyph, l = 0, m = 0, n = 0; i < endGlyph; i++ )
313        {
314            FT_Error ftResult;
315
316            // Load & render glyph
317            ftResult = FT_Load_Char( face, i, FT_LOAD_RENDER );
318            if (ftResult)
319            {
320                // problem loading this glyph, continue
321                LogManager::getSingleton().logMessage("Info: cannot load character " +
322                    StringConverter::toString(i) + " in font " + mName);
323                continue;
324            }
325
326                        FT_Int advance = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
327
328            unsigned char* buffer = face->glyph->bitmap.buffer;
329
330            if (!buffer)
331            {
332                // Yuck, FT didn't detect this but generated a null pointer!
333                LogManager::getSingleton().logMessage("Info: Freetype returned null for character " +
334                    StringConverter::toString(i) + " in font " + mName);
335                continue;
336            }
337
338            int y_bearnig = ( max_bear >> 6 ) - ( face->glyph->metrics.horiBearingY >> 6 );
339
340            for( j = 0; j < face->glyph->bitmap.rows; j++ )
341            {
342                int row = j + m + y_bearnig;
343                uchar* pDest = &imageData[(row * data_width) + l * pixel_bytes];   
344                for( k = 0; k < face->glyph->bitmap.width; k++ )
345                {
346                    if (mAntialiasColour)
347                    {
348                        // Use the same greyscale pixel for all components RGBA
349                        *pDest++= *buffer;
350                    }
351                    else
352                    {
353                        // Always white whether 'on' or 'off' pixel, since alpha
354                        // will turn off
355                        *pDest++= 0xFF;
356                    }
357                    // Always use the greyscale value for alpha
358                    *pDest++= *buffer++;                 }
359            }
360
361            this->setGlyphTexCoords( i,
362                (Real)l / (Real)tex_side,  // u1
363                (Real)m / (Real)tex_side,  // v1
364                (Real)( l + ( face->glyph->advance.x >> 6 ) ) / (Real)tex_side, // u2
365                ( m + ( max_height >> 6 ) ) / (Real)tex_side // v2
366                );
367
368            // Advance a column
369            l += (advance + char_spacer);
370
371            // If at end of row
372            if( tex_side - 1 < l + ( advance ) )
373            {
374                m += ( max_height >> 6 ) + char_spacer;
375                l = n = 0;
376            }
377        }
378
379        DataStreamPtr memStream(
380                        new MemoryDataStream(imageData, tex_side * tex_side * pixel_bytes, true));
381
382        Image img;
383                img.loadRawData( memStream, tex_side, tex_side, PF_BYTE_LA );
384
385                Texture* tex = static_cast<Texture*>(res);
386                tex->loadImage(img);
387
388               
389                FT_Done_FreeType(ftLibrary);
390    }
391        //-----------------------------------------------------------------------
392        //-----------------------------------------------------------------------
393        String Font::CmdType::doGet(const void* target) const
394        {
395                const Font* f = static_cast<const Font*>(target);
396                if (f->getType() == FT_TRUETYPE)
397                {
398                        return "truetype";
399                }
400                else
401                {
402                        return "image";
403                }
404        }
405        void Font::CmdType::doSet(void* target, const String& val)
406        {
407                Font* f = static_cast<Font*>(target);
408                if (val == "truetype")
409                {
410                        f->setType(FT_TRUETYPE);
411                }
412                else
413                {
414                        f->setType(FT_IMAGE);
415                }
416        }
417        //-----------------------------------------------------------------------
418        String Font::CmdSource::doGet(const void* target) const
419        {
420                const Font* f = static_cast<const Font*>(target);
421                return f->getSource();
422        }
423        void Font::CmdSource::doSet(void* target, const String& val)
424        {
425                Font* f = static_cast<Font*>(target);
426                f->setSource(val);
427        }
428        //-----------------------------------------------------------------------
429        String Font::CmdSize::doGet(const void* target) const
430        {
431                const Font* f = static_cast<const Font*>(target);
432                return StringConverter::toString(f->getTrueTypeSize());
433        }
434        void Font::CmdSize::doSet(void* target, const String& val)
435        {
436                Font* f = static_cast<Font*>(target);
437                f->setTrueTypeSize(StringConverter::parseReal(val));
438        }
439        //-----------------------------------------------------------------------
440        String Font::CmdResolution::doGet(const void* target) const
441        {
442                const Font* f = static_cast<const Font*>(target);
443                return StringConverter::toString(f->getTrueTypeResolution());
444        }
445        void Font::CmdResolution::doSet(void* target, const String& val)
446        {
447                Font* f = static_cast<Font*>(target);
448                f->setTrueTypeResolution(StringConverter::parseUnsignedInt(val));
449        }
450
451
452}
Note: See TracBrowser for help on using the repository browser.