65.9K
CodeProject 正在变化。 阅读更多。
Home

如何使用 TrueType 结构渲染用户定义的几何形状

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.80/5 (5投票s)

2009年1月3日

CPOL

2分钟阅读

viewsIcon

81995

downloadIcon

483

学习 TrueType 结构、TTPOLYGONHEADER 和 TTPOLYCURVE 的用法。

引言

TrueType 结构 TTPOLYGONHEADER 可用于生成用户自定义的几何形状。本文档旨在演示如何使用此结构格式化 TrueType 字体。

如你所知,一个字形轮廓由多个曲线段组成,这些曲线段由 TTPOLYCURVE 结构表示,而这些结构紧随 TTPOLYGONHEADER 之后。因此,我们可以简单地将每个曲线段按顺序添加到多边形头部之后,而无需显式使用 TTPOLYCURVE 结构。

背景

最初的想法是研究 TTPOLYGONHEADERTTPOLYCURVE 在 TrueType 字体渲染中的使用方式。此外,我们可以思考如何将这些几何形状与 TrueType 字体字符结合起来。我们将在下一节中讨论这个高级主题。

TrueType 多边形结构

让我们看看 TTPOLYGONHEADERTTPOLYCURVE 结构的成员。

typedef struct _TTPOLYGONHEADER 
{ 
  DWORD   cb; 
  DWORD   dwType; 
  POINTFX pfxStart; 
} TTPOLYGONHEADER, *LPTTPOLYGONHEADER;
  • cb - 指定 TTPOLYGONHEADER 结构和 TTPOLYCURVE 结构或描述字符轮廓所需的结构所需的字节数。
  • dwType - 指定返回的字符轮廓的类型。当前,此值必须为 TT_POLYGON_TYPE
  • pfxStart - 指定字符轮廓中轮廓的起始点。
typedef struct tagTTPOLYCURVE 
{ 
  WORD    wType; 
  WORD    cpfx; 
  POINTFX apfx[1]; 
} TTPOLYCURVE, *LPTTPOLYCURVE;
  • wType - 指定结构描述的曲线类型。
  • cpfx - 指定数组中的 POINTFX 结构的个数。
  • apfx - 指定定义多边形或贝塞尔样条曲线的 POINTFX 结构数组。

入门

我们将只关注如何使用 TTPOLYGONHEADER 生成自定义几何形状。以下是一个代码片段,用于解释创建用户自定义几何形状的方法。

LPTTPOLYGONHEADER CTTPolygonDlg::DemoPolygon(const PPLOYCURVE pPolycurve, int nCurveCount)
{
    LPTTPOLYGONHEADER lpPolygonHeader = NULL;
    LPBYTE lpPolyCurve = NULL;
    LPPOINTFX lpPointsFx = NULL;
    LPPOINTFX lpPointsInc = NULL;
    LPPOINTFX lpPointsEnd = NULL;
    DWORD dwOffsetAddr = 0L;
    UINT nSize = 0;
    UINT nPtBufSize = 0;
    UINT nPtCounts = 0;
    WORD wType = 0;
    WORD cpfx = 0;
    LPBYTE lpBytes = NULL;
    int i = 0;
    double* pDblVertex = NULL;
    double* pDblInc = NULL;

    if (0 >= nCurveCount || NULL == pPolycurve)
    {
        return( NULL );
    }

    for (i = 0; i < nCurveCount; i++)
    {
        if (1 >= (*(pPolycurve + i)).nVertexCount || 
            NULL == (*(pPolycurve + i)).pDblValues)
        {
            return( NULL );
        }

        if ((*(pPolycurve + i)).wCurveType != TT_PRIM_LINE && 
            (*(pPolycurve + i)).wCurveType != TT_PRIM_QSPLINE && 
            (*(pPolycurve + i)).wCurveType != TT_PRIM_CSPLINE)
        {
            return( NULL );
        }

        nPtBufSize += (sizeof( POINTFX ) * (*(pPolycurve + i)).nVertexCount);
    }

    //--- allocate buffer for polygon header ---
    nSize = 
    (
    sizeof( TTPOLYGONHEADER ) + 
    sizeof( TTPOLYCURVE ) +
    ((sizeof( WORD ) * 2) + nPtBufSize)
    );

    lpBytes = ::new BYTE[nSize];
    lpPolygonHeader = (LPTTPOLYGONHEADER)lpBytes;

    //--- setup header of polygon and its starting point ---
    lpPolygonHeader->cb = nSize;
    lpPolygonHeader->dwType = TT_POLYGON_TYPE;
    pDblVertex = (*pPolycurve).pDblValues;
    lpPolygonHeader->pfxStart.x = FixedFromDouble(*pDblVertex);
    lpPolygonHeader->pfxStart.y = FixedFromDouble(*(pDblVertex + 1));

    //--- get poly curve start address ---
    dwOffsetAddr = (DWORD)((LPBYTE)lpPolygonHeader + sizeof( TTPOLYGONHEADER ));

    //--- traverse all polycurves ---
    for (i = 0; i < nCurveCount; i++)
    {
        wType = (*(pPolycurve + i)).wCurveType;
        cpfx = (*(pPolycurve + i)).nVertexCount;

        ::CopyMemory((LPBYTE)dwOffsetAddr, &wType, sizeof( WORD ));
        dwOffsetAddr += sizeof( WORD );
        ::CopyMemory((LPBYTE)dwOffsetAddr, &cpfx, sizeof( WORD ));
        dwOffsetAddr += sizeof( WORD );

        //--- allocate buffer for current curve ---
        nPtBufSize = (sizeof( POINTFX ) * (*(pPolycurve + i)).nVertexCount);

        lpBytes = ::new BYTE[nPtBufSize];
        lpPointsFx = (LPPOINTFX)lpBytes;

        lpPointsInc = lpPointsFx;
        lpPointsEnd = (lpPointsInc + cpfx);
        pDblInc = (*(pPolycurve + i)).pDblValues;

        do
        {
            lpPointsInc->x = FixedFromDouble(*pDblInc++);
            lpPointsInc->y = FixedFromDouble(*pDblInc++);
        }
        while(++lpPointsInc < lpPointsEnd);

        //--- copy points to original structure ---
        ::CopyMemory((LPBYTE)dwOffsetAddr, lpPointsFx, nPtBufSize);
        dwOffsetAddr += nPtBufSize;

        //--- free temporary points ---
        delete []lpBytes;
        lpBytes = NULL;
    }

    //--- return polygon header ---
    return( lpPolygonHeader );
}

