Sign in to follow this  
Chett2001

applying text to a mesh/texture

Recommended Posts

Chett2001    126
Basically what im trying to do is create a book, i have created a simple page which ive animated to flip over when a key is pressed. Because each page will have different text on it i need a way to apply the text onto the page so when the book turns the text turns with it, the only way i have done text before is using RECT's as place holders so im pretty stumped how i can achieve this without creating a texture with the text on it. I dont want to do that because its not inline with the spec of the application i have to make (unless its done exclusively in DirectX at run time). Anyone got any suggestions for better ways of achieving this effect? The page (a flat rectangle) was created in 3dsmax and the page flip 'animation' is simply a rotation on the Y axis of 180 degrees.

Share this post


Link to post
Share on other sites
StratBoy61    232
Hey Chett2001,

I am not sure I understand : Why do you want not to use a Direct3D texture for that ? Could you please elaborate ?
Do you know that you can create a Direct3D texture in memory and write whatever you want on it, at runtime ? If you did not, the following code shows how to do that.
void my_function_that_writes_text_on_a_texture_in_memory()
{
D3DSURFACE_DESC ddsd;
if (FAILED(D3DXCreateTexture(m_pD3DDevice, iTextureWidth, iTextureHeight, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pMyTexture)) )
{
return FALSE;
}

if (FAILED(m_pTitleTexture->GetLevelDesc( 0, &ddsd ) ) )
{
return FALSE;
}

D3DFORMAT g_TextureFormat = ddsd.Format;
if (g_TextureFormat != D3DFMT_A8R8G8B8 && g_TextureFormat != D3DFMT_A1R5G5B5) {
return FALSE;
}

BYTE* ptPixels;
HDC memDC = CreateCompatibleDC(NULL);

HBITMAP hSomeBitmap = InitGenericBitmap(m_iMaxTitleWidth, m_iMaxTitleHeight, memDC, &ptPixels);
HBITMAP OldResBitmap = (HBITMAP)SelectObject(memDC, hSomeBitmap);
// prepare the bitmap for transparency...
HBRUSH myTransparentColorBrush = CreateSolidBrush(D3DCOLOR_RGBA(129, 87, 112, 30)); // for test purpose
HBRUSH theOldBrush = (HBRUSH)SelectObject(memDC, myTransparentColorBrush);

PatBlt(memDC, 0, 0, m_iMaxTitleWidth, m_iMaxTitleHeight, PATCOPY);
SelectObject(memDC, theOldBrush);
DeleteObject(myTransparentColorBrush);

int oldbkmode = SetBkMode(memDC, TRANSPARENT);
COLORREF textcolor = RGB(255, 255, 255);
COLORREF oldtextcolor = SetTextColor(memDC, textcolor);

LOGFONT lfFont;
SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lfFont, 0);
HFONT hFontNew = CreateFontIndirect(&lfFont);
HFONT hFontOld = (HFONT) SelectObject(memDC, hFontNew);

RECT myRect;
myRect.right = m_iMaxTitleWidth-1; // Mmm... I have an example on my desktop of an icon that can be displayed
// on one single line, and however, it appears on two lines... that's why I am reducing the rectangle here.
myRect.left = 0;
myRect.bottom = m_iMaxTitleHeight-1; // same for the height, even though I have not experienced it
myRect.top = 0;

char Msg[255];
strcpy(Msg, "Hello brave new world...");
DrawText(memDC, Msg, strlen(Msg), &myRect, DT_WORDBREAK | DT_CENTER | DT_NOPREFIX | DT_END_ELLIPSIS);

// Clean up.
SetTextColor(memDC, oldtextcolor);
SetBkMode(memDC, oldbkmode);

SelectObject(memDC, hFontOld);
DeleteObject(hFontNew);
SelectObject(memDC, OldResBitmap);
DeleteDC(memDC);

addBitmapToTitleTexture(hSomeBitmap); // see next function below
DeleteObject(hSomeBitmap);
}

void addBitmapToTitleTexture(HBITMAP theBitmap)
{
BYTE* ptPixels;
BITMAP bm;
GetObject(theBitmap, sizeof(bm), &bm);

HDC DirectDC = CreateCompatibleDC(NULL); // DC for working

HBITMAP DirectBitmap = InitGenericBitmap(bm.bmWidth, bm.bmHeight, DirectDC, &ptPixels);
if (DirectBitmap)
{
HDC BufferDC = CreateCompatibleDC(NULL);

SelectObject(BufferDC, theBitmap);
HGDIOBJ PreviousObject=SelectObject(DirectDC, DirectBitmap);
// we use StretchBlt as a trick to mirror the bitmap. As a matter of fact, copying to the DirectX texture mirrors the result
BOOL bRes = StretchBlt(DirectDC, 0, bm.bmHeight-1, bm.bmWidth, -bm.bmHeight, BufferDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);

SelectObject(DirectDC, PreviousObject);

BYTE* clrPixels = ptPixels;
D3DLOCKED_RECT d3dlr;
m_pTitleTexture->LockRect( 0, &d3dlr, 0, 0 );

LONG lTexturePitch = d3dlr.Pitch;
LONG lSamplePitch = 4*bm.bmWidth;

// Get the texture buffer & pitch
BYTE *pTextureBuffer = static_cast<byte *>(d3dlr.pBits) + lSamplePitch+bm.bmHeight;
for(LONG row = 0; row < bm.bmHeight; row++ )
{
BYTE *pBmpBufferOld = clrPixels;
BYTE *pTxtBufferOld = pTextureBuffer;

for (LONG col = 0; col < bm.bmWidth; col++)
{
pTextureBuffer[0] = clrPixels[0];
pTextureBuffer[1] = clrPixels[1];
pTextureBuffer[2] = clrPixels[2];
{
// condition for alpha blending/testing
if (clrPixels[0] == my_r && clrPixels[1] == my_g && clrPixels[2] == my_b)
pTextureBuffer[3] = 0x00;
else
pTextureBuffer[3] = 0xFF;
}

pTextureBuffer += 4;
clrPixels += 4;
}

clrPixels = pBmpBufferOld + lSamplePitch;
pTextureBuffer = pTxtBufferOld + lTexturePitch;
}
m_pTitleTexture->UnlockRect(0);
DeleteDC(BufferDC);
}
DeleteDC(DirectDC);
DeleteObject(DirectBitmap);
}

