LPD3DXFONT-DrawText Positioning

Started by
7 comments, last by SiCrane 16 years ago
Having a bit of trouble trying to position 2D text on the screen. When I position it at 0,0 it renders in the correct position, but as it gets lower on screen it seems to "slip out" of the rect as illustrated in this image: Free Image Hosting at allyoucanupload.com Important bits of code:


RECT fontRect;
	
LPD3DXFONT font;
D3DXCreateFont( directXDevice, 30, 0, FW_NORMAL, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &font );

//...

for(int x = 0; x <= 1000; x = x + 50)
{
  SetRect(&fontRect, 0, x, 500, 500);
  font->DrawText(NULL, "TEST", -1, &fontRect, DT_SINGLELINE | DT_TOP, D3DCOLOR_XRGB(160, 160, 160) );
}

Complete code

#include <windows.h>
#include <d3d9.h> 
#include <d3dx9.h>
#include <dinput.h> 

#define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }

const char	MAIN_WINDOW_TITLE[] = "Window",
			MAIN_WINDOW_CLASS_NAME[] = "WindowClass";

const int	MAIN_WINDOW_WIDTH  = 750,
			MAIN_WINDOW_HEIGHT = 750;

int int_AppRunning = true;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
		case WM_CLOSE:
			DestroyWindow(hwnd);
			int_AppRunning = false;
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			int_AppRunning = false;
			break;
		default:
			return DefWindowProc(hwnd, msg, wParam, lParam);
	}
	return 0;
}


WNDCLASSEX initWindow(HINSTANCE hInstance)
{
	WNDCLASSEX w;
	//Register window class
	w.cbSize = sizeof(WNDCLASSEX);
	w.style = 0;
	w.lpfnWndProc = WndProc;
	w.cbClsExtra = 0;
	w.cbWndExtra = 0;
	w.hInstance = hInstance;
	w.hIcon = LoadIcon(NULL, IDI_APPLICATION); // large icon (Alt+Tab)
	w.hCursor = LoadCursor(NULL, IDC_ARROW);
	w.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	w.lpszMenuName = NULL;
	w.lpszClassName = MAIN_WINDOW_CLASS_NAME;
	w.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // small icon (title bar)


	if(!RegisterClassEx(&w)){
		MessageBox(NULL, "RegisterClassEx() failed", "System error",
			MB_ICONEXCLAMATION | MB_OK);
	}

	return w;
}



