Sign in to follow this  
LilithAnn

Writing text to an image

Recommended Posts

LilithAnn    166
Scenario: Using Dark GDK for game development. It's drawing capability is limited to bitmaps and the screen (simplified statement). Dark GDK is a C++ interface to DirectX functionality, though I see more procedural code than OOP in their approach. So I'm working on an OOP wrapper for its 2D functionality to enhance my ability to inherit. I've created an Image class which has as some of its private data the following:

	DWORD width;	// visible width of the image
	DWORD height;	// visible height of the image
	DWORD depth;	// color depth in bits
	DWORD size;	// size of image in bytes
	UINT  pitch8;	// number of bytes across in the image, regardless of width
	UINT  pitch32;	// number of DWORDs across in the image, regardless of width
	UINT8 bpp;
	DWORD *bytes;	// pointer to image data for DWORD-sized data
	IDirect3DDevice9 *device;
	LPDIRECT3DTEXTURE9 data;	// pointer to image object
	D3DLOCKED_RECT imgData;		// locking rectangle
	ID3DXFont *font;	// pointer to font data
	UINT cursorX;	// cursor x position for printing
	UINT cursorY;	// cursor y position for printing
	UINT printW;	// print width
	UINT printH;	// print height
	void * imgPtr;	// void pointer to the pixel data
	LPSTR pData;

I've been able to develop some fucntions for drawing directly to the image, which is then displayed in conjunction with a sprite as needed. What I've found is that, whereas I can use the GDK to write text to the screen and a bitmap, I need to provide that capability directly to an image. The text may not need to be displayed immediately but whenever the image is displayed it needs to be there. After "borrowing" some code I've come up with the following for establishing the font. Some of it is hardcoded but that's only for developmental purposes. It still returns S_OK.
bool Image::SetFont(int h, UINT w, UINT weight, bool italics, LPCTSTR pFacename)
{
	if (font != NULL) font->Release();
	HRESULT result =
	D3DXCreateFont (device, h, w, weight, 0, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
					DEFAULT_PITCH, pFacename, &font);
	return (result == S_OK);
}

Below is the code I use to "try" to draw the text string to the image. In my test environment the image starts out blank white and the color I'm passing for the text is black. The code I was borrowing had a clear statement that I used initially but decided to remove since it wasn't necessary. The code also had pSurfaceLevel->Release(); statement, which I left in, but I'm not certain where the locking is being done, if it was in the code at all.
void Image::Print(LPSTR text, DWORD color)
{
	RECT rct;
	
	IDirect3DSurface9 *pSurfaceLevel;	// pointer to surface
	IDirect3DSurface9 *pSurfaceSave;	// pointer to current render target
	device->GetRenderTarget(0, &pSurfaceSave);
	data->GetSurfaceLevel(0, &pSurfaceLevel);
	device->SetRenderTarget(0, pSurfaceLevel);

	rct.left = cursorX;
	rct.right = cursorX + printW;
	rct.top = cursorY;
	rct.bottom = cursorY + printH;

	D3DCOLOR prtColor = color;
	if (font == NULL) return;
	font->DrawText(NULL, text, -1, &rct, DT_CENTER | DT_VCENTER, prtColor);
	device->SetRenderTarget(0, pSurfaceSave);
	pSurfaceLevel->Release();

}

The text doesn't appear on the image. Could someone advise me if this code has any merit or if I'm totally off base? Any advice regarding the proper approach? Thanks, Lilith

Share this post


Link to post
Share on other sites
LilithAnn    166
Yes. I'm sorry about the brevity of my naming conventions. It's one of my weak points. I use it to lock the area and set imgPtr to the beginning of the pixel area. This is my locking method.


void Image::Lock(void)
{
data->LockRect(0, &imgData, NULL, 0);
imgPtr = imgData.pBits;
pitch32 = imgData.Pitch / sizeof (DWORD);
bytes = (DWORD *) imgPtr;
locked = true;
}



Lilith

Share this post


Link to post
Share on other sites
Evil Steve    2017
Anything from the Debug Runtimes?

Also, from the docs for LockRect():
Quote:
This method cannot retrieve data from a surface that is is contained by a texture resource created with D3DUSAGE_RENDERTARGET because such a texture must be assigned to D3DPOOL_DEFAULT memory and is therefore not lockable. In this case, use instead IDirect3DDevice9::GetRenderTargetData to copy texture data from device memory to system memory.

Share this post


Link to post
Share on other sites
LilithAnn    166
I'm unable to comply. The Dark GDK API creates the texture and, for my purposes, I need to let them since its relationship to the sprite involved is dependent on their system. They provide code to load the image from file but there are some undocumented functions in their image header file for creating "empty" images.


LPDIRECT3DTEXTURE9 dbMakeImage ( int iID, int iWidth, int iHeight );
LPDIRECT3DTEXTURE9 dbMakeImageUsage ( int iID, int iWidth, int iHeight, DWORD dwUsage );
LPDIRECT3DTEXTURE9 dbMakeImageJustFormat ( int iID, int iWidth, int iHeight, D3DFORMAT Format );
LPDIRECT3DTEXTURE9 dbMakeImageRenderTarget ( int iID, int iWidth, int iHeight, D3DFORMAT Format );



I've used an image that I've let their code load from a file and I've also allowed for using the dbMakeImage() function to create an empty. The int iID identifier is their internal numbering for the image which I provide when I make the function call.

They provide


LPDIRECT3DTEXTURE9 dbGetImagePointer ( int iID );



in order to return a pointer to the image object, which I assign to "data".

Lilith

Share this post


Link to post
Share on other sites
LilithAnn    166
Quote:

The debug runtimes will still be able to tell you if there's a D3D call failing though.


Running through debug I'm getting a strange result with the statement

	result = device->SetRenderTarget(0, pSurfaceLevel);  


On the two previous calls I received S_OK in return. On this one I got a value returned that didn't get back S_OK or D3DERR_INVALIDCALL. Instead I got 0x8876086c. So I assume that it's failing in some sense there but I can't imagine what the return value indicates or why it would fail.

Lilith

Share this post


Link to post
Share on other sites
MJP    19755
Well whatever 0x8876086c means, it's a failing HRESULT code.

I'd bet a thousand bucks that when that GDK function loads the image to a texture, it doesn't load it with D3DUSAGE_RENDERTARGET or with D3DPOOL_DEFAULT. Probably the easiest way to do what you want here would be to create a render-target, then render the image onto that render-target. Then you could render the text onto that.

Share this post


Link to post
Share on other sites
LilithAnn    166
Kind of what I was hoping to avoid but I'll look into it. Most of what I'm pursuing here is an attempt to avoid drawing the text to what the GDK refers to as a bitmap and then copying that to the image. I'm guilty of being overly concerned with things that add time to the process.

AAR, you've given me something to think on and a direction to go. I offer my thanks for your help.

Lilith

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by LilithAnn
On the two previous calls I received S_OK in return. On this one I got a value returned that didn't get back S_OK or D3DERR_INVALIDCALL. Instead I got 0x8876086c. So I assume that it's failing in some sense there but I can't imagine what the return value indicates or why it would fail.
The debug runtimes should spit out a useful error message like "Direct3D9: (ERROR) : Textures created in D3DPOOL_DEFAULT are not lockable. LockRect() fails." into your debug output, telling you the problem.

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