绘制字体纹理(字符颠倒)

时间:2014-02-19 17:18:00

标签: c++ fonts directx directx-9

我正在尝试使用字符构造四边形,这个字符在字形纹理内(使用D3DXFont :: GetGlyphData获得)。

大部分字符都是正确绘制的。

然而,诸如“F”和“A”之类的字符被颠倒了。

保存到文件时,没有任何字形似乎是颠倒的。

#include <Windows.h>
#include <d3d9.h>
#include <d3dx9.h>

// global declarations
LPDIRECT3D9 d3d;    // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev;    // the pointer to the device class

ID3DXSprite* pSprite;
ID3DXFont* pFont;

void drawCharacter(const char c, int screenX, int screenY, D3DCOLOR color)
{
    struct CUSTOMVERTEX
    {
        float x, y, z, rhw, tu, tv;
    };

    WORD glyphIndex;
    IDirect3DTexture9* texture;
    RECT rect;
    POINT point;
    D3DSURFACE_DESC desc;

    if(GetGlyphIndices(pFont->GetDC(), &c, 1, &glyphIndex, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR)
        return;

    if(pFont->GetGlyphData(glyphIndex, &texture, &rect, &point) != S_OK)
        return;

    if(texture->GetLevelDesc(0, &desc) != D3D_OK)
        return;

    const float glyphWidth = static_cast<float>(desc.Width);
    const float glyphHeight = static_cast<float>(desc.Height);

    const float charWidth = static_cast<float>(rect.right - rect.left);
    const float charHeight = static_cast<float>(rect.bottom - rect.top);

    const float startX = static_cast<float>(screenY);
    const float startY = static_cast<float>(screenY);

    float u = (static_cast<float>(rect.left) + 0.5f) / glyphWidth;
    float v = (static_cast<float>(rect.top) + 0.5f) / glyphHeight;

    float u2 = u + (charWidth / glyphWidth);
    float v2 = v + (charHeight / glyphHeight);

const CUSTOMVERTEX char_quad[4] =
{
    // Bottom left vertex 
    {
        startX, startY, 0.0f, 1.0f, 
        u, v2
    }, 

    // Bottom right vertex
    {
        startX + charWidth, startY, 0.0f, 1.0f, 
        u2, v2
    }, 

    // Top right vertex
    {
        startX + charWidth, startY + charHeight, 0.0f, 1.0f, 
        u2, v
    },  

    // Top left vertex 
    {
        startX, startY + charHeight, 0.0f, 1.0f, 
        u, v
    }
};

    // D3DXSaveTextureToFileA("glyph.dds", D3DXIFF_DDS, texture, 0);

    d3ddev->SetTexture(0, texture);
    d3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, char_quad, sizeof(CUSTOMVERTEX));
}

// this is the function used to render a single frame
void render_frame()
{
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

    d3ddev->BeginScene();
    pSprite->Begin(D3DXSPRITE_ALPHABLEND);

    // select which vertex format we are using
    d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);

    drawCharacter('F', 100, 100, D3DCOLOR_XRGB(0, 255, 0));

    pSprite->End();
    d3ddev->EndScene();
    d3ddev->Present(NULL, NULL, NULL, NULL);
}

// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
{
    HWND hWnd;
    WNDCLASSEX wc = {};

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = DefWindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszClassName = "WindowClass";

    if(!RegisterClassEx(&wc))
    {
        return 0;
    }

    hWnd = CreateWindowEx(NULL,
        "WindowClass",
        "Our Direct3D Program",
        WS_OVERLAPPEDWINDOW,
        0, 0,
        800, 600,
        NULL,
        NULL,
        hInstance,
        NULL);

    if(!hWnd)
    {
        UnregisterClass(wc.lpszClassName, hInstance);
        return 0;
    }

    ShowWindow(hWnd, nCmdShow);

    // set up and initialize Direct3D
    d3d = Direct3DCreate9(D3D_SDK_VERSION);

    if(!d3d)
    {
        UnregisterClass(wc.lpszClassName, hInstance);
        return 0;
    }

    D3DPRESENT_PARAMETERS d3dpp = {};
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow = hWnd;
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dpp.BackBufferWidth = 800;
    d3dpp.BackBufferHeight = 600;

    // create a device class using this information and the info from the d3dpp stuct
    if(d3d->CreateDevice(D3DADAPTER_DEFAULT,
        D3DDEVTYPE_HAL,
        hWnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
        &d3dpp,
        &d3ddev) != D3D_OK)
    {
        d3d->Release();
        UnregisterClass(wc.lpszClassName, hInstance);
        return 0;
    }

    if(D3DXCreateSprite(d3ddev, &pSprite) != D3D_OK)
    {
        d3d->Release();
        d3ddev->Release();
        UnregisterClass(wc.lpszClassName, hInstance);
        return 0;
    }

    if(D3D_OK != D3DXCreateFont(d3ddev, 
            14, 
            0, 
            FW_BOLD, 
            1, 
            FALSE, 
            DEFAULT_CHARSET, 
            OUT_DEFAULT_PRECIS, 
            ANTIALIASED_QUALITY, 
            DEFAULT_PITCH | FF_DONTCARE, 
            "Georgia", 
            &pFont))
    {
        d3d->Release();
        d3ddev->Release();
        pSprite->Release();
        UnregisterClass(wc.lpszClassName, hInstance);
        return 0;
    }

    MSG msg;
    while(TRUE)
    {
        while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        if(msg.message == WM_QUIT)
            break;

        render_frame();
    }

    d3d->Release();
    d3ddev->Release();
    pSprite->Release();
    pFont->Release();
    UnregisterClass(wc.lpszClassName, hInstance);
    return msg.wParam;
}

修改:已更新,以包含我的问题的完整示例。

1 个答案:

答案 0 :(得分:0)

我做了任何DirextX的事情已经有一段时间了,但我认为这可能与四维纹理坐标排序有关。我运行了你的代码并尝试了这个:

const CUSTOMVERTEX char_quad[4] =
{
    // Top left vertex 
    {
        startX, startY + charHeight, 0.0f, 1.0f, 
        u, v2
    },
    // Top right vertex
    {
        startX + charWidth, startY + charHeight, 0.0f, 1.0f, 
        u2, v2
    },  
    // Bottom right vertex
    {
        startX + charWidth, startY, 0.0f, 1.0f, 
        u2, v
    },
    // Bottom left vertex 
    {
        startX, startY, 0.0f, 1.0f, 
        u, v
    }
};
输出字符ABCDEF的

都好。 我不能完全记住如何指定自定义顶点,所以我猜我可能幸运的是上面的黑客:)

再看看这个,我认为应该命令坐标以顺时针绕组顺序渲染三角形(因此它不会被剔除)。重新排序坐标更有意义我想:

// TRIANGLEFAN coords:
//    v1-----v2  clockwise winding order
//    |    / |
//    |  /   | 
//    v0-----v3
//
const CUSTOMVERTEX char_quad[4] =
{
    // Bottom left vertex 
    {
        startX, startY, 0.0f, 1.0f, 
        u, v
    },
    // Top left vertex 
    {
        startX, startY + charHeight, 0.0f, 1.0f, 
        u, v2
    },
    // Top right vertex
    {
        startX + charWidth, startY + charHeight, 0.0f, 1.0f, 
        u2, v2
    },  
    // Bottom right vertex
    {
        startX + charWidth, startY, 0.0f, 1.0f, 
        u2, v
    },
};