Ejemplo n.º 1
0
//----------------------------------------------------------------------
// Calculates the bounding box of a text after layout
// Author: pdaehne
//----------------------------------------------------------------------
void TextFace::calculateBoundingBox(const TextLayoutResult &layoutResult, Vec2f &lowerLeft, Vec2f &upperRight)
{
    // Initialize bounding box
    lowerLeft.setValues(FLT_MAX, FLT_MAX);
    upperRight.setValues(-FLT_MAX, -FLT_MAX);

    UInt32 i, numGlyphs = layoutResult.getNumGlyphs();
    for (i = 0; i < numGlyphs; ++i)
    {
        const TextGlyph &glyph = getGlyph(layoutResult.indices[i]);
        Real32 width = glyph.getWidth();
        Real32 height = glyph.getHeight();
        // Don't handle invisible glyphs
        if ((width <= 0.f) || (height <= 0.f))
            continue;

        // Calculate coodinates
        const Vec2f &pos = layoutResult.positions[i];
        Real32 left = pos.x();
        Real32 right = left + glyph.getWidth();
        Real32 top = pos.y();
        Real32 bottom = top - glyph.getHeight();

        // Adjust bounding box
        if (lowerLeft[0] > left)
            lowerLeft[0] = left;
        if (upperRight[0] < right)
            upperRight[0] = right;
        if (upperRight[1] < top)
            upperRight[1] = top;
        if (lowerLeft[1] > bottom)
            lowerLeft[1] = bottom;
    }
}
//----------------------------------------------------------------------
// Creates a texture image with the result of a layout operation
// Author: pdaehne
//----------------------------------------------------------------------
ImageTransitPtr TextPixmapFace::makeImage(const TextLayoutResult &layoutResult, Vec2f &offset, UInt32 border)
{
    Vec2f lowerLeft, upperRight;
    calculateBoundingBox(layoutResult, lowerLeft, upperRight);
    offset.setValues(lowerLeft.x() - border, upperRight.y() + border);

    ImageTransitPtr imagePtr = Image::create();

    UInt32 width  = static_cast<UInt32>(osgCeil(upperRight.x() - lowerLeft.x())) + (border << 1);
    UInt32 height = static_cast<UInt32>(osgCeil(upperRight.y() - lowerLeft.y())) + (border << 1);
    imagePtr->set(Image::OSG_A_PF, width, height);
    imagePtr->clear();
    UInt8 *buffer = imagePtr->editData();

    // Put the glyphs into the texture
    UInt32 i, numGlyphs = layoutResult.getNumGlyphs();
    for (i = 0; i < numGlyphs; ++i)
    {
        const TextPixmapGlyph &glyph = getPixmapGlyph(layoutResult.indices[i]);
        const Vec2f &pos = layoutResult.positions[i];
        Int32 x = static_cast<Int32>(pos.x() - lowerLeft.x() + 0.5f) + border;
        Int32 y = static_cast<Int32>(pos.y() - lowerLeft.y() + 0.5f) + border;
        glyph.putPixmap(x, y, buffer, width, height);
    }

    return imagePtr;
}
void Graphics3DExtrude::drawCharacters( const TextLayoutResult& layoutResult, const UIFontUnrecPtr TheFont) const
{
    glBegin(GL_QUADS);

    UInt32 i, numGlyphs = layoutResult.getNumGlyphs();
    Real32 width, height;
    for(i = 0; i < numGlyphs; ++i)
    {
        const TextTXFGlyph *glyph = TheFont->getTXFGlyph(layoutResult.indices[i]);
        width = glyph->getWidth();
        height = glyph->getHeight();
        // No need to draw invisible glyphs
        if ((width <= 0.f) || (height <= 0.f))
            continue;

        // Calculate coordinates
        const Vec2f &pos = layoutResult.positions[i];
        Real32 posLeft = pos.x();
        Real32 posTop = -pos.y();
        Real32 posRight = pos.x() + width;
        Real32 posBottom = -pos.y() + height;
        Real32 texCoordLeft = glyph->getTexCoord(TextTXFGlyph::COORD_LEFT);
        Real32 texCoordTop = glyph->getTexCoord(TextTXFGlyph::COORD_TOP);
        Real32 texCoordRight = glyph->getTexCoord(TextTXFGlyph::COORD_RIGHT);
        Real32 texCoordBottom = glyph->getTexCoord(TextTXFGlyph::COORD_BOTTOM);

        // lower left corner
		Real32 Offset(0.001);
	    glNormal3f(0.0,0.0,1.0);
        glTexCoord2f(texCoordLeft, texCoordBottom);
        glVertex3f(posLeft, posBottom, getTextOffset());

        // lower right corner
        glTexCoord2f(texCoordRight, texCoordBottom);
        glVertex3f(posRight, posBottom, getTextOffset());

        // upper right corner
        glTexCoord2f(texCoordRight, texCoordTop);
        glVertex3f(posRight, posTop, getTextOffset());

        // upper left corner
        glTexCoord2f(texCoordLeft, texCoordTop);
        glVertex3f(posLeft, posTop, getTextOffset());


    }

    glEnd();
}
Ejemplo n.º 4
0
// Create the metrics
NodePtr createMetrics(TextFace *face, Real32 scale, const TextLayoutParam &layoutParam,
                      const TextLayoutResult &layoutResult)
{
    GeometryPtr geoPtr = Geometry::create();
    beginEditCP(geoPtr);
    {
        GeoPTypesUI8Ptr typesPtr = GeoPTypesUI8::create();
        geoPtr->setTypes(typesPtr);

        GeoPLengthsUI32Ptr lensPtr = GeoPLengthsUI32::create();
        geoPtr->setLengths(lensPtr);

        GeoPositions3fPtr posPtr = GeoPositions3f::create();
        geoPtr->setPositions(posPtr);

        GeoColors3fPtr colorsPtr = GeoColors3f::create();
        colorsPtr->push_back(Color3f(0.f, 0.f, 1.f));
        colorsPtr->push_back(Color3f(1.f, 0.f, 0.f));
        colorsPtr->push_back(Color3f(0.f, 1.f, 0.f));
        colorsPtr->push_back(Color3f(1.f, 1.f, 0.f));
        geoPtr->setColors(colorsPtr);

        GeoIndicesUI32Ptr indicesPtr = GeoIndicesUI32::create();
        geoPtr->setIndices(indicesPtr);

        UInt32 i, numGlyphs = layoutResult.getNumGlyphs();
        for (i = 0; i < numGlyphs; ++i)
        {
            const TextGlyph &glyph = face->getGlyph(layoutResult.indices[i]);
            typesPtr->push_back(GL_LINE_LOOP);
            lensPtr->push_back(4);
            const Vec2f &pos = layoutResult.positions[i];
            Real32 left = pos.x() * scale;
            Real32 right = (pos.x() + glyph.getWidth()) * scale;
            Real32 top = pos.y() * scale;
            Real32 bottom = (pos.y() - glyph.getHeight()) * scale;
            UInt32 posOffset = posPtr->size();
            posPtr->push_back(Vec3f(left, bottom, 0.f));
            posPtr->push_back(Vec3f(right, bottom, 0.f));
            posPtr->push_back(Vec3f(right, top, 0.f));
            posPtr->push_back(Vec3f(left, top, 0.f));
            indicesPtr->push_back(posOffset);
            indicesPtr->push_back(0);
            indicesPtr->push_back(posOffset + 1);
            indicesPtr->push_back(0);
            indicesPtr->push_back(posOffset + 2);
            indicesPtr->push_back(0);
            indicesPtr->push_back(posOffset + 3);
            indicesPtr->push_back(0);
        }

        // Bounding box
        Vec2f lowerLeft, upperRight;
        face->calculateBoundingBox(layoutResult, lowerLeft, upperRight);
        typesPtr->push_back(GL_LINE_LOOP);
        lensPtr->push_back(4);
        Real32 left = lowerLeft.x() * scale;
        Real32 right = upperRight.x() * scale;
        Real32 top = upperRight.y() * scale;
        Real32 bottom = lowerLeft.y() * scale;
        UInt32 posOffset = posPtr->size();
        posPtr->push_back(Vec3f(left, bottom, 0.f));
        posPtr->push_back(Vec3f(right, bottom, 0.f));
        posPtr->push_back(Vec3f(right, top, 0.f));
        posPtr->push_back(Vec3f(left, top, 0.f));
        indicesPtr->push_back(posOffset);
        indicesPtr->push_back(1);
        indicesPtr->push_back(posOffset + 1);
        indicesPtr->push_back(1);
        indicesPtr->push_back(posOffset + 2);
        indicesPtr->push_back(1);
        indicesPtr->push_back(posOffset + 3);
        indicesPtr->push_back(1);

        // Text bounds & Line bounds
        Vec2f pos, textPos, offset;
        if (layoutParam.horizontal == true)
        {
            Real32 lineHeight = face->getHoriAscent() - face->getHoriDescent();
            Real32 spacing = layoutParam.spacing * lineHeight;
            if (layoutParam.topToBottom == true)
            {
                switch (layoutParam.minorAlignment)
                {
                    case TextLayoutParam::ALIGN_BEGIN:
                        break;
                    case TextLayoutParam::ALIGN_FIRST:
                        pos[1] = textPos[1] = face->getHoriAscent();
                        break;
                    case TextLayoutParam::ALIGN_MIDDLE:
                        pos[1] = textPos[1] = (spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f;
                        break;
                    case TextLayoutParam::ALIGN_END:
                        pos[1] = textPos[1] = spacing * (layoutResult.lineBounds.size() - 1) + lineHeight;
                        break;
                }
                offset.setValues(0.f, -spacing);
            }
            else
            {
                switch (layoutParam.minorAlignment)
                {
                    case TextLayoutParam::ALIGN_BEGIN:
                        pos[1] = lineHeight;
                        textPos[1] = spacing * (layoutResult.lineBounds.size() - 1) + lineHeight;
                        break;
                    case TextLayoutParam::ALIGN_FIRST:
                        pos[1] = face->getHoriAscent();
                        textPos[1] = spacing * (layoutResult.lineBounds.size() - 1) + face->getHoriAscent();
                        break;
                    case TextLayoutParam::ALIGN_MIDDLE:
                        pos[1] = -(spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f + lineHeight;
                        textPos[1] = (spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f;
                        break;
                    case TextLayoutParam::ALIGN_END:
                        pos[1] = -spacing * (layoutResult.lineBounds.size() - 1);
                        break;
                }
                offset.setValues(0.f, spacing);
            }
        }
        else
        {
            Real32 lineHeight = face->getVertDescent() - face->getVertAscent();
            Real32 spacing = layoutParam.spacing * lineHeight;
            if (layoutParam.leftToRight == true)
            {
                switch (layoutParam.minorAlignment)
                {
                    case TextLayoutParam::ALIGN_BEGIN:
                        break;
                    case TextLayoutParam::ALIGN_FIRST:
                        pos[0] = textPos[0] = face->getVertAscent();
                        break;
                    case TextLayoutParam::ALIGN_MIDDLE:
                        pos[0] = textPos[0] = -(spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f;
                        break;
                    case TextLayoutParam::ALIGN_END:
                        pos[0] = textPos[0] = -spacing * (layoutResult.lineBounds.size() - 1) - lineHeight;
                        break;
                }
                offset.setValues(spacing, 0.f);
            }
            else
            {
                switch (layoutParam.minorAlignment)
                {
                    case TextLayoutParam::ALIGN_BEGIN:
                        pos[0] = -lineHeight;
                        textPos[0] = -spacing * (layoutResult.lineBounds.size() - 1) - lineHeight;
                        break;
                    case TextLayoutParam::ALIGN_FIRST:
                        pos[0] = -face->getVertDescent();
                        textPos[0] = -spacing * (layoutResult.lineBounds.size() - 1) -face->getVertDescent();
                        break;
                    case TextLayoutParam::ALIGN_MIDDLE:
                        pos[0] = (spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f - lineHeight;
                        textPos[0] = -(spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f;
                        break;
                    case TextLayoutParam::ALIGN_END:
                        pos[0] = spacing * (layoutResult.lineBounds.size() - 1);
                        break;
                }
                offset.setValues(-spacing, 0.f);
            }
        }

        typesPtr->push_back(GL_LINE_LOOP);
        lensPtr->push_back(4);
        left = textPos.x();
        top = textPos.y();
        if (layoutParam.horizontal == true)
            if (layoutParam.leftToRight == true)
                switch (layoutParam.majorAlignment)
                {
                    case TextLayoutParam::ALIGN_BEGIN:
                    case TextLayoutParam::ALIGN_FIRST:
                        break;
                    case TextLayoutParam::ALIGN_MIDDLE:
                        left -= layoutResult.textBounds.x() / 2.f;
                        break;
                    case TextLayoutParam::ALIGN_END:
                        left -= layoutResult.textBounds.x();
                        break;
                }
            else
                switch (layoutParam.majorAlignment)
                {
                    case TextLayoutParam::ALIGN_BEGIN:
                    case TextLayoutParam::ALIGN_FIRST:
                        left -= layoutResult.textBounds.x();
                        break;
                    case TextLayoutParam::ALIGN_MIDDLE:
                        left -= layoutResult.textBounds.x() / 2.f;
                        break;
                    case TextLayoutParam::ALIGN_END:
                        break;
                }
        else
            if (layoutParam.topToBottom == true)
                switch (layoutParam.majorAlignment)
                {
                    case TextLayoutParam::ALIGN_BEGIN:
                    case TextLayoutParam::ALIGN_FIRST:
                        break;
                    case TextLayoutParam::ALIGN_MIDDLE:
                        top += layoutResult.textBounds.y() / 2.f;
                        break;
                    case TextLayoutParam::ALIGN_END:
                        top += layoutResult.textBounds.y();
                        break;
                }
            else
                switch (layoutParam.majorAlignment)
                {
                    case TextLayoutParam::ALIGN_BEGIN:
                    case TextLayoutParam::ALIGN_FIRST:
                        top += layoutResult.textBounds.y();
                        break;
                    case TextLayoutParam::ALIGN_MIDDLE:
                        top += layoutResult.textBounds.y() / 2.f;
                        break;
                    case TextLayoutParam::ALIGN_END:
                        break;
                }
        left *= scale;
        right = left + layoutResult.textBounds.x() * scale;
        top *= scale;
        bottom = top - layoutResult.textBounds.y() * scale;
        posOffset = posPtr->size();
        posPtr->push_back(Vec3f(left, bottom, 0.f));
        posPtr->push_back(Vec3f(right, bottom, 0.f));
        posPtr->push_back(Vec3f(right, top, 0.f));
        posPtr->push_back(Vec3f(left, top, 0.f));
        indicesPtr->push_back(posOffset);
        indicesPtr->push_back(3);
        indicesPtr->push_back(posOffset + 1);
        indicesPtr->push_back(3);
        indicesPtr->push_back(posOffset + 2);
        indicesPtr->push_back(3);
        indicesPtr->push_back(posOffset + 3);
        indicesPtr->push_back(3);

        vector<Vec2f>::const_iterator lbIt;
        for (lbIt = layoutResult.lineBounds.begin(); lbIt != layoutResult.lineBounds.end(); ++lbIt)
        {
            typesPtr->push_back(GL_LINE_LOOP);
            lensPtr->push_back(4);
            Real32 left = pos.x();
            Real32 top = pos.y();
            if (layoutParam.horizontal == true)
                if (layoutParam.leftToRight == true)
                    switch (layoutParam.majorAlignment)
                    {
                        case TextLayoutParam::ALIGN_BEGIN:
                        case TextLayoutParam::ALIGN_FIRST:
                            break;
                        case TextLayoutParam::ALIGN_MIDDLE:
                            left -= lbIt->x() / 2.f;
                            break;
                        case TextLayoutParam::ALIGN_END:
                            left -= lbIt->x();
                            break;
                    }
                else
                    switch (layoutParam.majorAlignment)
                    {
                        case TextLayoutParam::ALIGN_BEGIN:
                        case TextLayoutParam::ALIGN_FIRST:
                            left -= lbIt->x();
                            break;
                        case TextLayoutParam::ALIGN_MIDDLE:
                            left -= lbIt->x() / 2.f;
                            break;
                        case TextLayoutParam::ALIGN_END:
                            break;
                    }
            else
                if (layoutParam.topToBottom == true)
                    switch (layoutParam.majorAlignment)
                    {
                        case TextLayoutParam::ALIGN_BEGIN:
                        case TextLayoutParam::ALIGN_FIRST:
                            break;
                        case TextLayoutParam::ALIGN_MIDDLE:
                            top += lbIt->y() / 2.f;
                            break;
                        case TextLayoutParam::ALIGN_END:
                            top += lbIt->y();
                            break;
                    }
                else
                    switch (layoutParam.majorAlignment)
                    {
                        case TextLayoutParam::ALIGN_BEGIN:
                        case TextLayoutParam::ALIGN_FIRST:
                            top += lbIt->y();
                            break;
                        case TextLayoutParam::ALIGN_MIDDLE:
                            top += lbIt->y() / 2.f;
                            break;
                        case TextLayoutParam::ALIGN_END:
                            break;
                    }
            left *= scale;
            Real32 right = left + lbIt->x() * scale;
            top *= scale;
            Real32 bottom = top - lbIt->y() * scale;
            UInt32 posOffset = posPtr->size();
            posPtr->push_back(Vec3f(left, bottom, 0.f));
            posPtr->push_back(Vec3f(right, bottom, 0.f));
            posPtr->push_back(Vec3f(right, top, 0.f));
            posPtr->push_back(Vec3f(left, top, 0.f));
            indicesPtr->push_back(posOffset);
            indicesPtr->push_back(2);
            indicesPtr->push_back(posOffset + 1);
            indicesPtr->push_back(2);
            indicesPtr->push_back(posOffset + 2);
            indicesPtr->push_back(2);
            indicesPtr->push_back(posOffset + 3);
            indicesPtr->push_back(2);

            typesPtr->push_back(GL_LINE_STRIP);
            lensPtr->push_back(2);
            posOffset = posPtr->size();
            if (layoutParam.horizontal == true)
            {
                Real32 base = top - face->getHoriAscent() * scale;
                posPtr->push_back(Vec3f(left, base, 0.f));
                posPtr->push_back(Vec3f(right, base, 0.f));
            }
            else
            {
                Real32 base = left - face->getVertAscent() * scale;
                posPtr->push_back(Vec3f(base, top, 0.f));
                posPtr->push_back(Vec3f(base, bottom, 0.f));
            }
            indicesPtr->push_back(posOffset);
            indicesPtr->push_back(2);
            indicesPtr->push_back(posOffset + 1);
            indicesPtr->push_back(2);
            pos += offset;
        }

        geoPtr->editMFIndexMapping()->clear();
        geoPtr->editMFIndexMapping()->push_back(Geometry::MapPosition);
        geoPtr->editMFIndexMapping()->push_back(Geometry::MapColor);

        SimpleMaterialPtr matPtr = SimpleMaterial::create();
        geoPtr->setMaterial(matPtr);
    }
    endEditCP(geoPtr);

    NodePtr nodePtr = Node::create();
    beginEditCP(nodePtr, Node::CoreFieldMask);
    {
        nodePtr->setCore(geoPtr);
    }
    endEditCP(nodePtr, Node::CoreFieldMask);

    return nodePtr;
}
Ejemplo n.º 5
0
//----------------------------------------------------------------------
// Lays out multiple lines of text
// Author: pdaehne
//----------------------------------------------------------------------
void TextFace::layout(const vector<wstring> &lines,
                      const TextLayoutParam &param,
                      TextLayoutResult &result)
{
    // Initialize return values
    result.clear();

    TextLayoutParam lineParam = param;
    Vec2f offset, lineOffset;
    if (param.horizontal == true)
    {
        Real32 lineHeight = _horiAscent - _horiDescent;
        Real32 spacing = param.spacing * lineHeight;
        Real32 leading = spacing - lineHeight;
        Real32 fullHeight = spacing * lines.size() - leading;
        result.textBounds[1] = fullHeight;
        lineParam.minorAlignment = TextLayoutParam::ALIGN_FIRST;
        if (param.topToBottom == true)
        {
            lineOffset[1] = -spacing;
            switch (param.minorAlignment)
            {
                default:
                case TextLayoutParam::ALIGN_FIRST:
                    break;
                case TextLayoutParam::ALIGN_BEGIN:
                    offset[1] = -_horiAscent;
                    break;
                case TextLayoutParam::ALIGN_MIDDLE:
                    offset[1] = -_horiAscent + fullHeight / 2.f;
                    break;
                case TextLayoutParam::ALIGN_END:
                    offset[1] = -_horiAscent + fullHeight;
                    break;
            }
        }
        else // topToBottom == false
        {
            lineOffset[1] = spacing;
            switch (param.minorAlignment)
            {
                default:
                case TextLayoutParam::ALIGN_FIRST:
                    break;
                case TextLayoutParam::ALIGN_BEGIN:
                    offset[1] = -_horiDescent;
                    break;
                case TextLayoutParam::ALIGN_MIDDLE:
                    offset[1] = -_horiDescent - fullHeight / 2.f;
                    break;
                case TextLayoutParam::ALIGN_END:
                    offset[1] = -_horiDescent - fullHeight;
                    break;
            }
        }
    }
    else // horizontal == false
    {
        Real32 lineHeight = _vertDescent - _vertAscent;
        Real32 spacing = param.spacing * lineHeight;
        Real32 leading = spacing - lineHeight;
        Real32 fullHeight = spacing * lines.size() - leading;
        result.textBounds[0] = fullHeight;
        lineParam.minorAlignment = TextLayoutParam::ALIGN_FIRST;
        if (param.leftToRight == true)
        {
            lineOffset[0] = spacing;
            switch (param.minorAlignment)
            {
                default:
                case TextLayoutParam::ALIGN_FIRST:
                    break;
                case TextLayoutParam::ALIGN_BEGIN:
                    offset[0] = -_vertAscent;
                    break;
                case TextLayoutParam::ALIGN_MIDDLE:
                    offset[0] = -_vertAscent - fullHeight / 2.f;
                    break;
                case TextLayoutParam::ALIGN_END:
                    offset[0] = -_vertAscent - fullHeight;
                    break;
            }
        }
        else // leftToRight == false
        {
            lineOffset[0] = -spacing;
            switch (param.minorAlignment)
            {
                default:
                case TextLayoutParam::ALIGN_FIRST:
                    break;
                case TextLayoutParam::ALIGN_BEGIN:
                    offset[0] = -_vertDescent;
                    break;
                case TextLayoutParam::ALIGN_MIDDLE:
                    offset[0] = -_vertDescent + fullHeight / 2.f;
                    break;
                case TextLayoutParam::ALIGN_END:
                    offset[0] = -_vertDescent + fullHeight;
                    break;
            }
        }
    }

    result.lineBounds.reserve(lines.size());
    TextLayoutResult lineResult;
    Real32 maxExtend = 0.f;
    UInt32 lineIndex;
    for (lineIndex = 0; lineIndex < lines.size(); ++lineIndex)
    {
        lineParam.setLength(param.getLength(lineIndex));
        layout(lines[lineIndex], lineParam, lineResult);
        UInt32 i, numGlyphs = lineResult.getNumGlyphs();
        for (i = 0; i < numGlyphs; ++i)
        {
            result.indices.push_back(lineResult.indices[i]);
            result.positions.push_back(lineResult.positions[i] + offset);
        }
        OSG_ASSERT(lineResult.lineBounds.empty() == false);
        result.lineBounds.push_back(lineResult.lineBounds.front());
        Real32 extend = lineResult.lineBounds.front()[param.horizontal == true ? 0 : 1];
        if (extend > maxExtend)
            maxExtend = extend;
        offset += lineOffset;
    }
    result.textBounds[param.horizontal == true ? 0 : 1] = maxExtend;
}
Ejemplo n.º 6
0
//----------------------------------------------------------------------
// Fills a geometry with a new text
// Author: afischle, pdaehne
//----------------------------------------------------------------------
void TextVectorFace::fillGeo(Geometry *geoPtr, const TextLayoutResult &layoutResult,
                             Real32 scale, Real32 depth, UInt32 level,
                             Real32 creaseAngle)
{
    // cast the field containers down to the needed type and create them
    // when they have the wrong type
    GeoPnt3fPropertyUnrecPtr posPtr = 
        dynamic_cast<GeoPnt3fProperty *>(geoPtr->getPositions());

    if (posPtr == NULL)
    {
        posPtr = GeoPnt3fProperty::create();
        geoPtr->setPositions(posPtr);
    }
    else
        posPtr->clear();
    GeoVec3fPropertyUnrecPtr normalsPtr = 
        dynamic_cast<GeoVec3fProperty *>(geoPtr->getNormals());

    if (normalsPtr == NULL)
    {
        normalsPtr = GeoVec3fProperty::create();
        geoPtr->setNormals(normalsPtr);
    }
    else
        normalsPtr->clear();

    GeoVec2fPropertyUnrecPtr texPtr = 
        dynamic_cast<GeoVec2fProperty *>(geoPtr->getTexCoords());

    if (texPtr == NULL)
    {
        texPtr = GeoVec2fProperty::create();
        geoPtr->setTexCoords(texPtr);
    }
    else
        texPtr->clear();

    GeoUInt32PropertyUnrecPtr lensPtr = 
        dynamic_cast<GeoUInt32Property *>(geoPtr->getLengths());

    if (lensPtr == NULL)
    {
        lensPtr = GeoUInt32Property::create();
        geoPtr->setLengths(lensPtr);
    }
    else
        lensPtr->clear();

    GeoUInt32PropertyUnrecPtr posIndicesPtr = 
        dynamic_cast<GeoUInt32Property *>(
            geoPtr->getIndex(Geometry::PositionsIndex));

    if (posIndicesPtr == NULL)
    {
        posIndicesPtr = GeoUInt32Property::create();
        geoPtr->setIndex(posIndicesPtr, Geometry::PositionsIndex);
    }
    else
        posIndicesPtr->clear();

    GeoUInt32PropertyUnrecPtr normalIndicesPtr = 
        dynamic_cast<GeoUInt32Property *>(
            geoPtr->getIndex(Geometry::NormalsIndex));

    if (normalIndicesPtr == NULL)
    {
        normalIndicesPtr = GeoUInt32Property::create();
        geoPtr->setIndex(normalIndicesPtr, Geometry::NormalsIndex);
    }
    else
        normalIndicesPtr->clear();

    GeoUInt32PropertyUnrecPtr texCoordIndicesPtr = 
        dynamic_cast<GeoUInt32Property *>(
            geoPtr->getIndex(Geometry::TexCoordsIndex));

    if (texCoordIndicesPtr == NULL)
    {
        texCoordIndicesPtr = GeoUInt32Property::create();
        geoPtr->setIndex(texCoordIndicesPtr, Geometry::TexCoordsIndex);
    }
    else
        texCoordIndicesPtr->clear();

    GeoUInt8PropertyUnrecPtr typesPtr = 
        dynamic_cast<GeoUInt8Property *>(geoPtr->getTypes());

    if (typesPtr == NULL)
    {
        typesPtr = GeoUInt8Property::create();
        geoPtr->setTypes(typesPtr);
    }
    else
        typesPtr->clear();

    geoPtr->setColors(NULL);
    geoPtr->setSecondaryColors(NULL);
    geoPtr->setTexCoords1(NULL);
    geoPtr->setTexCoords2(NULL);
    geoPtr->setTexCoords3(NULL);

    UInt32 numGlyphs = layoutResult.getNumGlyphs();
    if (numGlyphs == 0)
    {
        return;
    }

    // the interleaved multi-index blocks have the layout
    // Position | Normal | TexCoord
/*
    geoPtr->getIndexMapping().push_back(Geometry::MapPosition);
    geoPtr->getIndexMapping().push_back(Geometry::MapNormal);
    geoPtr->getIndexMapping().push_back(Geometry::MapTexCoords);
 */

    // store the normal for the front face
    normalsPtr->push_back(Vec3f(0.f, 0.f, 1.f));
    if (depth > 0.f)
        // store the normal for the back face
        normalsPtr->push_back(Vec3f(0.f, 0.f, -1.f));

    UInt32 i;
    for (i = 0; i < numGlyphs; ++i)
    {
        const TextVectorGlyph &glyph = getVectorGlyph(layoutResult.indices[i]);
        const TextVectorGlyph::PolygonOutline &outline = glyph.getLines(level);
        const Vec2f &pos = layoutResult.positions[i];

        // add the front face to the geometry

        // store positions and texture coordinates
        UInt32 coordOffset = posPtr->size();
        UInt32 texCoordOffset = texPtr->size();
        Real32 coordZ = 0.5f * depth;
        vector<Vec2f>::const_iterator cIt;
        for (cIt = outline.coords.begin(); cIt != outline.coords.end(); ++cIt)
        {
            Vec2f coord = *cIt + pos;
            Vec2f texCoord = coord;
            coord *= scale;
            posPtr->push_back(Vec3f(coord.x(), coord.y(), coordZ));
            texCoord -= layoutResult.positions.front();
            texPtr->push_back(texCoord);
        }

        // Store types, lengths and indices
        vector<TextVectorGlyph::PolygonOutline::TypeIndex>::const_iterator tIt;
        UInt32 indexBegin = 0, indexEnd;
        for (tIt = outline.types.begin(); tIt != outline.types.end(); ++tIt)
        {
            typesPtr->push_back(tIt->first);
            indexEnd = tIt->second;
            OSG_ASSERT(indexEnd >= indexBegin);
            lensPtr->push_back(indexEnd - indexBegin);
            UInt32 i;
            for (i = indexBegin; i < indexEnd; ++i)
            {
                // the interleaved multi-index blocks have the layout
                // Position | Normal | TexCoord
                OSG_ASSERT(i < outline.indices.size());
                UInt32 index = outline.indices[i];
                OSG_ASSERT(coordOffset + index < posPtr->size());
                posIndicesPtr->push_back(coordOffset + index);
                normalIndicesPtr->push_back(0);
                OSG_ASSERT(texCoordOffset + index < texPtr->size());
                texCoordIndicesPtr->push_back(texCoordOffset + index);
            }
            indexBegin = indexEnd;
        }

        // add the back and side faces only if depth > 0
        if (depth > 0.f)
        {
            // add the back face to the geometry

            // store positions
            // No need to store texture coordinates - we reuse the
            // texture coordinates from the front side
            UInt32 backCoordOffset = posPtr->size();
            coordZ = -0.5f * depth;
            for (cIt = outline.coords.begin(); cIt != outline.coords.end(); ++cIt)
            {
                Vec2f coord = *cIt + pos;
                coord *= scale;
                posPtr->push_back(Vec3f(coord.x(), coord.y(), coordZ));
            }

            // Store types, lengths and indices
            // We have to flip all triangles to enable correct backface culling.
            // For GL_TRIANGLES, we simply flip the vertices.
            // For GL_TRIANGLE_FANs, we leave the first vertex at its place and flip the
            // remaining vertices.
            // For GL_TRIANGLE_STRIPs, things are more complicated. When the number of
            // vertices is uneven, we simply flip the vertices. When the number of
            // vertices is even, we have to add an additional vertex before we flip the
            // vertices.
            vector<TextVectorGlyph::PolygonOutline::TypeIndex>::const_iterator tIt;
            UInt32 indexBegin = 0, indexEnd;
            for (tIt = outline.types.begin(); tIt != outline.types.end(); ++tIt)
            {
                typesPtr->push_back(tIt->first);
                indexEnd = tIt->second;
                OSG_ASSERT(indexEnd >= indexBegin);
                UInt32 len = indexEnd - indexBegin;
                UInt32 i = indexEnd;
                if (tIt->first == GL_TRIANGLE_FAN)
                {
                    i = indexBegin;
                    ++indexBegin;
                }
                if ((tIt->first == GL_TRIANGLE_STRIP) && ((len & 1) == 0))
                {
                    OSG_ASSERT((indexEnd >= 2) && (indexEnd - 2 >= indexBegin));
                    i = indexEnd - 2;
                    ++len;
                }
                if (i != indexEnd)
                {
                    // the interleaved multi-index blocks have the layout
                    // Position | Normal | TexCoord
                    OSG_ASSERT(i < outline.indices.size());
                    UInt32 index = outline.indices[i];
                    OSG_ASSERT(backCoordOffset + index < posPtr->size());
                    posIndicesPtr->push_back(backCoordOffset + index);
                    normalIndicesPtr->push_back(1);
                    OSG_ASSERT(texCoordOffset + index < texPtr->size());
                    texCoordIndicesPtr->push_back(texCoordOffset + index);
                    i = indexEnd;
                }
                lensPtr->push_back(len);
                while (true)
                {
                    if (i <= indexBegin)
                        break;
                    --i;

                    // the interleaved multi-index blocks have the layout
                    // Position | Normal | TexCoord
                    OSG_ASSERT(i < outline.indices.size());
                    UInt32 index = outline.indices[i];
                    OSG_ASSERT(backCoordOffset + index < posPtr->size());
                    posIndicesPtr->push_back(backCoordOffset + index);
                    normalIndicesPtr->push_back(1);
                    OSG_ASSERT(texCoordOffset + index < texPtr->size());
                    texCoordIndicesPtr->push_back(texCoordOffset + index);
                }
                indexBegin = indexEnd;
            }

            // Add the side faces to the geometry
            const TextVectorGlyph::Normals &normals = glyph.getNormals(level);

            // construct the multi index
            UInt32 start = 0, end, index = 0;
            vector<UInt32>::const_iterator iIt;
            vector<TextVectorGlyph::Orientation>::const_iterator oriIt = glyph.getContourOrientations().begin();
            for (iIt = outline.contours.begin(); iIt != outline.contours.end(); ++iIt, ++oriIt)
            {
                OSG_ASSERT(oriIt != glyph.getContourOrientations().end());
                UInt32 contourCoordOffset, contourBackCoordOffset;
                if (*oriIt == TextVectorGlyph::CCW)
                {
                    contourCoordOffset = coordOffset;
                    contourBackCoordOffset = backCoordOffset;
                }
                else
                {
                    contourCoordOffset = backCoordOffset;
                    contourBackCoordOffset = coordOffset;
                }

                end = *iIt;

                // the side faces are stored as quads
                GLenum mode = GL_QUAD_STRIP;
                UInt32 len = 0;

                UInt32 coordIndex, backCoordIndex;
                UInt32 normalOffset, startNormalOffset = normalsPtr->size();
                for (index = start; index < end; ++index)
                {
                    normalOffset = normalsPtr->size() - 1;
                    OSG_ASSERT(index < normals.size());
                    if (normals[index].edgeAngle > creaseAngle)
                    {
                        // We have an edge with two normals, so we need to
                        // add the vertices twice, but with different normals
                        // - but only when this is not the start index
                        if (index > start)
                        {
                            if ((mode == GL_QUAD_STRIP) && (len > 2))
                            {
                                typesPtr->push_back(GL_QUAD_STRIP);
                                OSG_ASSERT(((len + 2) & 1) == 0);
                                lensPtr->push_back(len + 2);
                                len = 0;
                                coordIndex = contourCoordOffset + index;
                                backCoordIndex = contourBackCoordOffset + index;
                            }
                            else
                            {
                                mode = GL_QUADS;
                                len += 2;
                                coordIndex = contourBackCoordOffset + index;
                                backCoordIndex = contourCoordOffset + index;
                            }

                            // back
                            OSG_ASSERT(backCoordIndex < posPtr->size());
                            posIndicesPtr->push_back(backCoordIndex);
                            OSG_ASSERT(normalOffset < normalsPtr->size());
                            normalIndicesPtr->push_back(normalOffset);
                            OSG_ASSERT(texCoordOffset + index < texPtr->size());
                            texCoordIndicesPtr->push_back(texCoordOffset + index);
                            // front
                            OSG_ASSERT(coordIndex < posPtr->size());
                            posIndicesPtr->push_back(coordIndex);
                            OSG_ASSERT(normalOffset < normalsPtr->size());
                            normalIndicesPtr->push_back(normalOffset);
                            OSG_ASSERT(texCoordOffset + index < texPtr->size());
                            texCoordIndicesPtr->push_back(texCoordOffset + index);
                        }

                        const Vec2f &normal = normals[index].nextEdgeNormal;
                        normalsPtr->push_back(Vec3f(normal.x(), normal.y(), 0.f));
                    }
                    else
                    {
                        if (mode == GL_QUADS)
                        {
                            typesPtr->push_back(GL_QUADS);
                            mode = GL_QUAD_STRIP;
                            OSG_ASSERT(len >= 6);
                            OSG_ASSERT(((len - 2) & 3) == 0);
                            lensPtr->push_back(len - 2);
                            len = 2;
                        }

                        const Vec2f &normal = normals[index].meanEdgeNormal;
                        normalsPtr->push_back(Vec3f(normal.x(), normal.y(), 0.f));
                    }
                    ++normalOffset;

                    // back
                    OSG_ASSERT(contourBackCoordOffset + index < posPtr->size());
                    posIndicesPtr->push_back(contourBackCoordOffset + index);
                    OSG_ASSERT(normalOffset < normalsPtr->size());
                    normalIndicesPtr->push_back(normalOffset);
                    OSG_ASSERT(texCoordOffset + index < texPtr->size());
                    texCoordIndicesPtr->push_back(texCoordOffset + index);
                    // front
                    OSG_ASSERT(contourCoordOffset + index < posPtr->size());
                    posIndicesPtr->push_back(contourCoordOffset + index);
                    OSG_ASSERT(normalOffset < normalsPtr->size());
                    normalIndicesPtr->push_back(normalOffset);
                    OSG_ASSERT(texCoordOffset + index < texPtr->size());
                    texCoordIndicesPtr->push_back(texCoordOffset + index);

                    len += 2;
                }

                // We have to close the strip, so add the start vertices again
                if (normals[start].edgeAngle <= creaseAngle)
                    normalOffset = startNormalOffset;
                if (mode == GL_QUAD_STRIP)
                {
                    coordIndex = contourCoordOffset + start;
                    backCoordIndex = contourBackCoordOffset + start;
                }
                else
                {
                    coordIndex = contourBackCoordOffset + start;
                    backCoordIndex = contourCoordOffset + start;
                }

                // back
                OSG_ASSERT(backCoordIndex < posPtr->size());
                posIndicesPtr->push_back(backCoordIndex);
                OSG_ASSERT(normalOffset < normalsPtr->size());
                normalIndicesPtr->push_back(normalOffset);
                OSG_ASSERT(texCoordOffset + start < texPtr->size());
                texCoordIndicesPtr->push_back(texCoordOffset + start);
                // front
                OSG_ASSERT(coordIndex < posPtr->size());
                posIndicesPtr->push_back(coordIndex);
                OSG_ASSERT(normalOffset < normalsPtr->size());
                normalIndicesPtr->push_back(normalOffset);
                OSG_ASSERT(texCoordOffset + start < texPtr->size());
                texCoordIndicesPtr->push_back(texCoordOffset + start);

                len += 2;

                // store the number of multi index blocks
                typesPtr->push_back(mode);
                OSG_ASSERT((mode != GL_QUADS) || ((len & 3) == 0));
                OSG_ASSERT((mode != GL_QUAD_STRIP) || ((len & 1) == 0));
                lensPtr->push_back(len);

                start = end;
            }
        }
    }
}