Edit

kc3-lang/ftgl/src/FTVectoriser.cpp

Branch :

  • Show log

    Commit

  • Author : henry
    Date : 2002-11-28 09:39:36
    Hash : cce53af5
    Message : Changed the gluTess callback function definitions

  • src/FTVectoriser.cpp
  • #include    "FTVectoriser.h"
    #include    "FTGL.h"
    
    
    #ifndef CALLBACK
    #define CALLBACK
    #endif
    
    
    void CALLBACK ftglError( GLenum errCode, FTMesh* mesh)
    {
        mesh->Error( errCode);
    }
    
    void CALLBACK ftglVertex( void* data, FTMesh* mesh)
    {
        FTGL_DOUBLE* vertex = (FTGL_DOUBLE*)data;
        mesh->AddPoint( vertex[0], vertex[1], vertex[2]);
    }
    
    
    void CALLBACK ftglBegin( GLenum type, FTMesh* mesh)
    {
        mesh->Begin( type);
    }
    
    
    void CALLBACK ftglEnd( FTMesh* mesh)
    {
        mesh->End();
    }
    
    
    void CALLBACK ftglCombine( FTGL_DOUBLE coords[3], void* vertex_data[4], GLfloat weight[4], void** outData, FTMesh* mesh)
    {
        FTGL_DOUBLE* vertex = (FTGL_DOUBLE*)coords;
        mesh->tempPool.push_back( FTPoint( vertex[0], vertex[1], vertex[2]));
        
        *outData = &mesh->tempPool[ mesh->tempPool.size() - 1].x;
    }
            
    
    FTMesh::FTMesh()
    :   err(0)
    {
        tess.reserve( 16);
        tempPool.reserve( 128);
    }
    
    
    FTMesh::~FTMesh()
    {
        for( size_t t = 0; t < tess.size(); ++t)
        {
            delete tess[t];
        }
        tess.clear();
    
        tempPool.clear();
    }
    
    
    void FTMesh::AddPoint( const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z)
    {
        tempTess->AddPoint( x, y, z);
    }
    
    void FTMesh::Begin( GLenum m)
    {
        tempTess = new FTTesselation;
        tempTess->meshType = m;
    }
    
    
    void FTMesh::End()
    {
        tess.push_back( tempTess);
    }
    
    
    FTGL_DOUBLE* FTMesh::Point()
    {
        return &tempTess->pointList[ tempTess->size() - 1].x;
    }
    
    
    int FTMesh::size() const
    {
        int s = 0;
        for( size_t t = 0; t < tess.size(); ++t)
        {
            s += tess[t]->size();
            ++s;
        }
        return s;
    }
    
    
    //=============================================================================
    
    
    FTVectoriser::FTVectoriser( const FT_Glyph glyph)
    :   contour(0),
        mesh(0),
        contourFlag(0),
        kBSTEPSIZE( 0.2f)
    {
        FT_OutlineGlyph outline = (FT_OutlineGlyph)glyph;
        ftOutline = outline->outline;
        
        contourList.reserve( ftOutline.n_contours);
    }
    
    
    FTVectoriser::~FTVectoriser()
    {
        for( size_t c = 0; c < contours(); ++c)
        {
            delete contourList[c];
        }
    
        contourList.clear();
        
        if( mesh)
            delete mesh;
    }
    
    
    int FTVectoriser::points()
    {
        int s = 0;
        for( size_t c = 0; c < contours(); ++c)
        {
            s += contourList[c]->size();
        }
        
        return s;
    }
    
    
    bool FTVectoriser::Process()
    {
        short first = 0;
        short last;
        const short cont = ftOutline.n_contours;
        
        for( short c = 0; c < cont; ++c)
        {
            contour = new FTContour;
            contourFlag = ftOutline.flags;
            last = ftOutline.contours[c];
    
            for( int p = first; p <= last; ++p)
            {
                switch( ftOutline.tags[p])
                {
                    case FT_Curve_Tag_Conic:
                        p += Conic( p, first, last);
                        break;
                    case FT_Curve_Tag_Cubic:
                        p += Cubic( p, first, last);
                        break;
                    case FT_Curve_Tag_On:
                    default:
                        contour->AddPoint( ftOutline.points[p].x, ftOutline.points[p].y);
                }
            }
            
            contourList.push_back( contour);
            first = last + 1;
        }
        
        return true;
    }
    
    
    int FTVectoriser::Conic( const int index, const int first, const int last)
    {
        int next = index + 1;
        int prev = index - 1;
        
        if( index == last)
        {
            next = first; 
        }
        
        if( index == first)
        {
            prev = last; 
        }
        
        if( ftOutline.tags[next] != FT_Curve_Tag_Conic)
        {
            ctrlPtArray[0][0] = ftOutline.points[prev].x;   ctrlPtArray[0][1] = ftOutline.points[prev].y;
            ctrlPtArray[1][0] = ftOutline.points[index].x;  ctrlPtArray[1][1] = ftOutline.points[index].y;
            ctrlPtArray[2][0] = ftOutline.points[next].x;   ctrlPtArray[2][1] = ftOutline.points[next].y;
            
            evaluateCurve( 2);
            return 1;
        }
        else
        {
            int next2 = next + 1;
            if( next == last)
                next2 = first;
            
            // create a phantom point
            float x = ( ftOutline.points[index].x + ftOutline.points[next].x) * 0.5f;
            float y = ( ftOutline.points[index].y + ftOutline.points[next].y) * 0.5f;
            
            // process first curve
            ctrlPtArray[0][0] = ftOutline.points[prev].x;   ctrlPtArray[0][1] = ftOutline.points[prev].y;
            ctrlPtArray[1][0] = ftOutline.points[index].x;  ctrlPtArray[1][1] = ftOutline.points[index].y;
            ctrlPtArray[2][0] = x;                          ctrlPtArray[2][1] = y;
            
            evaluateCurve( 2);
            
            // process second curve
            ctrlPtArray[0][0] = x;                          ctrlPtArray[0][1] = y;
            ctrlPtArray[1][0] = ftOutline.points[next].x;   ctrlPtArray[1][1] = ftOutline.points[next].y;
            ctrlPtArray[2][0] = ftOutline.points[next2].x;  ctrlPtArray[2][1] = ftOutline.points[next2].y;
            evaluateCurve( 2);
            
            return 2;
        }
    }
    
    
    int FTVectoriser::Cubic( const int index, const int first, const int last)
    {
        int next = index + 1;
        int prev = index - 1;
        
        if( index == last)
        {
            next = first; 
        }
        
        int next2 = next + 1;
        
        if( next == last)
        {
            next2 = first;
        }
        
        if( index == first)
        {
            prev = last; 
        }
        
        ctrlPtArray[0][0] = ftOutline.points[prev].x;       ctrlPtArray[0][1] = ftOutline.points[prev].y;
        ctrlPtArray[1][0] = ftOutline.points[index].x;      ctrlPtArray[1][1] = ftOutline.points[index].y;
        ctrlPtArray[2][0] = ftOutline.points[next].x;       ctrlPtArray[2][1] = ftOutline.points[next].y;
        ctrlPtArray[3][0] = ftOutline.points[next2].x;      ctrlPtArray[3][1] = ftOutline.points[next2].y;
    
        evaluateCurve( 3);
        return 2;
    }
    
    
    // De Casteljau algorithm contributed by Jed Soane
    void FTVectoriser::deCasteljau( const float t, const int n)
    {
        //Calculating successive b(i)'s using de Casteljau algorithm.
        for( int i = 1; i <= n; i++)
            for( int k = 0; k <= (n - i); k++)
            {
                bValues[i][k][0] = (1 - t) * bValues[i - 1][k][0] + t * bValues[i - 1][k + 1][0];
                bValues[i][k][1] = (1 - t) * bValues[i - 1][k][1] + t * bValues[i - 1][k + 1][1];
            }
            
        //Specify next vertex to be included on curve
        contour->AddPoint( bValues[n][0][0], bValues[n][0][1]);
    }
    
    
    // De Casteljau algorithm contributed by Jed Soane
    void FTVectoriser::evaluateCurve( const int n)
    {
        // setting the b(0) equal to the control points
        for( int i = 0; i <= n; i++)
        {
            bValues[0][i][0] = ctrlPtArray[i][0];
            bValues[0][i][1] = ctrlPtArray[i][1];
        }
    
        float t; //parameter for curve point calc. [0.0, 1.0]
    
        for( int m = 0; m <= ( 1 / kBSTEPSIZE); m++)
        {
            t = m * kBSTEPSIZE;
            deCasteljau( t, n);  //calls to evaluate point on curve att.
        }
    }
    
    
    void FTVectoriser::GetOutline( FTGL_DOUBLE* data)
    {
        int i = 0;
        
        for( size_t c= 0; c < contours(); ++c)
        {
            const FTContour* contour = contourList[c];
            
            for( size_t p = 0; p < contour->size(); ++p)
            {
                data[i] = static_cast<FTGL_DOUBLE>(contour->pointList[p].x / 64.0f); // is 64 correct?
                data[i + 1] = static_cast<FTGL_DOUBLE>(contour->pointList[p].y / 64.0f);
                data[i + 2] = 0.0f; // static_cast<FTGL_DOUBLE>(contour->pointList[p].z / 64.0f);
                i += 3;
            }
        }
    }
    
    
    void FTVectoriser::MakeMesh( FTGL_DOUBLE zNormal)
    {
        if( mesh)
        {
            delete mesh;
        }
            
        mesh = new FTMesh;
        
        GLUtesselator* tobj = gluNewTess();
        
        typedef GLvoid (*GLUTesselatorFunction)(...);
        
        gluTessCallback( tobj, GLU_TESS_BEGIN_DATA,     (GLUTesselatorFunction)ftglBegin);
        gluTessCallback( tobj, GLU_TESS_VERTEX_DATA,    (GLUTesselatorFunction)ftglVertex);
        gluTessCallback( tobj, GLU_TESS_COMBINE_DATA,   (GLUTesselatorFunction)ftglCombine);
        gluTessCallback( tobj, GLU_TESS_END_DATA,       (GLUTesselatorFunction)ftglEnd);
        gluTessCallback( tobj, GLU_TESS_ERROR_DATA,     (GLUTesselatorFunction)ftglError);
        
        if( contourFlag & ft_outline_even_odd_fill) // ft_outline_reverse_fill
        {
            gluTessProperty( tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
        }
        else
        {
            gluTessProperty( tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
        }
        
        
        gluTessProperty( tobj, GLU_TESS_TOLERANCE, 0);
        gluTessNormal( tobj, 0.0f, 0.0f, zNormal);
        gluTessBeginPolygon( tobj, mesh);
        
            for( size_t c = 0; c < contours(); ++c)
            {
                const FTContour* contour = contourList[c];
    
                gluTessBeginContour( tobj);
                
                    for( size_t p = 0; p < contour->size(); ++p)
                    {
                        FTGL_DOUBLE* d = const_cast<FTGL_DOUBLE*>(&contour->pointList[p].x);
                        gluTessVertex( tobj, d, d);
                    }
    
                gluTessEndContour( tobj);
            }
            
        gluTessEndPolygon( tobj);
    
        gluDeleteTess( tobj);
    }
    
    
    void FTVectoriser::GetMesh( FTGL_DOUBLE* data)
    {
        int i = 0;
        
        // fill out the header
        size_t msize = mesh->tess.size();
        data[0] = msize;
        
        for( int p = 0; p < data[0]; ++p)
        {
            FTTesselation* tess = mesh->tess[p];
            size_t tSize =  tess->pointList.size();
            int tType =  tess->meshType;
            
            data[i+1] = tType;
            data[i+2] = tSize;
            i += 3;
            for( size_t q = 0; q < ( tess->pointList.size()); ++q)
            {
                data[i] = tess->pointList[q].x / 64.0f; // is 64 correct?
                data[i + 1] = tess->pointList[q].y / 64.0f;
                data[i + 2] = 0.0f; // static_cast<FTGL_DOUBLE>(mesh->pointList[p].z / 64.0f);
                i += 3;
            }
        }
    }