[DX9] Displaying font loaded by FreeType

Started by
16 comments, last by datboi 5 years, 2 months ago

Hello everyone. I have been trying to make a font renderer that uses freetype for the past couple of days but am currently stuck with getting uv tex values when rendering.

Here is the current code I use


struct SVertex
{
	SVector4f        pos;
    Color32           col;
    SVector2f        tex;
};
// D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1
float CDisplayFont::DrawTextA( const char * szText, int textCount, const SVector2f& pos, const SColor & color, const SRectf * pClipRect )
{
    SVector2f tmp = ( pos );
	IRender * pRender = g_pCore->GetGraphics()->GetRender();
    
    for ( int i = 0; i < textCount; ++i )
    {
        Codepoint_t cp = static_cast< Codepoint_t >( szText[ i ] );
        if ( GlyphInfo_t * info = GetGlyphInfo( cp ) )
        {
            if ( szText[ i ] != ' ' )
            {
                float sx = tmp.x + info->offsetX * m_fScaleHoriz;
                float sy = tmp.y - ( info->height - info->offsetY ) * m_fScaleVert;
                float w = info->width * m_fScaleHoriz;
                float h = info->height * m_fScaleVert;
                                    
                // column (u) and row (v) number
                // -- heres where i'm stuck
                float u = 0;
                float v = 0;
	            SVertex vtx[ ] =
                {
                    { sx,     sy + h, 0.0f, 1.f, color, u, v },
                    { sx,     sy,     0.0f, 1.f, color, u, v },
                    { sx + w, sy + h, 0.0f, 1.f, color, u, v },
                    { sx + w, sy,     0.0f, 1.f, color, u, v },
                    { sx + w, sy + h, 0.0f, 1.f, color, u, v },
                    { sx,     sy,     0.0f, 1.f, color, u, v }
                };
	            //   arguments ->    ( rl, vtx data, vtx count, topology, texture (IDirect3DTexture9) )
                pRender->PushVertices( NULL, vtx, 6, D3DPT_TRIANGLELIST, info->texture->GetInternalPtr() );    
            }    
            tmp.x += ( float )( info->advance >> 6 ) * m_fScaleHoriz;        
        }
    }
    
    return tmp.x;
}

This obviously prints nothing because I am stuck on how exactly I should be getting the correct u & v coords.

I have confirmed that I am getting the correct texture by saving the IDirect3DTexture9 to a file, getting stuff like this - https://imgur.com/a/Lwl2Xws

I appreciate any advice/pointers in the right direction, thank you.

Advertisement

I’m just wondering why you’re using DirectX 9?  I don’t mean that as a criticism, because it’s your business what API you use.  If you can run your code on DirectX 10 or higher, you have the option of using DirectWrite.  It’s fast, easy to get a handle on and frees you up from having to worry about styles, formatting and so on.

In the event that it’s not fast enough for your needs, you can use it to render your glyphs to an offscreen surface and you can then copy characters from that surface at your leisure, but with DirectWrite providing hints about the individual character bounds.

First off, I'm with @ROGRat, unless you have a very good reason for using DX9 I would switch to at least DX10 as you're gaining no real useful knowledge at this point as DX9 is something like 15+ years old.

As for your question, this is OpenGL code but what you want is identical: https://learnopengl.com/In-Practice/Text-Rendering

Look for the function: void RenderText(Shader &s, std::string text, GLfloat x, GLfloat y, GLfloat scale, glm::vec3 color) and you'll see the UV coordinates you'll want to use.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

5 hours ago, CrazyCdn said:

~snip~

 

 

7 hours ago, ROGRat said:

~snip~

Hey, appreciate both of your feedback. Actually my goal is to allow cross platform rendering and I'm currently working on DX9 but eventually will work on DX11 and possibly OpenGL. But for now I'd like to figure this out on DX9.

@CrazyCdn Actually I have saw that code and tried the uv coordinates used there. It resulted in nothing being drawn so I'm not sure how to properly get them or maybe I'm just doing something wrong.

