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

Revision 692, 16.2 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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(
249                                mSource, mGroup, true, this);
250                MemoryDataStream ttfchunk(dataStreamPtr);
251
252        // Load font
253        if( FT_New_Memory_Face( ftLibrary, ttfchunk.getPtr(), (FT_Long)ttfchunk.size() , 0, &face ) )
254            OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR,
255            "Could not open font face!", "Font::createTextureFromFont" );
256
257
258        // Convert our point size to freetype 26.6 fixed point format
259        FT_F26Dot6 ftSize = (FT_F26Dot6)(mTtfSize * (1 << 6));
260        if( FT_Set_Char_Size( face, ftSize, 0, mTtfResolution, mTtfResolution ) )
261            OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR,
262            "Could not set char size!", "Font::createTextureFromFont" );
263
264        //FILE *fo_def = stdout;
265
266        int max_height = 0, max_width = 0, max_bear = 0;
267
268        uint startGlyph = 33;
269        uint endGlyph = 167;
270
271        // Calculate maximum width, height and bearing
272        for( i = startGlyph, l = 0, m = 0, n = 0; i < endGlyph; i++ )
273        {
274            FT_Load_Char( face, i, FT_LOAD_RENDER );
275
276            if( ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY ) > max_height )
277                max_height = ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY );
278            if( face->glyph->metrics.horiBearingY > max_bear )
279                max_bear = face->glyph->metrics.horiBearingY;
280
281            if( (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 ) > max_width)
282                max_width = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
283        }
284
285                // Now work out how big our texture needs to be
286                size_t rawSize = (max_width + char_spacer) *
287                                                        ((max_height >> 6) + char_spacer) *
288                                                        (endGlyph - startGlyph + 1);
289
290                size_t tex_side = Math::Sqrt(rawSize);
291                // just in case the size might chop a glyph in half, add another glyph width/height
292                tex_side += std::max(max_width, (max_height>>6));
293                // Now round up to nearest power of two, max out at 4096
294                size_t roundUpSize = 0;
295                for (i = 0; i < 12 && roundUpSize < tex_side; ++i)
296            #if  OGRE_COMPILER == OGRE_COMPILER_MSVC &&  OGRE_ARCH_TYPE == OGRE_ARCHITECTURE_64
297                    roundUpSize = 1i64 << i;//  64-bit shift otherwise we get a C4334 warning
298            #else
299                    roundUpSize = 1 << i;
300            #endif
301
302                tex_side = roundUpSize;
303                const size_t pixel_bytes = 2;
304                size_t data_width = tex_side * pixel_bytes;
305
306                LogManager::getSingleton().logMessage("Font " + mName + "using texture size " +
307                        StringConverter::toString(tex_side) + "x" + StringConverter::toString(tex_side));
308
309        uchar* imageData = new uchar[tex_side * tex_side * pixel_bytes];
310                // Reset content (White, transparent)
311        for (i = 0; i < tex_side * tex_side * pixel_bytes; i += pixel_bytes)
312        {
313            imageData[i + 0] = 0xFF; // luminance
314            imageData[i + 1] = 0x00; // alpha
315        }
316
317        for( i = startGlyph, l = 0, m = 0, n = 0; i < endGlyph; i++ )
318        {
319            FT_Error ftResult;
320
321            // Load & render glyph
322            ftResult = FT_Load_Char( face, i, FT_LOAD_RENDER );
323            if (ftResult)
324            {
325                // problem loading this glyph, continue
326                LogManager::getSingleton().logMessage("Info: cannot load character " +
327                    StringConverter::toString(i) + " in font " + mName);
328                continue;
329            }
330
331                        FT_Int advance = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
332
333            unsigned char* buffer = face->glyph->bitmap.buffer;
334
335            if (!buffer)
336            {
337                // Yuck, FT didn't detect this but generated a null pointer!
338                LogManager::getSingleton().logMessage("Info: Freetype returned null for character " +
339                    StringConverter::toString(i) + " in font " + mName);
340                continue;
341            }
342
343            int y_bearnig = ( max_bear >> 6 ) - ( face->glyph->metrics.horiBearingY >> 6 );
344
345            for( j = 0; j < face->glyph->bitmap.rows; j++ )
346            {
347                int row = j + m + y_bearnig;
348                uchar* pDest = &imageData[(row * data_width) + l * pixel_bytes];
349                for( k = 0; k < face->glyph->bitmap.width; k++ )
350                {
351                    if (mAntialiasColour)
352                    {
353                        // Use the same greyscale pixel for all components RGBA
354                        *pDest++= *buffer;
355                    }
356                    else
357                    {
358                        // Always white whether 'on' or 'off' pixel, since alpha
359                        // will turn off
360                        *pDest++= 0xFF;
361                    }
362                    // Always use the greyscale value for alpha
363                    *pDest++= *buffer++;                 }
364            }
365
366            this->setGlyphTexCoords( i,
367                (Real)l / (Real)tex_side,  // u1
368                (Real)m / (Real)tex_side,  // v1
369                (Real)( l + ( face->glyph->advance.x >> 6 ) ) / (Real)tex_side, // u2
370                ( m + ( max_height >> 6 ) ) / (Real)tex_side // v2
371                );
372
373            // Advance a column
374            l += (advance + char_spacer);
375
376            // If at end of row
377            if( tex_side - 1 < l + ( advance ) )
378            {
379                m += ( max_height >> 6 ) + char_spacer;
380                l = n = 0;
381            }
382        }
383
384        DataStreamPtr memStream(
385                        new MemoryDataStream(imageData, tex_side * tex_side * pixel_bytes, true));
386
387        Image img;
388                img.loadRawData( memStream, tex_side, tex_side, PF_BYTE_LA );
389
390                Texture* tex = static_cast<Texture*>(res);
391                tex->loadImage(img);
392
393
394                FT_Done_FreeType(ftLibrary);
395    }
396        //-----------------------------------------------------------------------
397        //-----------------------------------------------------------------------
398        String Font::CmdType::doGet(const void* target) const
399        {
400                const Font* f = static_cast<const Font*>(target);
401                if (f->getType() == FT_TRUETYPE)
402                {
403                        return "truetype";
404                }
405                else
406                {
407                        return "image";
408                }
409        }
410        void Font::CmdType::doSet(void* target, const String& val)
411        {
412                Font* f = static_cast<Font*>(target);
413                if (val == "truetype")
414                {
415                        f->setType(FT_TRUETYPE);
416                }
417                else
418                {
419                        f->setType(FT_IMAGE);
420                }
421        }
422        //-----------------------------------------------------------------------
423        String Font::CmdSource::doGet(const void* target) const
424        {
425                const Font* f = static_cast<const Font*>(target);
426                return f->getSource();
427        }
428        void Font::CmdSource::doSet(void* target, const String& val)
429        {
430                Font* f = static_cast<Font*>(target);
431                f->setSource(val);
432        }
433        //-----------------------------------------------------------------------
434        String Font::CmdSize::doGet(const void* target) const
435        {
436                const Font* f = static_cast<const Font*>(target);
437                return StringConverter::toString(f->getTrueTypeSize());
438        }
439        void Font::CmdSize::doSet(void* target, const String& val)
440        {
441                Font* f = static_cast<Font*>(target);
442                f->setTrueTypeSize(StringConverter::parseReal(val));
443        }
444        //-----------------------------------------------------------------------
445        String Font::CmdResolution::doGet(const void* target) const
446        {
447                const Font* f = static_cast<const Font*>(target);
448                return StringConverter::toString(f->getTrueTypeResolution());
449        }
450        void Font::CmdResolution::doSet(void* target, const String& val)
451        {
452                Font* f = static_cast<Font*>(target);
453                f->setTrueTypeResolution(StringConverter::parseUnsignedInt(val));
454        }
455
456
457}
Note: See TracBrowser for help on using the repository browser.