以下是详细的解释

  1. 我们需要根据多边形有多少个顶点来为多边形结构指定大小。然后,为该结构分配空间。
  2. for (i = 0; i < nCurveCount; i++)
    {
        if (1 >= (*(pPolycurve + i)).nVertexCount || 
            NULL == (*(pPolycurve + i)).pDblValues)
        {
            return( NULL );
        }
    
        if ((*(pPolycurve + i)).wCurveType != TT_PRIM_LINE && 
            (*(pPolycurve + i)).wCurveType != TT_PRIM_QSPLINE && 
            (*(pPolycurve + i)).wCurveType != TT_PRIM_CSPLINE)
        {
            return( NULL );
        }
    
        nPtBufSize += (sizeof( POINTFX ) * (*(pPolycurve + i)).nVertexCount);
    }
    
    //--- allocate buffer for polygon header ---
    nSize = 
    (
    sizeof( TTPOLYGONHEADER ) + 
    sizeof( TTPOLYCURVE ) +
    ((sizeof( WORD ) * 2) + nPtBufSize)
    );
    
    lpBytes = ::new BYTE[nSize];
    lpPolygonHeader = (LPTTPOLYGONHEADER)lpBytes;
  3. 从多边形的第一个顶点开始,如下所示。
  4. //--- setup header of polygon and its starting point ---
    lpPolygonHeader->cb = nSize;
    lpPolygonHeader->dwType = TT_POLYGON_TYPE;
    pDblVertex = (*pPolycurve).pDblValues;
    lpPolygonHeader->pfxStart.x = FixedFromDouble(*pDblVertex);
    lpPolygonHeader->pfxStart.y = FixedFromDouble(*(pDblVertex + 1));
    
    //--- get poly curve start address ---
    dwOffsetAddr = (DWORD)((LPBYTE)lpPolygonHeader + sizeof( TTPOLYGONHEADER ));
  5. 为每条曲线提供顶点。定义 TTPOLYCURVE 结构
    1. 设置多边形类型。
    2. 为多边形提供顶点数。
    3. 为多边形提供顶点。
    //--- traverse all polycurves ---
    for (i = 0; i < nCurveCount; i++)
    {
        wType = (*(pPolycurve + i)).wCurveType;
        cpfx = (*(pPolycurve + i)).nVertexCount;
    
        ::CopyMemory((LPBYTE)dwOffsetAddr, &wType, sizeof( WORD ));
        dwOffsetAddr += sizeof( WORD );
        ::CopyMemory((LPBYTE)dwOffsetAddr, &cpfx, sizeof( WORD ));
        dwOffsetAddr += sizeof( WORD );
    
        //--- allocate buffer for current curve ---
        nPtBufSize = (sizeof( POINTFX ) * (*(pPolycurve + i)).nVertexCount);
    
        lpBytes = ::new BYTE[nPtBufSize];
        lpPointsFx = (LPPOINTFX)lpBytes;
    
        lpPointsInc = lpPointsFx;
        lpPointsEnd = (lpPointsInc + cpfx);
        pDblInc = (*(pPolycurve + i)).pDblValues;
    
        do
        {
            lpPointsInc->x = FixedFromDouble(*pDblInc++);
            lpPointsInc->y = FixedFromDouble(*pDblInc++);
        }
        while(++lpPointsInc < lpPointsEnd);
    
        //--- copy points to original structure ---
        ::CopyMemory((LPBYTE)dwOffsetAddr, lpPointsFx, nPtBufSize);
        dwOffsetAddr += nPtBufSize;
    
        //--- free temporary points ---
        delete []lpBytes;
        lpBytes = NULL;
    }
  6. 现在我们可以使用这个自定义的多边形头部渲染几何对象。
  7. //--- render geometry shape ---
    RenderPolygon(lpPolygonHeader, nSize);

修订

  • 版本 1.0:初始发布。
  • 版本 1.1:支持多种形状。
© . All rights reserved.