I have some code laying around which I downloaded from the internet long long ago, and I wanted to play with it.
So I extracted the interesting parts, created a proxy d3d9.dll and hooked up to a game.
Now I have a question because I cannot find the difference in the drawing between these two code pieces which determine if the vertice must be drawn on the screen or in the game scene
(I mean, like - a HUD is on screen and you always see it, and a vehicle is in the game scene, when you turn around you don't see it).
The first piece is the code I want to edit, I want to make it to display text in the game scene, not on the screen as static text.
The code which is used in the DLL is this:
float m_fTexCoords[224][4];
float CD3DFont::DrawLength ( const char *szText ) const
{
float len = 0.0f;
float sub = ( m_dwCreateFlags & FCR_BORDER ) ? 2.0f : 0.0f;
for ( const char *p = szText; *p; p++ )
{
int c = *(unsigned char *)p - 32;
if ( c >= 0 && c < 224 )
len += ( (m_fTexCoords[c][2] - m_fTexCoords[c][0]) * m_texWidth - sub ) - m_chrSpacing * 2;
}
return len;
}
HRESULT CD3DFont::Print ( float x, float y, DWORD color, const char *szText)
{
if ( !m_isReady )
return E_FAIL;
float strWidth = DrawLength( szText );
x -= (float)m_chrSpacing;
if ( FAILED(this->BeginRender()) )
return E_FAIL;
DWORD fvf;
m_pD3Ddev->GetFVF( &fvf );
m_pD3Ddev->SetFVF( D3DFVF_BITMAPFONT );
m_pD3Ddev->SetTexture( 0, m_pD3Dtex );
m_pD3Ddev->SetStreamSource( 0, m_pD3Dbuf, 0, sizeof(d3dvertex_s) );
while ( *szText )
{
UINT usedTriangles = 0;
d3dvertex_s *pVertex;
if ( FAILED(m_pD3Dbuf->Lock(0, 0, (void **) &pVertex, D3DLOCK_DISCARD)) )
{
m_pD3Ddev->SetFVF( fvf );
this->EndRender();
return E_FAIL;
}
for ( ; *szText; szText++ )
{
int c = *(unsigned char *)szText - 32;
if ( !(c >= 0 && c < 224) )
continue;
float tx1 = m_fTexCoords[c][0];
float tx2 = m_fTexCoords[c][2];
float ty1 = m_fTexCoords[c][1];
float ty2 = m_fTexCoords[c][3];
float w = ( tx2 - tx1 ) * m_texWidth;
float h = ( ty2 - ty1 ) * m_texHeight;
*pVertex++ = Init2DVertex( x - 0.5f, y - 0.5f, color, tx1, ty1 ); //topleft
*pVertex++ = Init2DVertex( x + w - 0.5f, y - 0.5f, color, tx2, ty1 ); //topright
*pVertex++ = Init2DVertex( x - 0.5f, y + h - 0.5f, color, tx1, ty2 ); //bottomleft
*pVertex++ = Init2DVertex( x + w - 0.5f, y - 0.5f, color, tx2, ty1 ); //topright
*pVertex++ = Init2DVertex( x + w - 0.5f, y + h - 0.5f, color, tx2, ty2 ); //bottomright
*pVertex++ = Init2DVertex( x - 0.5f, y + h - 0.5f, color, tx1, ty2 ); //bottomleft
if ( m_dwCreateFlags & FCR_BORDER )
w -= 2.0f;
x += w - ( m_chrSpacing * 2 );
usedTriangles += 2;
if ( usedTriangles >= m_maxTriangles )
break;
}
if ( usedTriangles > 0 )
{
m_pD3Dbuf->Unlock();
m_pD3Ddev->DrawPrimitive( D3DPT_TRIANGLELIST, 0, usedTriangles );
}
}
m_pD3Ddev->SetFVF( fvf );
this->EndRender();
return S_OK;
}
Then I saw a function named "DrawLine", so I decided to check it out and see what it does, and it draws a line in the game world, not a static line on the screen, so when I turn around and don't see the specific positions - I won't see the line:
bool CD3DRender::DrawLine ( const D3DXVECTOR3 &a, const D3DXVECTOR3 &b, DWORD dwColor )
{
if ( FAILED(CD3DBaseRender::BeginRender()) )
return false;
////////////////////////////////////////////////////
// Make sure we have a valid vertex buffer.
if ( m_pD3Dbuf == NULL )
{
return false;
}
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPING, false );
m_pD3Ddev->SetRenderState ( D3DRS_ZENABLE, false );
//m_pD3Ddev->SetRenderState ( D3DRS_LIGHTING, false );
D3DLVERTEX lineList[2];
//////////////////////////////////////////////////
// Lock the vertex buffer and copy in the verts.
m_pD3Dbuf->Lock( 0, 0, (void **) &lineList, D3DLOCK_DISCARD | D3DLOCK_NOSYSLOCK ); // flogs: D3DLOCK_NOSYSLOCK, D3DLOCK_DISCARD
{
lineList[0].x = a.x;
lineList[0].y = a.y;
lineList[0].z = a.z;
lineList[0].color = dwColor;
lineList[0].specular = dwColor;
lineList[1].x = b.x;
lineList[1].y = b.y;
lineList[1].z = b.z;
lineList[1].color = dwColor;
lineList[1].specular = dwColor;
}
m_pD3Dbuf->Unlock();
// store FVF to restore original at the end of this function
DWORD fvf;
m_pD3Ddev->GetFVF( &fvf );
m_pD3Ddev->SetFVF( D3DFVF_LVERTEX );
//m_pD3Ddev->SetFVF( D3DFVF_PRIMITIVES );
////////////////////////////////////////////////////
// Draw!
m_pD3Ddev->DrawPrimitiveUP( D3DPT_LINESTRIP, 1, lineList, sizeof(lineList) / 2 );
// reset states
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
m_pD3Ddev->SetRenderState ( D3DRS_ZENABLE, true );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPING, true );
// restore FVF
m_pD3Ddev->SetFVF( fvf );
CD3DBaseRender::EndRender();
return true;
}
Now the question is: where is the difference? Where does this code tell:
"Hey draw the text on the player screen and let it stay there"?
and
"Hey draw this in the game world, draw only the piece the player can see"?
Can anyone point me in the right direction? Or maybe how to edit the Print function to show the text in the game world?
thanks in advance.
concise example of what I want to achieve:
What Print now does (green box) and what I want it to do (red box)
(screens taken from another game where such "3d texts" exists but the program is closed source):
You can see the position of the text in the red box has changed on-screen but not in-game. I want to do that too. (you can see the red and blue #'s too)
The DrawLine code already creates the line in the game, but it's only a line, not text, so how does it finally happen that the other is and the other no?
I can only guess what the rest of your code does. It seems that the Print
method is called in an environment where the transform matrices have been set to form an orthographic view while the DrawLine
method uses the game's matrices.
However, you don't want to draw text in the scene. This would result in a misalignment and wrong scaling of the text. What you acutally want to do is getting the position on the screen where a scene position would be and draw the text there. You can use the D3DXVec3Project function for that. Be sure to provide the correct transform matrices. Not the updated ones for 2D-rendering.