Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

OSGTextTXFFace.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038 
00039 #ifdef _MSC_VER
00040 # pragma warning (disable: 4786)
00041 #endif
00042 
00043 #include "OSGTextTXFFace.h"
00044 #include "OSGTextTXFGlyph.h"
00045 #include "OSGTextLayoutParam.h"
00046 #include "OSGTextLayoutResult.h"
00047 #include "OSGTextFaceFactory.h"
00048 
00049 #include <fstream>
00050 #ifdef __sgi
00051 # include <assert.h>
00052 #else
00053 # include <cassert>
00054 #endif
00055 
00056 
00057 using namespace std;
00058 
00059 
00060 OSG_BEGIN_NAMESPACE
00061 
00062 
00063 //----------------------------------------------------------------------
00064 // Static Class Variable implementations
00065 // Author: pdaehne
00066 //----------------------------------------------------------------------
00067 TextTXFGlyph TextTXFFace::_emptyGlyph;
00068 
00069 
00070 //----------------------------------------------------------------------
00071 // Destructor
00072 // Author: pdaehne
00073 //----------------------------------------------------------------------
00074 TextTXFFace::~TextTXFFace()
00075 {
00076     // Delete all glyphs in the glyph cache
00077     GlyphMap::iterator it;
00078     for (it = _glyphMap.begin(); it != _glyphMap.end(); ++it)
00079     {
00080         assert(it->second != 0);
00081         delete it->second;
00082     }
00083 
00084     // Delete the texture
00085     subRefCP(_texture);
00086 }
00087 
00088 
00089 //----------------------------------------------------------------------
00090 // Returns information about a glyph.
00091 // Author: pdaehne
00092 //----------------------------------------------------------------------
00093 const TextGlyph &TextTXFFace::getGlyph(TextGlyph::Index glyphIndex)
00094 {
00095     return getTXFGlyph(glyphIndex);
00096 }
00097 
00098 
00099 //----------------------------------------------------------------------
00100 // Returns information about a glyph.
00101 // Author: pdaehne
00102 //----------------------------------------------------------------------
00103 const TextTXFGlyph &TextTXFFace::getTXFGlyph(TextGlyph::Index glyphIndex)
00104 {
00105     // Try to find the glyph in the map of glyphs
00106     GlyphMap::const_iterator it = _glyphMap.find(glyphIndex);
00107     if (it != _glyphMap.end())
00108     {
00109         assert(it->second != 0);
00110         return *(it->second);
00111     }
00112 
00113     // We did not find the glyph in the map of glyphs,
00114     // so try to convert uppercase letters to lowercase
00115     // letters and vice versa
00116     if (glyphIndex > 255)
00117         glyphIndex = TextGlyph::INVALID_INDEX;
00118     else if (isupper(glyphIndex))
00119         glyphIndex = tolower(glyphIndex);
00120     else if (islower(glyphIndex))
00121         glyphIndex = toupper(glyphIndex);
00122     else
00123         glyphIndex = TextGlyph::INVALID_INDEX;
00124     it = _glyphMap.find(glyphIndex);
00125     if (it != _glyphMap.end())
00126     {
00127         assert(it->second != 0);
00128         return *(it->second);
00129     }
00130 
00131     return _emptyGlyph;
00132 }
00133 
00134 
00135 //----------------------------------------------------------------------
00136 // Fills a geometry with a new text
00137 // Author: afischle, pdaehne
00138 //----------------------------------------------------------------------
00139 void TextTXFFace::fillGeo(GeometryPtr &geoPtr, const TextLayoutResult &layoutResult, Real32 scale,
00140                           Vec2f offset, Color3f color)
00141 {
00142     // cast the field containers down to the needed type and create them
00143     // when they have the wrong type
00144     GeoPositions3fPtr posPtr = GeoPositions3fPtr::dcast(geoPtr->getPositions());
00145     if (posPtr != NullFC)
00146        posPtr->clear();
00147 
00148     // Clear out any existing data and then add to the geom
00149     GeoNormals3fPtr normalPtr = GeoNormals3fPtr::dcast(geoPtr->getNormals());
00150     if (normalPtr != NullFC)
00151        normalPtr->clear();
00152 
00153     GeoTexCoords2fPtr texPtr = GeoTexCoords2fPtr::dcast(geoPtr->getTexCoords());
00154     if (texPtr != NullFC)
00155        texPtr->clear();
00156 
00157     GeoColors3fPtr colorPtr = GeoColors3fPtr::dcast(geoPtr->getColors());
00158     if (NullFC != colorPtr)
00159        colorPtr->clear();
00160 
00161     GeoPLengthsUI32Ptr lensPtr = GeoPLengthsUI32Ptr::dcast(geoPtr->getLengths());
00162     if (lensPtr != NullFC)
00163        lensPtr->clear();
00164 
00165     GeoPTypesUI8Ptr typesPtr = GeoPTypesUI8Ptr::dcast(geoPtr->getTypes());
00166     if (typesPtr != NullFC)
00167        typesPtr->clear();
00168 
00169     geoPtr->setIndices(NullFC);
00170     geoPtr->setSecondaryColors(NullFC);
00171     geoPtr->setTexCoords1(NullFC);
00172     geoPtr->setTexCoords2(NullFC);
00173     geoPtr->setTexCoords3(NullFC);
00174     geoPtr->getIndexMapping().clear();
00175 
00176     addToGeom(geoPtr,layoutResult,scale,offset,color);
00177 }
00178 
00179 void TextTXFFace::addToGeom(GeometryPtr &geoPtr, const TextLayoutResult &layoutResult, Real32 scale,
00180                             Vec2f offset, Color3f color)
00181 {
00182     beginEditCP(geoPtr);
00183 
00184     // cast the field containers down to the needed type and create them
00185     // when they have the wrong type
00186     GeoPositions3fPtr posPtr = GeoPositions3fPtr::dcast(geoPtr->getPositions());
00187     GeoNormals3fPtr normalPtr = GeoNormals3fPtr::dcast(geoPtr->getNormals());
00188     GeoTexCoords2fPtr texPtr = GeoTexCoords2fPtr::dcast(geoPtr->getTexCoords());
00189     GeoColors3fPtr colorPtr = GeoColors3fPtr::dcast(geoPtr->getColors());
00190     GeoPLengthsUI32Ptr lensPtr = GeoPLengthsUI32Ptr::dcast(geoPtr->getLengths());
00191     GeoPTypesUI8Ptr typesPtr = GeoPTypesUI8Ptr::dcast(geoPtr->getTypes());
00192 
00193     // Create color buffer: If Null container AND color is set && we have not potentially added text before
00194     if ((NullFC == colorPtr) && (color != OSG::Color3f(-1,-1,-1)) &&
00195         ((NullFC == posPtr) && (NullFC == texPtr)) )
00196     {
00197        colorPtr = GeoColors3f::create();
00198        geoPtr->setColors(colorPtr);
00199     }
00200     bool use_colors(NullFC != colorPtr);
00201 
00202     if (posPtr == NullFC)
00203     {
00204         posPtr = GeoPositions3f::create();
00205         geoPtr->setPositions(posPtr);
00206     }
00207 
00208     if (normalPtr == NullFC)
00209     {
00210         normalPtr = GeoNormals3f::create();
00211         geoPtr->setNormals(normalPtr);
00212     }
00213 
00214     if (texPtr == NullFC)
00215     {
00216         texPtr = GeoTexCoords2f::create();
00217         geoPtr->setTexCoords(texPtr);
00218     }
00219 
00220     if (lensPtr == NullFC)
00221     {
00222         lensPtr = GeoPLengthsUI32::create();
00223         geoPtr->setLengths(lensPtr);
00224     }
00225 
00226     if (typesPtr == NullFC)
00227     {
00228         typesPtr = GeoPTypesUI8::create();
00229         geoPtr->setTypes(typesPtr);
00230     }
00231 
00232     UInt32 numGlyphs = layoutResult.getNumGlyphs();
00233     if (numGlyphs == 0)
00234     {
00235         endEditCP(geoPtr);
00236         return;
00237     }
00238 
00239     beginEditCP(posPtr, GeoPositions3f::GeoPropDataFieldMask);
00240     beginEditCP(normalPtr, GeoNormals3f::GeoPropDataFieldMask);
00241     beginEditCP(texPtr, GeoTexCoords2f::GeoPropDataFieldMask);
00242     if(NullFC != colorPtr)
00243     {  beginEditCP(colorPtr, GeoIndicesUI32::GeoPropDataFieldMask); }
00244     beginEditCP(lensPtr, GeoPLengthsUI32::GeoPropDataFieldMask);
00245     beginEditCP(typesPtr, GeoPTypesUI8::GeoPropDataFieldMask);
00246 
00247     OSG::Vec3f normal(0.0, 0.0, 0.0);        // normal to use for each glyph
00248 
00249     typesPtr->push_back(GL_QUADS);
00250     unsigned num_glyphs_added(0);
00251 
00252     for (UInt32 i = 0; i < numGlyphs; ++i)
00253     {
00254         TextGlyph::Index glyphIndex = layoutResult.indices[i];
00255         const TextTXFGlyph &glyph = getTXFGlyph(glyphIndex);
00256         Real32 width = glyph.getWidth();
00257         Real32 height = glyph.getHeight();
00258         // No need to draw invisible glyphs
00259         if ((width <= 0.f) || (height <= 0.f))
00260             continue;
00261         else
00262             num_glyphs_added += 1;
00263 
00264         // Calculate coordinates
00265         Vec2f pos = layoutResult.positions[i];
00266         Real32 posLeft = (pos.x() * scale) + offset.x();
00267         Real32 posTop = (pos.y() * scale) + offset.y();
00268         Real32 posRight = ((pos.x() + width) * scale) + offset.x();
00269         Real32 posBottom = ((pos.y() - height) * scale) + offset.y();
00270 
00271         // Calculate texture coordinates
00272         Real32 texCoordLeft = glyph.getTexCoord(TextTXFGlyph::COORD_LEFT);
00273         Real32 texCoordTop = glyph.getTexCoord(TextTXFGlyph::COORD_TOP);
00274         Real32 texCoordRight = glyph.getTexCoord(TextTXFGlyph::COORD_RIGHT);
00275         Real32 texCoordBottom = glyph.getTexCoord(TextTXFGlyph::COORD_BOTTOM);
00276 
00277         // lower left corner
00278         posPtr->push_back(Vec3f(posLeft, posBottom, 0.f));
00279         texPtr->push_back(Vec2f(texCoordLeft, texCoordBottom));
00280         normalPtr->push_back(normal);
00281         if(use_colors) colorPtr->push_back(color);
00282 
00283         // lower right corner
00284         posPtr->push_back(Vec3f(posRight, posBottom, 0.f));
00285         texPtr->push_back(Vec2f(texCoordRight, texCoordBottom));
00286         normalPtr->push_back(normal);
00287         if(use_colors) colorPtr->push_back(color);
00288 
00289         // upper right corner
00290         posPtr->push_back(Vec3f(posRight, posTop, 0.f));
00291         texPtr->push_back(Vec2f(texCoordRight, texCoordTop));
00292         normalPtr->push_back(normal);
00293         if(use_colors) colorPtr->push_back(color);
00294 
00295         // upper left corner
00296         posPtr->push_back(Vec3f(posLeft, posTop, 0.f));
00297         texPtr->push_back(Vec2f(texCoordLeft, texCoordTop));
00298         normalPtr->push_back(normal);
00299         if(use_colors) colorPtr->push_back(color);
00300     }
00301     lensPtr->push_back(num_glyphs_added*4);
00302 
00303     endEditCP(typesPtr, GeoPTypesUI8::GeoPropDataFieldMask);
00304     endEditCP(lensPtr, GeoPLengthsUI32::GeoPropDataFieldMask);
00305     endEditCP(texPtr, GeoTexCoords2f::GeoPropDataFieldMask);
00306     endEditCP(normalPtr, GeoNormals3f::GeoPropDataFieldMask);
00307     endEditCP(posPtr, GeoPositions3f::GeoPropDataFieldMask);
00308     if(NullFC != colorPtr)
00309     { endEditCP(colorPtr, GeoIndicesUI32::GeoPropDataFieldMask); }
00310 
00311     endEditCP(geoPtr);
00312 }
00313 
00314 
00315 //----------------------------------------------------------------------
00316 // Creates a new text geometry
00317 // Author: pdaehne
00318 //----------------------------------------------------------------------
00319 GeometryPtr TextTXFFace::makeGeo(const TextLayoutResult &layoutResult, Real32 scale,
00320                                  Vec2f offset, Color3f color)
00321 {
00322     GeometryPtr geo = Geometry::create();
00323     fillGeo(geo, layoutResult, scale, offset, color);
00324     return geo;
00325 }
00326 
00327 
00328 //----------------------------------------------------------------------
00329 // Creates a new node with a text geometry
00330 // Author: pdaehne
00331 //----------------------------------------------------------------------
00332 NodePtr TextTXFFace::makeNode(const TextLayoutResult &layoutResult, Real32 scale,
00333                               Vec2f offset, Color3f color)
00334 {
00335     GeometryPtr geo = makeGeo(layoutResult, scale, offset, color);
00336     NodePtr node = Node::create();
00337     beginEditCP(node, Node::CoreFieldMask);
00338     node->setCore(geo);
00339     endEditCP(node, Node::CoreFieldMask);
00340     return node;
00341 }
00342 
00343 
00344 //----------------------------------------------------------------------
00345 // Tries to create a TXF face
00346 // Author: pdaehne
00347 //----------------------------------------------------------------------
00348 TextTXFFace *TextTXFFace::create(const string &family, Style style, const TextTXFParam &param)
00349 { return TextFaceFactory::the().createTXFFace(family, style, param); }
00350 
00351 
00352 //----------------------------------------------------------------------
00353 // Reads a long value in network byte order from the input stream
00354 // Author: pdaehne
00355 //----------------------------------------------------------------------
00356 static UInt32 readLong(istream &is, bool swap)
00357 {
00358     UInt8 bytes[4];
00359     is.read((istream::char_type*)(bytes), 4);
00360     return swap ?
00361         (bytes[3] << 24) |
00362         (bytes[2] << 16) |
00363         (bytes[1] << 8) |
00364         bytes[0]
00365                 :
00366         (bytes[0] << 24) |
00367         (bytes[1] << 16) |
00368         (bytes[2] << 8) |
00369         bytes[3];
00370 }
00371 
00372 
00373 //----------------------------------------------------------------------
00374 // Reads a short value in network byte order from the input stream
00375 // Author: pdaehne
00376 //----------------------------------------------------------------------
00377 static UInt16 readShort(istream &is, bool swap)
00378 {
00379     UInt8 bytes[2];
00380     is.read((istream::char_type*)(bytes), 2);
00381     return swap ?
00382         (bytes[1] << 8) |
00383         bytes[0]
00384                 :
00385         (bytes[0] << 8) |
00386         bytes[1];
00387 }
00388 
00389 
00390 //----------------------------------------------------------------------
00391 // Reads a TXF face from an input stream
00392 // Author: pdaehne
00393 //----------------------------------------------------------------------
00394 TextTXFFace *TextTXFFace::createFromStream(istream &is, const string &family, Style style)
00395 {
00396     // Check the magic bytes
00397     istream::char_type magicBytes[4];
00398     is.read(magicBytes, 4);
00399     if ((is.good() == false) || (strncmp(magicBytes, "\xfftxf", 4) != 0))
00400         return 0;
00401 
00402     // Check endianess
00403     UInt32 endianness = readLong(is, false);
00404     bool swap;
00405     if (endianness == 0x12345678)
00406         swap = false;
00407     else if (endianness == 0x78563412)
00408         swap = true;
00409     else
00410         return 0;
00411 
00412     TextTXFFace *face = new TextTXFFace();
00413     face->_family = family;
00414     face->_style = style;
00415 
00416     // Read header
00417     UInt32 format = readLong(is, swap);
00418     UInt32 textureWidth = readLong(is, swap);
00419     UInt32 textureHeight = readLong(is, swap);
00420     Int32 max_ascent = readLong(is, swap);
00421     Int32 max_descent = readLong(is, swap);
00422     if (max_descent < 0)
00423         max_descent = -max_descent;
00424     UInt32 num_glyphs = readLong(is, swap);
00425     if (is.good() == false)
00426     {
00427         subRefP(face);
00428         return 0;
00429     }
00430 
00431     // Determine parameters
00432     face->_param.size = max_ascent + max_descent;
00433     face->_param.gap = 0; // There is no way to determine the gap
00434     face->_param.textureWidth = textureWidth;
00435 
00436     // Determine the scale factor
00437     face->_scale = 1.f / static_cast<Real32>(max_ascent + max_descent);
00438 
00439     // Determine ascent
00440     face->_horiAscent = static_cast<Real32>(max_ascent) * face->_scale;
00441     face->_vertAscent = -0.5f;
00442 
00443     // Determine descent
00444     face->_horiDescent = static_cast<Real32>(-max_descent) * face->_scale;
00445     face->_vertDescent = 0.5f;
00446 
00447     // Parse glyph information
00448     Int32 vertBearingY = -(max_ascent + max_descent) / 20;
00449     if (vertBearingY > -1)
00450         vertBearingY = -1;
00451     Real32 vertAdvanceOffset = static_cast<Real32>(vertBearingY) * 2.f * face->_scale;
00452     wstring characters;
00453     characters.reserve(num_glyphs);
00454     UInt32 i;
00455     for (i = 0; i < num_glyphs; ++i)
00456     {
00457         // Create the new glyph object
00458         TextTXFGlyph *glyph = new TextTXFGlyph();
00459         UInt16 glyphIndex = readShort(is, swap);
00460         characters.append(static_cast<wchar_t>(glyphIndex), 1);
00461         glyph->_glyphIndex = glyphIndex;
00462         glyph->_scale = face->_scale;
00463         glyph->_width = (unsigned char)is.get();
00464         glyph->_height = (unsigned char)is.get();
00465         glyph->_horiBearingX = (signed char)is.get();
00466         glyph->_horiBearingY = (signed char)is.get() + glyph->_height;
00467         glyph->_horiAdvance = ((signed char)is.get()) * face->_scale;
00468         is.ignore(); // padding
00469         glyph->_x = readShort(is, swap);
00470         glyph->_y = readShort(is, swap);
00471 
00472         // There is no vertical layout information in a TXF file,
00473         // therefore we have to guess reasonable values
00474         glyph->_vertBearingX = -static_cast<Int32>(glyph->_width >> 1);
00475         if (glyphIndex == 32)
00476         {
00477             glyph->_vertBearingY = -glyph->_horiBearingX;
00478             glyph->_vertAdvance = -glyph->_horiAdvance;
00479         }
00480         else
00481         {
00482             glyph->_vertBearingY = vertBearingY;
00483             glyph->_vertAdvance = -static_cast<Real32>(glyph->_height) * face->_scale + vertAdvanceOffset;
00484         }
00485 
00486         glyph->calculateCoordinates(textureWidth, textureHeight);
00487         face->_glyphMap[glyphIndex] = glyph;
00488 
00489         if (is.good() == false)
00490         {
00491             subRefP(face);
00492             return 0;
00493         }
00494     }
00495     face->_param.setCharacters(characters);
00496 
00497     // Create the texture
00498     face->_texture = Image::create();
00499     addRefCP(face->_texture);
00500     beginEditCP(face->_texture);
00501     face->_texture->set(Image::OSG_I_PF, textureWidth, textureHeight);
00502     face->_texture->clear();
00503 
00504     // Parse texture
00505     switch (format)
00506     {
00507         case 0: // TXF_FORMAT_BYTE
00508             {
00509                 UInt32 size = textureWidth * textureHeight;
00510                 assert(face->_texture->getSize() == size);
00511                 is.read((istream::char_type*)face->_texture->getData(), size);
00512                 endEditCP(face->_texture);
00513                 if (is.good() == false)
00514                 {
00515                     subRefP(face);
00516                     return 0;
00517                 }
00518             }
00519             break;
00520         case 1: // TXF_FORMAT_BITMAP
00521             {
00522                 UInt32 stride = (textureWidth + 7) >> 3;
00523                 UInt32 size = stride * textureHeight;
00524                 UInt8 *buffer = new UInt8[size];
00525                 is.read((istream::char_type*)buffer, size);
00526                 if (is.good() == false)
00527                 {
00528                     delete [] buffer;
00529                     endEditCP(face->_texture);
00530                     subRefP(face);
00531                     return 0;
00532                 }
00533                 assert(face->_texture->getSize() == textureWidth * textureHeight);
00534                 UInt8 *dst = face->_texture->getData();
00535                 UInt32 x, y;
00536                 for (y = 0; y < textureHeight; ++y)
00537                     for (x = 0; x < textureWidth; ++x)
00538                         dst[y * textureWidth + x] = buffer[y * stride + (x >> 3)] & (1 << (x & 7)) ? 255 : 0;
00539                 delete [] buffer;
00540                 endEditCP(face->_texture);
00541             }
00542             break;
00543         default:
00544             endEditCP(face->_texture);
00545             subRefP(face);
00546             return 0;
00547     }
00548 
00549     return face;
00550 }
00551 
00552 
00553 //----------------------------------------------------------------------
00554 // Reads a TXF face from a file
00555 // Author: pdaehne
00556 //----------------------------------------------------------------------
00557 TextTXFFace *TextTXFFace::createFromFile(const string &filename)
00558 {
00559     // Open the file
00560     ifstream is(filename.c_str(), ios_base::in | ios_base::binary);
00561     if (is.good() == false)
00562         return 0;
00563 
00564     // Remove the directory and the suffix from the filename and use the
00565     // remaining filename as the family name
00566     string::size_type pos = filename.find_last_of("/\\");
00567     string family = pos != string::npos ? filename.substr(pos + 1) : filename;
00568     pos = family.rfind('.');
00569     if (pos != string::npos)
00570         family.erase(pos);
00571 
00572     // Parse the file
00573     TextTXFFace *face = createFromStream(is, family);
00574     if (face == 0)
00575         return 0;
00576 
00577     return face;
00578 }
00579 
00580 
00581 //----------------------------------------------------------------------
00582 // Writes a long value in network byte order to the output stream
00583 // Author: pdaehne
00584 //----------------------------------------------------------------------
00585 static void writeLong(ostream &os, UInt32 value)
00586 {
00587     UInt8 bytes[4];
00588     bytes[0] = static_cast<UInt8>((value >> 24) & 0xff);
00589     bytes[1] = static_cast<UInt8>((value >> 16) & 0xff);
00590     bytes[2] = static_cast<UInt8>((value >> 8) & 0xff);
00591     bytes[3] = static_cast<UInt8>(value & 0xff);
00592     os.write(reinterpret_cast<ostream::char_type*>(bytes), 4);
00593 }
00594 
00595 
00596 //----------------------------------------------------------------------
00597 // Writes a short value in network byte order to the output stream
00598 // Author: pdaehne
00599 //----------------------------------------------------------------------
00600 static void writeShort(ostream &os, UInt16 value)
00601 {
00602     UInt8 bytes[2];
00603     bytes[0] = static_cast<UInt8>((value >> 8) & 0xff);
00604     bytes[1] = static_cast<UInt8>(value & 0xff);
00605     os.write(reinterpret_cast<ostream::char_type*>(bytes), 2);
00606 }
00607 
00608 
00609 //----------------------------------------------------------------------
00610 // Writes a TXF face to an output stream
00611 // Author: pdaehne
00612 //----------------------------------------------------------------------
00613 bool TextTXFFace::writeToStream(ostream &os) const
00614 {
00615     // Write the magic bytes
00616     const ostream::char_type *magicBytes = "\xfftxf";
00617     os.write(magicBytes, 4);
00618 
00619     // Write the header
00620     assert(_texture != NullFC);
00621     writeLong(os, 0x12345678); // endianness
00622     writeLong(os, 0); // format
00623     writeLong(os, _texture->getWidth());
00624     writeLong(os, _texture->getHeight());
00625     writeLong(os, static_cast<UInt32>(_horiAscent / _scale));
00626     writeLong(os, static_cast<UInt32>(_horiDescent / _scale));
00627     writeLong(os, _glyphMap.size());
00628     if (os.good() == false)
00629         return false;
00630 
00631     // Write glyph information
00632     GlyphMap::const_iterator it;
00633     for (it = _glyphMap.begin(); it != _glyphMap.end(); ++it)
00634     {
00635         assert(it->second != 0);
00636         writeShort(os, static_cast<UInt16>(it->second->getGlyphIndex()));
00637         os.put(it->second->getPixmapWidth());
00638         os.put(it->second->getPixmapHeight());
00639         os.put(it->second->getPixmapHoriBearingX());
00640         os.put(it->second->getPixmapHoriBearingY() - it->second->getPixmapHeight());
00641         os.put(static_cast<ostream::char_type>(it->second->getHoriAdvance() / _scale));
00642         os.put(0); // padding
00643         writeShort(os, it->second->getX());
00644         writeShort(os, it->second->getY());
00645         if (os.good() == false)
00646             return false;
00647     }
00648 
00649     // Write texture
00650     assert(_texture->getSize() == static_cast<UInt32>(_texture->getWidth() * _texture->getHeight()));
00651     os.write((ostream::char_type*)_texture->getData(), _texture->getWidth() * _texture->getHeight());
00652 
00653     return os.good();
00654 }
00655 
00656 
00657 //----------------------------------------------------------------------
00658 // Writes a TXF face to a file
00659 // Author: pdaehne
00660 //----------------------------------------------------------------------
00661 bool TextTXFFace::writeToFile(const string &filename) const
00662 {
00663     ofstream os(filename.c_str(), ios_base::out | ios_base::trunc | ios_base::binary);
00664     if (os.good() == false)
00665         return false;
00666     return writeToStream(os);
00667 }
00668 
00669 
00670 //----------------------------------------------------------------------
00671 // Lays out one line of text.
00672 // Author: pdaehne
00673 //----------------------------------------------------------------------
00674 void TextTXFFace::layout(const string &utf8Text,
00675                          const TextLayoutParam &param,
00676                          TextLayoutResult &result)
00677 {
00678     TextFace::layout(utf8Text, param, result);
00679 }
00680 
00681 
00682 //----------------------------------------------------------------------
00683 // Lays out one line of text
00684 // Author: pdaehne
00685 //----------------------------------------------------------------------
00686 void TextTXFFace::layout(const wstring &text,
00687                          const TextLayoutParam &param,
00688                          TextLayoutResult &result)
00689 {
00690     // Initialize return values
00691     result.clear();
00692 
00693     // Do the layout depending on the direction
00694     Vec2f currPos;
00695     size_t i, len = text.length();
00696     result.indices.reserve(len);
00697     result.positions.reserve(len);
00698     vector<UInt32> spaceIndices;
00699     bool justify = param.getLength(0) > 0.f;
00700     for (i = 0; i < len; ++i)
00701     {
00702         // Get glyph
00703         const TextGlyph &glyph = getGlyph(text[i]);
00704         if ((justify == true) && (text[i] == ' '))
00705             spaceIndices.push_back(result.indices.size());
00706 
00707         // Calculate position
00708         Vec2f pos;
00709         if (param.horizontal == true)
00710         {
00711             if (param.leftToRight == true)
00712             {
00713                 pos = currPos;
00714                 pos[0] += glyph.getHoriBearingX();
00715                 pos[1] += glyph.getHoriBearingY();
00716                 currPos[0] += glyph.getHoriAdvance();
00717             }
00718             else // leftToRight == false
00719             {
00720                 currPos[0] -= glyph.getHoriAdvance();
00721                 pos = currPos;
00722                 pos[0] += glyph.getHoriBearingX();
00723                 pos[1] += glyph.getHoriBearingY();
00724             }
00725         }
00726         else // horizontal == false
00727         {
00728             if (param.topToBottom == true)
00729             {
00730                 pos = currPos;
00731                 pos[0] += glyph.getVertBearingX();
00732                 pos[1] += glyph.getVertBearingY();
00733                 currPos[1] += glyph.getVertAdvance();
00734             }
00735             else // topToBottom == false
00736             {
00737                 currPos[1] -= glyph.getVertAdvance();
00738                 pos = currPos;
00739                 pos[0] += glyph.getVertBearingX();
00740                 pos[1] += glyph.getVertBearingY();
00741             }
00742         }
00743 
00744         result.indices.push_back(glyph.getGlyphIndex());
00745         result.positions.push_back(pos);
00746     }
00747 
00748     // Justify the line
00749     if (justify == true)
00750         justifyLine(param, spaceIndices, currPos, result);
00751 
00752     // Adjust the origin depending on the major and the minor alignment
00753     adjustLineOrigin(param, currPos, result);
00754 
00755     // Determine text bounds / line bounds
00756     if (param.horizontal == true)
00757         result.textBounds.setValues(osgabs(currPos.x()), _horiAscent - _horiDescent);
00758     else
00759         result.textBounds.setValues(_vertDescent - _vertAscent, osgabs(currPos.y()));
00760     result.lineBounds.push_back(result.textBounds);
00761 }
00762 
00763 
00764 //----------------------------------------------------------------------
00765 // Lays out multiple lines of text
00766 // Author: pdaehne
00767 //----------------------------------------------------------------------
00768 void TextTXFFace::layout(const vector<string> &lines,
00769                          const TextLayoutParam &param,
00770                          TextLayoutResult &result)
00771 {
00772     TextFace::layout(lines, param, result);
00773 }
00774 
00775 
00776 //----------------------------------------------------------------------
00777 // Lays out multiple lines of text
00778 // Author: pdaehne
00779 //----------------------------------------------------------------------
00780 void TextTXFFace::layout(const vector<wstring> &lines,
00781                          const TextLayoutParam &param,
00782                          TextLayoutResult &result)
00783 {
00784     TextFace::layout(lines, param, result);
00785 }
00786 
00787 
00788 //----------------------------------------------------------------------
00789 // Calculates the positions of the glyphs on the texture
00790 // Author: pdaehne
00791 //----------------------------------------------------------------------
00792 void TextTXFFace::prepareTexture(const TextTXFParam &param)
00793 {
00794     // Sort characters by height and calculate the area necessary
00795     // to keep all characters
00796     typedef multimap<UInt32, TextTXFGlyph*, greater<UInt32> > HeightMap;
00797     HeightMap heightMap;
00798     UInt32 area = 0, maxWidth = 0;
00799     GlyphMap::iterator gmIt;
00800     for (gmIt = _glyphMap.begin(); gmIt != _glyphMap.end(); ++gmIt)
00801     {
00802         TextTXFGlyph *glyph = gmIt->second;
00803         heightMap.insert(HeightMap::value_type(glyph->getPixmapHeight(), glyph));
00804         if (maxWidth < glyph->getPixmapWidth())
00805             maxWidth = glyph->getPixmapWidth();
00806         area += (glyph->getPixmapWidth() + param.gap) * (glyph->getPixmapHeight() + param.gap);
00807     }
00808 
00809     UInt32 textureSize;
00810     if (param.textureWidth == 0)
00811     {
00812         // Try to make a good guess about the optimal width of the texture
00813         textureSize = static_cast<UInt32>(ceil(sqrt(static_cast<Real32>(area))));
00814     }
00815     else
00816         textureSize = param.textureWidth;
00817     maxWidth += param.gap << 1;
00818     if (textureSize < maxWidth)
00819         textureSize = maxWidth;
00820     UInt32 textureWidth = osgnextpower2(textureSize);
00821 
00822     // Calculate the positions of the glyphs in the texture
00823     HeightMap::iterator hmIt = heightMap.begin();
00824     UInt32 xpos = param.gap, ypos = param.gap, heightOfRow = 0;
00825     while (hmIt != heightMap.end())
00826     {
00827         HeightMap::iterator hmIt3;
00828         // Does the next glyph fit into the line?
00829         if (xpos + hmIt->second->getPixmapWidth() + param.gap > textureWidth)
00830         {
00831             // No, so lets try to find another glyph
00832             HeightMap::iterator hmIt2 = hmIt;
00833             ++hmIt2;
00834             for (++hmIt2; hmIt2 != heightMap.end(); ++hmIt2)
00835             {
00836                 if (xpos + hmIt2->second->getPixmapWidth() + param.gap <= textureWidth)
00837                     break;
00838             }
00839             if (hmIt2 == heightMap.end())
00840             {
00841                 // There no other glyph
00842                 xpos = param.gap;
00843                 ypos += heightOfRow + param.gap;
00844                 heightOfRow = 0;
00845                 hmIt3 = hmIt;
00846                 ++hmIt;
00847             }
00848             else // There is another glyph that fits
00849                 hmIt3 = hmIt2;
00850         }
00851         else
00852         {
00853             // Yes, the glyph fits into the line
00854             hmIt3 = hmIt;
00855             ++hmIt;
00856         }
00857         hmIt3->second->_x = xpos;
00858         hmIt3->second->_y = ypos;
00859         xpos += hmIt3->second->getPixmapWidth() + param.gap;
00860         if (hmIt3->second->getPixmapHeight() > heightOfRow)
00861             heightOfRow = hmIt3->second->getPixmapHeight();
00862         heightMap.erase(hmIt3);
00863     }
00864     ypos += heightOfRow;
00865 
00866     // Calculate the height of the texture
00867     UInt32 textureHeight = osgnextpower2(static_cast<UInt32>(ypos));
00868 
00869     // Create the texture
00870     _texture = Image::create();
00871     addRefCP(_texture);
00872     beginEditCP(_texture);
00873     {
00874         _texture->set(Image::OSG_I_PF, textureWidth, textureHeight);
00875         _texture->clear();
00876     }
00877     endEditCP(_texture);
00878 
00879     // Calculate the coordinates of all glyphs
00880     for (gmIt = _glyphMap.begin(); gmIt != _glyphMap.end(); ++gmIt)
00881         gmIt->second->calculateCoordinates(textureWidth, textureHeight);
00882 }
00883 
00884 
00885 OSG_END_NAMESPACE
00886 
00887 
00888 /*------------------------------------------------------------------------*/
00889 /*                              cvs id's                                  */
00890 
00891 #ifdef OSG_SGI_CC
00892 #pragma set woff 1174
00893 #endif
00894 
00895 #ifdef OSG_LINUX_ICC
00896 #pragma warning( disable : 177 )
00897 #endif
00898 
00899 namespace
00900 {
00901     static OSG::Char8 cvsid_cpp[] = "@(#)$Id: OSGTextTXFFace.cpp,v 1.5 2005/07/05 16:25:15 dirk Exp $";
00902     static OSG::Char8 cvsid_hpp[] = OSGTEXTTXFFACE_HEADER_CVSID;
00903     static OSG::Char8 cvsid_inl[] = OSGTEXTTXFFACE_INLINE_CVSID;
00904 }
00905 
00906 #ifdef __sgi
00907 #pragma reset woff 1174
00908 #endif

Generated on Thu Aug 25 04:11:18 2005 for OpenSG by  doxygen 1.4.3