int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	
	WNDCLASSEX w = initWindow(hInstance);
	DWORD windowStyle = WS_OVERLAPPEDWINDOW;

	// Create window
	HWND hwnd = CreateWindowEx(NULL, MAIN_WINDOW_CLASS_NAME, MAIN_WINDOW_TITLE,windowStyle, CW_USEDEFAULT, CW_USEDEFAULT, MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);

	if(hwnd == NULL){
		MessageBox(NULL, "CreateWindowEx() failed", "System error", MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	// Show window
	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	// Init DirectX objects
	LPDIRECT3D9 directX;
	LPDIRECT3DDEVICE9 directXDevice;

	D3DPRESENT_PARAMETERS dxPresentParams;

	directX = Direct3DCreate9(D3D_SDK_VERSION);
	if (directX == NULL){
		::MessageBox(hwnd, "DirectX runtime library is not installed.", "System error", MB_ICONEXCLAMATION | MB_OK);
	}

	ZeroMemory( &dxPresentParams, sizeof(dxPresentParams) );
	dxPresentParams.Windowed = true;
	dxPresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
	dxPresentParams.BackBufferFormat = D3DFMT_UNKNOWN;		
    dxPresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
    dxPresentParams.hDeviceWindow = hwnd;
    dxPresentParams.BackBufferFormat = D3DFMT_X8R8G8B8;
    dxPresentParams.BackBufferWidth = MAIN_WINDOW_WIDTH;
    dxPresentParams.BackBufferHeight = MAIN_WINDOW_HEIGHT;
    dxPresentParams.EnableAutoDepthStencil = TRUE;  
    dxPresentParams.AutoDepthStencilFormat = D3DFMT_D16;
	D3DDISPLAYMODE d3ddm;

	directX->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);

	if (FAILED(directX->CreateDevice(
		D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
		hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, 
		&dxPresentParams, &directXDevice))){
		if (FAILED(directX->CreateDevice(
			D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, 
			hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, 
			&dxPresentParams, &directXDevice))){
			::MessageBox(hwnd, 
			"CreateDevice() failed", "System error", 
			MB_ICONEXCLAMATION | MB_OK);
		}
	}

	directXDevice->SetRenderState(D3DRS_LIGHTING, TRUE);    // turn on the 3D lighting
    directXDevice->SetRenderState(D3DRS_ZENABLE, TRUE);    // turn on the z-buffer
    directXDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(50, 50, 50));    // ambient light

	// Init Font	
	RECT fontRect;
	
	LPD3DXFONT font;
	D3DXCreateFont( directXDevice, 30, 0, FW_NORMAL, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &font );

	MSG msg;
	while(int_AppRunning)
	{
		if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
		}	

		directXDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0);
		directXDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
		directXDevice->BeginScene();



		for(int x = 0; x <= 1000; x = x + 50)
		{
			SetRect(&fontRect, 0, x, 500, 500);
			font->DrawText(NULL, "TEST", -1, &fontRect, DT_SINGLELINE | DT_TOP, D3DCOLOR_XRGB(160, 160, 160) );
		}		
		directXDevice->EndScene();
		directXDevice->Present(NULL, NULL, NULL, NULL);

		Sleep(100);
		
	}

	SAFE_RELEASE(directXDevice);
	SAFE_RELEASE(directX)
	SAFE_RELEASE(font);

	DestroyWindow(hwnd);
	return 0;
}



Any help as to what im doing wrong here would be much appreciated. Thanks.
Advertisement
.bump.
I would say it's the background texture that is wrong, check it :)

secondly...
// to clear both screen and zbufferdirectXDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0);// c++ supports += operatorfor(int x = 0; x <= 1000; x += 50)
Thanks for the clearing tip.

I'm not quite sure what you mean by 'background texture' the red boxes were added to the output via photoshop, to show where the rects are.
ok, well you must have drawn those line wrong then :)

and it should be:
SetRect(&fontRect, 0, x, 500, x + 500);
I've double checked and the red boxes are 50px in height (including the 1px red lines).

The reason why I'm trying to solve this problem is that I change the color of the text when the mouse is within the rect. So I'm pretty sure about the position of the rects.

I've changed my code to:

SetRect(&fontRect, 0, x, 500, x + 500); (as it is in my actual game)

but the only difference it makes is that the text now shows below y = 500px

Any other ideas?
The problem is most likely your window creation code. When you call CreateWindow() you pass it MAIN_WINDOW_WIDTH and MAIN_WINDOW_HEIGHT and when you set your present parameters you use the same sizes. Unfortunately, the client area of your window is going to be smaller than MAIN_WINDOW_WIDTH and MAIN_WINDOW_HEIGHT since the values you pass to CreateWindow() include things like the window caption and borders. Try using AdjustWindowRect() to account for the difference.
Thanks SiCrane that seems to have fixed it (it still slips a little but not as much).

The msdn docs say that WS_OVERLAPPED can't be used with AdjustWindowRect:
http://msdn2.microsoft.com/en-us/library/ms632665(VS.85).aspx

but they don't specify why? Is it simply because WS_OVERLAPPED is an aggregate of other window styles?
I don't know the official reason, but I've been told it's because WS_OVERLAPPED has a numeric value of 0 and the code that adjusts the rectangle works off of the bit flags so the 0 value isn't processed correctly. This is hearsay so take it with a grain of salt.

Here is a thread that describes other posters' workarounds for this.

This topic is closed to new replies.

Advertisement