Шаг 22 - Используем шрифты в Direct3D

Когда я изучал Borland C++ версии 3.0 (работал он только под DOS-ом, о Windows еще никто ничего не знал) меня потянуло в графику. После некоторого изучения я понял, что без русского шрифта не обойтись. С ним были проблемы, когда переходил в графический режим вместо русского выходили иероглифы. Но потом нашел выход, сделал двумерный массив под каждую букву с шириной 8х8 точек и заполнил их. И позже в своей программе их использовал. Был один недостаток у шрифта, нельзя было менять размер. Но меня тогда это не расстраивало, т.к. на то время, шрифт был стандартным и использовали во всех программах один тип и один размер. Сейчас, все по другому, ничего не нужно самому изобретать все уже есть :) Вы можете использовать любой тип шрифта с любым цветом, с любыми размерами :) и с кириллицей теперь нет проблем :)

Как Вы уже знаете из раздела MFC, прежде чем отображать шрифт, его нужно создать. Поэтому добавьте в конструктор главного окна после инициализации указателей следующее:

HFONT hFont = CreateFont(
	24,			// высота шрифта
	0,			// ширина
	0,			// угол по часовой стрелке
	0,			// угол против часовой стрелки
	FW_NORMAL,		// насыщенность шрифта
	FALSE,			// курсив
	FALSE,			// подчеркивание
	0,			// зачеркнуть
	ANSI_CHARSET,		// использование кодировки
	OUT_DEFAULT_PRECIS,	// nOutPrecision
	CLIP_DEFAULT_PRECIS,	// nClipPrecision
	DEFAULT_QUALITY,		// качество
	DEFAULT_PITCH | FF_SWISS,	// семейство и гарнитура
	"Arial");			// тип шрифта

Дальше мы создадим свой класс Font, чтобы позже нам было проще работать с шрифтом. Для этого закроем свой исходник, зайдем в окно Class View, нажмем правую кнопку на имени проекта, из меню выберем Add->Add Class (Добавить->Добавить Класс). В появившемся окне выбираем в правой части Generic C++ Class (Генерировать Класс C++), нажимаем кнопку Open (Открыть). Появится новое окно Generic C++ Class Wizard Имя проекта в поле Class Name (Имя Класса) вводим Font и нажимаем кнопку Finish (Финиш). Скелет класса готов. Начнем постепенно его заполнять.

Щелкните правой кнопкой на классе Font и выберите из меню Add->Add Function (Добавить->Добавить Функцию).

22_1.gif (4091 b)

В появившемся диалоговом окне в поле Return Type (Возвращаемый Тип) выберите из выпадающего списка void (пустой). В поле Function Name (Имя Функции) введите Init. В поле Parameter Type (Тип Параметра) введите LPDIRECT3DDEVICE8 и в поле Parameter Name (Имя Параметра) введите Device. Затем щелкните на кнопку Add (Добавить). Тип и имя параметра попадут в поле Parameter List (Список Параметров), см. ниже рисунок:

22_2.gif (2638 b)

Не закрывая диалоговое окно, добавьте тип и имя параметра HFONT Font. Должно получиться:

22_3.gif (2681 b)

И теперь нажмите кнопку Finish (Финиш).

Добавим к данному классу несколько переменных. Щелкаем правой кнопкой мышки на классе Font и из меню выбираем Add->Add Variable (Добавить->Добавить Переменную):

22_4.gif (3619 b)

В появившемся диалоговом окне заполняем:

22_5.gif (1944 b)

И нажимаем кнопку Finish (Финиш). Таким же способом добавьте:

LPD3DXFONT pFont;		// Используемый шрифт
RECT Rect;		// Координаты текста

Более подробно о структуре LPD3DXFONT см. раздел Справка по DirectX: "Шаг 83 - Описание интерфейса ID3DXFont". В конструкторе класса указатель pFont присвойте NULL.

Font::Font(void)
{
	pFont = NULL;
}

Перейдем к заполнению функции Init():

void Font::Init(LPDIRECT3DDEVICE8 Device, HFONT Font)
{
	d3d_Device = Device;			// Запоминаем используемое устройство
	D3DXCreateFont (Device, Font, &pFont);	// Создаем шрифт
}

Наше устройство должно знать, какой шрифт нужно использовать. Т.к. здесь мы используем функцию D3DXCreateFont, то нам нужно указать соответствующие библиотеки. Более подробно об этой функции см. раздел Справка по DirectX: "Шаг 84 - Функция D3DXCreateFont".

Откройте файл Font.h и добавьте:

#pragma once

#include <D3dx8core.h>
#pragma comment (lib, "d3dx8.lib")

Вывод на экран. Добавим новую функцию Print к классу Font и заполним его:

void Font::Print(char* text, int x, int y, D3DCOLOR Color)
{
	Rect.left = x;		// Заносим координаты текста
	Rect.top = y;		// в структуру Rect, как
	Rect.bottom = 0;		// левый верхний угол
	Rect.right = 0;

	pFont->Begin();		// Начинаем вывод текста

		// Рисуем текст в определенном месте, с заданным цветом
		pFont->DrawTextA (text, -1, &Rect, 0, Color);

	pFont->End();		// Закончили вывод текста
}

Более подробно об этих функциях см. раздел Справка по DirectX:

Все, с классом Font покончено :) Теперь возьмемся за его реализацию в нашей программе. Так как мы собираемся использовать этот класс, то и подключим его:

#include "font.h"

Произведем MyFont от класса Font:

class CMainWnd : public CFrameWnd
{
private:
.
.
.
	Font MyFont;	// Наш текст
.
.
.

Перейдем в конструктор главного окна рамки, перед закрывающей скобкой инициализируем шрифт:

MyFont.Init(p_d3d_Device, (HFONT)hFont);

Перейдем в функцию OnPaint() и перед EndScene() добавим:

MyFont.Print ("Привет, всем разработчикам DirectX !!!",
	300, 400, D3DCOLOR_XRGB (0,255,0));

Осталось только удалить указатели, которые потом станут ненужными, вставьте ниже следующий код после подключения библиотек в файле Font.h:

#define _RELEASE_(p) { if(p) { (p)->Release(); (p)=NULL; };};
#define _DELETE_(p)  { if(p) { delete (p); (p)=NULL; };};

И деструктор должен выглядеть:

Font::~Font(void)
{
	_RELEASE_ (pFont);
	_DELETE_ (pFont);
}

Компилируем, запускаем и получаем:

Чтобы восстановить шрифт, нам нужно сделать следующее:

void Font::Restore(void)
{
	pFont->OnLostDevice ();	// Освобождаем шрифт (если устройство потеряно)
	pFont->OnResetDevice ();	// Восстанавливаем шрифт
}

Добавьте выше показанную функцию самостоятельно :) Более подробно об этих функциях см. раздел Справка по DirectX:

И вызовите эту функцию в OnPaint():

if (hr==D3DERR_DEVICENOTRESET)
{
	p_d3d_Device->Reset(&d3dpp);
	Transform3D();
	MyFont.Restore();
}

Тестируйте и проверяйте :)


Загрузить проект | Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Хавов Евгений Валерьевич - 3.09.2002