Question

I am trying to texture a quad, with a character, that is within the glyph texture (obtained with D3DXFont::GetGlyphData).

Most of the characters are drawn correctly.

However characters such as: 'F', and 'A' are being drawn upside down.

None of the glyphs when saved to file seem to be upside down.

#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;
}

Edit: Updated to include a full example of my problem.

Was it helpful?

Solution

It's been a while since I did any DirextX stuff, but I think it may be to do with the quad texture coordinate ordering. I ran your code and tried this:

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
    }
};

which output the characters ABCDEF all Ok. I can't exactly remember how to specify the custom vertex, so I guess I was probably lucky with the above hack :)

Had another look at this and I think the coords should be ordered to render the TRIANGLEFAN in Clockwise Winding Order (so it doesn't get backface culled). Reordering the coords makes more sense I think:

// 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
    },
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top