310 likes | 511 Views
9 장 글꼴. 텍스트 출력 방법. ID3DXFont 인터페이스를 이용해서 텍스트 렌더링 CD3Dfont 클래스를 이용해서 텍스트 렌더링 D3DXCreateText 함수를 이용해 3D 텍스트를 만들고 렌더링. ID3DXFont. D3DX 라이브러리는 Direct3D 애플리케이션에서 텍스트를 그리는 데 사용할 수 있는 ID3DXFont 인터페이스를 제공 이 인터페이스는 내부적으로 GDI 를 이용하기 때문에 약간의 성능 저하가 따르지만 , GDI 의 도움으로 복잡한 글꼴이나 포맷팅을 이용할 수 있음
E N D
텍스트 출력 방법 • ID3DXFont 인터페이스를 이용해서 텍스트 렌더링 • CD3Dfont 클래스를 이용해서 텍스트 렌더링 • D3DXCreateText 함수를 이용해 3D 텍스트를 만들고 렌더링 컴퓨터게임(DirectX)
ID3DXFont • D3DX 라이브러리는 Direct3D 애플리케이션에서 텍스트를 그리는 데 사용할 수 있는 ID3DXFont 인터페이스를 제공 • 이 인터페이스는 내부적으로 GDI를 이용하기 때문에 약간의 성능 저하가 따르지만, GDI의 도움으로 복잡한 글꼴이나 포맷팅을 이용할 수 있음 • ID3DXFont 만들기 • D3DXCreateFontIndirect 함수를 이용해 ID3DXFont 인터페이스를 만들 수 있음 컴퓨터게임(DirectX)
HRESULT D3DXCreateFontIndirect( LPDIRECT3DDEVICE9 pDevice, //글꼴과 연결된 장치 CONST LOGFONT* pLogFont, //글꼴을 나타내는 LOGFONT 구조체 LPD3DXFONT* ppFont //만들어진 글꼴을 리턴 ); 컴퓨터게임(DirectX)
D3DXCreateFontIndirect 함수 이용 방법 LOGFONT lf; ZeroMemory(&lf, sizeof(LOGFONT)); lf.lfHeight = 25; // in logical units lf.lfWidth = 12; // in logical units lf.lfEscapement = 0; lf.lfOrientation = 0; lf.lfWeight = 500; // boldness, range 0(light) - 1000(bold) lf.lfItalic = false; lf.lfUnderline = false; lf.lfStrikeOut = false; lf.lfCharSet = DEFAULT_CHARSET; lf.lfOutPrecision = 0; 컴퓨터게임(DirectX)
lf.lfClipPrecision = 0; lf.lfQuality = 0; lf.lfPitchAndFamily = 0; strcpy(lf.lfFaceName, "Times New Roman"); // font style ID3DXFont* font=0; D3DXCreateFontIndirect(Device,&lf,&font); • 만들고자 하는 글꼴의 특성을 지정하는 LOGFONT 구조체를 먼저 채워야 한다 컴퓨터게임(DirectX)
텍스트 그리기 • ID3DXFont 인터페이스로의 포인터를 얻은 다음에는 ID3DXFont::DrawText 메서드를 호출하여 간단하게 텍스트를 그려낼 수 있음 • INT ID3DXFont::DrawText( LPCSTR pString, INT Count, LPRECT pRect, DWORD Format, D3DCOLOR color ); • pString –그리고자하는 문자열을 가리키는 포인터 • Count –문자열 내에 포함된 문자의 수. 문자열이 null로 끝나는 경우에는 -1을 지정할 수 있음 컴퓨터게임(DirectX)
pRect –텍스트가 그려질 화면 상의 영역을 정의하는 RECT 구조체를 가리키는 포인터 • Format –텍스트 포맷을 지정하는 선택적 플래그 • Color –텍스트 컬러 • 예를 들면 • Font->DrawText( “Hello World”, // 그리고자 하는 문자열 -1, // Null 로 끝나는 문자열 &rect, // 텍스트가 그려질 사각형 DT_TOP | DT_LEFT, // 사각형의 왼쪽 상단에 그림 0xff000000); // 검은색 컴퓨터게임(DirectX)
초당 렌더링 프레임 계산하기 • CFont 예제는 초당 렌더링되는 프레임수(FPS) 출력 • 먼저 다음과 같은 세 개의 전역 변수 인스턴스를 만든다 • DWORD FrameCnt; //렌더링된 프레임수 float TimeElapsed; //현재까지 경과된 시간 float FPS; //초당 렌더링 프레임 수 • 매 초마다 FPS를 계산하여 비교적 정확한 평균을 얻음. 부가적으로 매 초당 일정한 FPS를 유지하여 변경된 값을 다시 계산할 동안 충분한 시간을 제공 • 각각의 프레임은 FrameCnt를 증가시키며 TimeElapsed에 마지막 프레임부터 현재까지 걸린 시간을 더함 • FrameCnt++; TimeElapsed += timeDelta; //timeDelta는 각 프레임당 걸린시간 컴퓨터게임(DirectX)
1초가 흐른 뒤에는 다음과 같은 식을 이용해 FPS를 계산할 수 있음 • FPS=(float) FrameCnt/ TimeElapsed; • 이제 FrameCnt와 TimeElapsed를 초기화하고 다음 1초를 위한 FPS 계산을 시작 • 다음은 완성된 코드임 • void CalcFPS(float timeDelta) { FrameCnt++; TimeElapsed += timeDelta; If(TimeElapsed >= 1.0f) { FPS=(float)FrameCnt / TimeElapsed; TimeElapsed = 0.0f; FrameCnt=0; } } 컴퓨터게임(DirectX)
CD3DFont • DirectX SDK는 DXDSK 루트 디렉토리의 /samples/c++/common 폴더에 매우 유용한 유틸리티 코드를 제공 • 이 코드 중에 CD3Dfont 클래스가 포함되어 있으며, 이 클래스는 Direct3D와 텍스처를 입힌 삼각형을 이용해 텍스트를 렌더링함 • CD3DFont는 GDI가 아닌 Direct3D를 이용하므로 ID3DXFont에 비해 훨씬 빠른 속도를 가지고 있지만 ID3DXFont의 복잡한 글꼴과 포맷팅은 지원하지 못함 • CD3DFont 클래스를 이용하려면 d3dfont.h, d3dfont.cpp, d3dutil.h, dxutil.h, dxutil.cpp 파일을 추가해야 함: • Common 폴더의 Include 와 src 폴더에 있음 컴퓨터게임(DirectX)
CD3DFont 구성하기 • CD3DFont 인스턴스를 만들기 위해서는 일반적인 C++객체와 마찬가지로 이를 인스턴스화하면 됨 • CD3DFont의 생성자 프로토타입 • CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags=0L); • strFontName –글꼴의 이름을 지정하는 null로 끝나는 문자열 • dwHeight –글꼴의 높이 • dwFlags –선택적 생성 플래그들; 이 인자에는 0을 지정하거나 D3DFONT_BOLD, D3DFONT_ITALIC, D3DFONT_ZENABLE 플래그들의 조합을 지정할 수 있음 컴퓨터게임(DirectX)
CD3DFont 객체를 인스턴스화한 다음에는 다음의 메서드들을 순서대로 호출하여 글꼴을 초기화해야 함 • Font=new CD3DFont(“Times New Roman”, 16,0); • Font->InitDeviceObjects(Device); • Font->RestoreDeviceObjects(); 컴퓨터게임(DirectX)
텍스트 그리기 • CD3DFont 객체를 구성하고 초기화하였다면 텍스트를 그릴 준비가 완료된 것이고, 텍스트를 그리는 데는 다음과 같은 메서드가 이용 • HRESULT CD3DFont::DrawText(FLOAT x, FLOAT y, DWORD dwColor, const TCHAR* strText, DWORD dwFlags=0L); • x - 텍스트 그리기를 시작할 화면의 x축 좌표 • y - 텍스트 그리기를 시작할 화면의 y축 좌표 • dwColor –텍스트의 컬러 • strText –그리고자 하는 문자열의 포인터 • dwFlags –선택적 렌더링 플래그들; 이 인자에는 0을 지정하거나 D3DFONT_CENTERED, D3DFONT_TWOSIDED, D3DFONT_FILTERED 플래그들의 조합을 지정할 수 있음 • 예를 들어 • Font->DrawText(20, 20, 0xff000000, “Hello, World”); 컴퓨터게임(DirectX)
정리 • D3DFont 객체를 삭제하기 전에 다음의 코드 조각에서 보여주는 것과 같은 약간의 정리 루틴을 호출해야 함 • Font->InvalidateDeviceObjects(); Font->DeleteDeviceObjects(); Delete Font; 컴퓨터게임(DirectX)
D3DXCreateText • 이 함수는 텍스트의 3D 메쉬를 만드는데 이용됨 • 함수의 프로토 타입 • HRESULT D3DXCreateText( LPDIRECT3DDEVICE9 pDevice, HDC hDC, LPCTSTR pText, FLOAT Deviation, FLOAT Extrusion, LPD3DXMESH* ppMesh, LPD3DXBUFFER* ppAdjacency, LPGLYPHMETRICSFLOAT pGlyphMetrics ); 컴퓨터게임(DirectX)
이 함수는 실행이 성공한 경우 D3D_OK를 리턴 • pDevice –메쉬와 연결될 장치 • hDC –메쉬를 생성하는 데 이용될 글꼴 정보를 포함하는 장치 컨텍스트로의 핸들 • pText –메쉬로 만들 텍스트를 포함하는 null로 끝나는 문자열 • Deviation –트루타입 글꼴 외곽선에서의 최대 편차. 이 값은 0이거나 보다 커야 한다. 이 값이 0일 때 편차는 원본 글꼴의 한 디자인 단위와 같게 됨 • Extrusion –음의 z축 방향으로 잰 글꼴의 깊이 • ppMesh –만들어진 메쉬를 리턴 • ppAdjacency –만들어진 메쉬의 근접 정보를 리턴 • pGlyphMetrics –장식 거리 데이터를 포함하는 LPGLYPHMETRICSFLOAT 구조체 배열의 포인터. 장식 거리 데이터에 상관하지 않는 경우에는 이를 0으로 지정 컴퓨터게임(DirectX)
다음의 예제코드는 이 함수를 이용해 3D 메쉬를 만드는 방법을 보여줌 HDC hdc = CreateCompatibleDC( 0 ); // 장치컨텍스트로의 핸들 HFONT hFont; // 을 얻음 ZeroMemory(&lf, sizeof(LOGFONT)); // LOGFONT 구조체를 채움 lf.lfHeight = 25; // in logical units lf.lfWidth = 12; // in logical units lf.lfEscapement = 0; lf.lfOrientation = 0; lf.lfWeight = 500; // boldness, range 0(light) - 1000(bold) lf.lfItalic = false; lf.lfUnderline = false; lf.lfStrikeOut = false; lf.lfCharSet = DEFAULT_CHARSET; 컴퓨터게임(DirectX)
lf.lfOutPrecision = 0; lf.lfClipPrecision = 0; lf.lfQuality = 0; lf.lfPitchAndFamily = 0; strcpy(lf.lfFaceName, "Times New Roman"); // font style // 글꼴을 만들고 장치 컨텍스트로 글꼴을 선택 HFONT hFontOld; LOGFONT lf; hFont = CreateFontIndirect(&lf); hFontOld = (HFONT)SelectObject(hdc, hFont); // 텍스트의 3D 메쉬를 만들어낸다. ID3DXMesh* Text = 0; D3DXCreateText(Device, hdc, "Direct3D", 0.001f, 0.4f, &Text, 0, 0); 컴퓨터게임(DirectX)
// 다시 이전의 글꼴을 선택하고 자원을 해제 SelectObject(hdc, hFontOld); DeleteObject( hFont ); DeleteDC( hdc ); • 마지막으로 메쉬의 DrawSubset 메서드를 호출하여 간단히 3D 텍스트 메쉬를 렌더링할 수 있음 • Text->DrawSubset(0); 컴퓨터게임(DirectX)
d3dxcreatetext.cpp #include "d3dUtility.h" IDirect3DDevice9* Device = 0; const int Width = 640; const int Height = 480; ID3DXMesh* Text = 0; bool Setup() { HDC hdc = CreateCompatibleDC( 0 ); HFONT hFont; HFONT hFontOld; LOGFONT lf; ZeroMemory(&lf, sizeof(LOGFONT)); 컴퓨터게임(DirectX)
lf.lfHeight = 25; // in logical units lf.lfWidth = 12; // in logical units lf.lfEscapement = 0; lf.lfOrientation = 0; lf.lfWeight = 500; // boldness, range 0(light) - 1000(bold) lf.lfItalic = false; lf.lfUnderline = false; lf.lfStrikeOut = false; lf.lfCharSet = DEFAULT_CHARSET; lf.lfOutPrecision = 0; lf.lfClipPrecision = 0; lf.lfQuality = 0; lf.lfPitchAndFamily = 0; strcpy(lf.lfFaceName, "Times New Roman"); // font style hFont = CreateFontIndirect(&lf); hFontOld = (HFONT)SelectObject(hdc, hFont); 컴퓨터게임(DirectX)
D3DXCreateText(Device, hdc, "Direct3D", 0.001f, 0.4f, &Text, 0, 0); SelectObject(hdc, hFontOld); DeleteObject( hFont ); DeleteDC( hdc ); D3DXVECTOR3 dir(0.0f, -0.5f, 1.0f); D3DXCOLOR col = d3d::WHITE; D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col); Device->SetLight(0, &light); Device->LightEnable(0, true); Device->SetRenderState(D3DRS_NORMALIZENORMALS, true); Device->SetRenderState(D3DRS_SPECULARENABLE, true); 컴퓨터게임(DirectX)
D3DXVECTOR3 pos(0.0f, 1.5f, -3.3f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; D3DXMatrixLookAtLH( &V, &pos, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( 컴퓨터게임(DirectX)
&proj, D3DX_PI * 0.25f, // 45 - degree (float)Width / (float)Height, 0.01f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); return true; } void Cleanup() { d3d::Release<ID3DXMesh*>(Text); } bool Display(float timeDelta) { 컴퓨터게임(DirectX)
if( Device ) { D3DXMATRIX yRot, T; static float y = 0.0f; D3DXMatrixRotationY(&yRot, y); y += timeDelta; if( y >= 6.28f ) y = 0.0f; D3DXMatrixTranslation(&T, -1.6f, 0.0f, 0.0f); T = T * yRot; Device->SetTransform(D3DTS_WORLD, &T); 컴퓨터게임(DirectX)
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0); Device->BeginScene(); Device->SetMaterial(&d3d::WHITE_MTRL); Text->DrawSubset(0); Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; } LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) 컴퓨터게임(DirectX)
{ case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) 컴퓨터게임(DirectX)
{ if(!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device)) { ::MessageBox(0, "InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) { ::MessageBox(0, "Setup() - FAILED", 0, 0); return 0; } d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; } 컴퓨터게임(DirectX)