Thanks.

 

40 minutes ago, datboi said:

Hey, appreciate both of your feedback. Actually my goal is to allow cross platform rendering and I'm currently working on DX9 but eventually will work on DX11 and possibly OpenGL. But for now I'd like to figure this out on DX9.

Well then Direct X is not the right choice.  Vulkan would be far more cross platform and supporting Direct X 9 is absolutely pointless.  Nothing of value from DX9 will transfer to any modern API, honestly.

42 minutes ago, datboi said:

@CrazyCdn Actually I have saw that code and tried the uv coordinates used there. It resulted in nothing being drawn so I'm not sure how to properly get them or maybe I'm just doing something wrong.

Go over the whole tutorial then.  Should not be difficult at all to go from OpenGL to Direct X if you absolutely must support a 14+ (just checked, first released 2004) year old dead API.  The code worked for me about a year ago so I know it's functionally correct.  Maybe see where yours and theirs differs.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

2 hours ago, CrazyCdn said:

Well then Direct X is not the right choice.  Vulkan would be far more cross platform and supporting Direct X 9 is absolutely pointless.  Nothing of value from DX9 will transfer to any modern API, honestly.

Go over the whole tutorial then.  Should not be difficult at all to go from OpenGL to Direct X if you absolutely must support a 14+ (just checked, first released 2004) year old dead API.  The code worked for me about a year ago so I know it's functionally correct.  Maybe see where yours and theirs differs.

That is not what I meant by cross platform, sorry for the confusion. The ultimate goal for me is to have a renderer that will work for DX9, DX11, and more in the future hopefully. Why? Well I'm making a GUI specifically and one of the things I'd like to do is make an overlay for games and such (A lot of games still use DX9). If I was making my own program/app (which I also plan on doing), I definitely wouldn't be using DX9, like you said, it is a pretty dead API.. That would be a time where I'd choose one of the other APIs I have support for.

But, I've been looking into CD3DFont and the values supplied in the U, V are not always defined as 0.0 or 1.0.

Those uv coordinates are calculated here for example


mTexCoords[c-32][0] = ((float)(x + 0 - mSpacing))/mTexWidth;					
mTexCoords[c-32][1] = ((float)(y + 0 + 0 ))/mTexHeight;					
mTexCoords[c-32][2] = ((float)(x + size.cx + mSpacing))/mTexWidth;					
mTexCoords[c-32][3] = ((float)(y + size.cy+ 0))/mTexHeight

I guess I'll just try to replicate what CD3DFont does with GDI but using FreeType.

@datboi By overlay you mean something like Overwolf?

10 hours ago, ROGRat said:

@datboi By overlay you mean something like Overwolf?

Yeah I guess that is a good comparison. Just doing this mostly for the learning experience and I am actually very interested in general on how high quality/fast rendering works in general.

Well that explains that then :)  Never bad to learn and yes a lot of games still work that use D3D9.  Yeah, if I recall correctly it's only 0.0 and 1.0 because each letter is rendered individually in that example I gave you.  I think I ended up making a texture atlas which had individual UV coordinates, sorry if I find it I will put the code up here.  

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

datboi

That ogl text rendering definitely can be moded for directx. The thing to bear in mind is that the 2D transform is different for dx and gl. 

I've noticed in yr code that yr UV is always (0, 0). In yr case it should be:

1,0

0,0

1,1

0,1

1,1

0,0

Also i have not seen yr index buffer but again in yr case it should be: 0, 1, 2, 3, 2, 1

So check those.

To check if yr output is right. Things u can try:

- just try to draw 1 glyph only. That 1 quad. So put a "break;" in yr for loop for now

- force sx = 50; for example and sy = 100;

- turn off alpha blending so when the quad gets rendered it is fully visible

- turn off cull mode

- make sure winding order is set for clockwise

- in the pixel shader just do something like  "return float4(1,1,1,1);" so u force a white colour out

These tips are how u can get yr freetype glyph rendering investigated/fixed and then improved on

This topic is closed to new replies.

Advertisement