Cheers
StratBoy61

Share this post


Link to post
Share on other sites
remigius    1172
I think the easiest way to do this would be to use a render-to-texture pass to generate the page texture at runtime. This way you can still use the text rendering like you're used to and because you only need to generate the texture once, this approach should get the job done with a minimum of overhead.

Edit - Bah, too late [smile] StratBoy61's solution should also work just fine.

Share this post


Link to post
Share on other sites
Chett2001    126
MMm im finding that code kinda confusing im pretty new to DirectX and C++, do you have a full example? I replaced m_pMyTexture with the name of my bitmaps texture but ive got errors such as InitGenericBitmap': identifier not found, do i need to define it somewhere? I defined some UINT's for the sizes of the texture look right?:

UINT iTextureWidth = 1024;
UINT iTextureHeight = 1024;
UINT m_iMaxTitleWidth = 1000;
UINT m_iMaxTitleHeight = 40;

And to make it work i would have to call:

my_function_that_writes_text_on_a_texture_in_memory()

then

addBitmapToTitleTexture(?????) (I see the first function uses this one so i dont have too !!)

(-_-)

Share this post


Link to post
Share on other sites
StratBoy61    232
Hey Chet2001,

Here is the implementation of the missing funtion.
HBITMAP InitGenericBitmap(int iIconWidth, int iIconHeight, HDC theDC, BYTE **BitmapPtr)
{
BITMAPINFO RGB32BitsBITMAPINFO;
ZeroMemory(&RGB32BitsBITMAPINFO,sizeof(BITMAPINFO));
RGB32BitsBITMAPINFO.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
RGB32BitsBITMAPINFO.bmiHeader.biWidth=iIconWidth;
RGB32BitsBITMAPINFO.bmiHeader.biHeight=iIconHeight;
RGB32BitsBITMAPINFO.bmiHeader.biPlanes=1;
RGB32BitsBITMAPINFO.bmiHeader.biBitCount=32;

return CreateDIBSection(theDC,
(BITMAPINFO *)&RGB32BitsBITMAPINFO,
DIB_RGB_COLORS,
(void **)BitmapPtr,
NULL, 0);
}


I recommend you to spend some time understanding what the whole code does. If you are a beginner, it is a bit of a problem, because what you want to do is not straightforward, unfortunately...
Maybe you want to start with a simple project that will only create a DIB with your dynamic text inside and display it onto a window panel (using MFC for instance); then, you may move on to applying the same technique to a DirectX texture.
Cheers
StratBoy61

Share this post


Link to post
Share on other sites
Chett2001    126
Allright will do, ive got it kinda working.. textures a bit distorted, the section the text is writen to is inverted colour and text? and the text is small.. Nothing a bit more research can fix no doubt :D. Its just nice to have something to play with so i can see exactly what controls what if you know what i mean, its a lot easier learning that way imo. I had no idea how i would achieve this before making this post so i would like to thank you guys a lot for the help leading me on the right lines. If i get completely stuck again though you might see another post further down the line :)

Share this post


Link to post
Share on other sites
Chett2001    126
OK another quick question, i want to replace the regular char Msg[255] variable text with something i can change the size of or the font type the line of code i need to change is:

DrawText(memDC, Msg, strlen(Msg), &myRect, DT_WORDBREAK | DT_CENTER | DT_NOPREFIX | DT_END_ELLIPSIS);

So i created a font with the settings i want and that all works this type of font doesnt accept the memDC and wants a sprite, when i leave it as a NULL value and let DirectX do its thing nothing shows up:

g_pd3dxFont->DrawText( NULL, myString, -1, &myRect, DT_WORDBREAK | DT_CENTER | DT_NOPREFIX | DT_END_ELLIPSIS, D3DXCOLOR(255, 255, 255, 1.0f));

Im sure its because i cant include the memDC, so:

A) whys is there a significant difference between the two types of DrawText.
B) What would be the best method to achieve this.
C) What exactly is memDC (HDC) achieving in this example? All the documentaiton ive read through hasnt really helped explain it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this