DirectX 8.1 в MASM32: Урок 5. Использование текста — Архив WASM.RU

Все статьи

DirectX 8.1 в MASM32: Урок 5. Использование текста — Архив WASM.RU

Часто, когда приложение уже запущено, необходимо вывести некоторую полезную информацию: подсказки пользователю, содержимое переменных, сообщения об ошибках и т.д. Легко и быстро это делается с помощью текста.

Как вы все знаете, вывод текста в приложениях, не использующих 3D, осуществляется посредством GDI, который может предложить несколько функций, различающихся параметрами и удобством применения. В трехмерном же приложении использование GDI практически невозможно за редким исключением. Даже если удастся каким-то образом его задействовать, то потери времени при использовании будут очень значительные. В качестве альтернативы Direct3D предлагает нам всего лишь один метод для вывода текста. Если вы ожидаете от него каких-то наворотов и спецэффектов, то спешу вас разочаровать, метод служит только для простого вывода текста и ничего более. Кстати, у него имеется довольно много различных флагов, но они не сильно скрашивают и так хилые возможности. Более подробно на преимуществах и недостатках мы остановимся в конце статьи, а пока... пока рассмотрим с чего собственно начинать.

Первым делом, необходимо подключить .inc файл, содержащий прототипы необходимых нам функций и методов. Называется он d3dx8core.

Далее у нас есть два пути создания шрифта. Почему два и не более? Просто разработчики создали по аналогии с GDI две функции: D3DXCreateFont и D3DXCreateFontIndirect, которые и помогут сделать всю работу.

Рассмотрим по шагам первый путь:

 1. а) Или вызываем функцию GDI CreateFont для создания шрифта
    б) Или заполняем структуру LOGFONT нужными параметрами и вызываем 
       CreateFontIndirect 
    
       ( те, кто не пользовался этими функциями, могут прочитать о них в одном
         из уроков Iczeliona )

 2. Вызываем функцию D3DXCreateFont, передавая ей полученный ID шрифта

Вот и все. Проще просто не бывает.

А теперь второй путь:

 1. Заполняем структуру LOGFONT нужными параметрами 
 2. Вызываем функцию D3DXCreateFontIndirect, передавая ей указатель на 
    структуру

Второй путь самый минимальный. Никаких тебе GDI функций и лишней головной боли.

Справка

  D3DXCreateFont передается 3 параметра.
  ---------------------------------------------
  1. Указатель на Direct3DDevice
  2. ID шрифта
  3. Адрес памяти куда Direct3D поместит указатель на шрифт

  Если все прошло успешно, функция возвращает D3D_OK.
  Если нет, то D3DERR_INVALIDCALL или D3DERR_OUTOFMEMORY.

  D3DXCreateFontIndirect передается 3 параметра.
  ----------------------------------------------
  1. Указатель на Direct3DDevice
  2. Адрес структуры LOGFONT
  3. Адрес памяти куда Direct3D поместит указатель на шрифт

  Если все прошло успешно, функция возвращает D3D_OK.
  Если нет, то D3DERR_INVALIDCALL или D3DERR_OUTOFMEMORY.

Как видно из справки, без уже созданного устройства Direct3DDevice создать и зарегистрировать шрифт не представляется возможным.

После того, как мы получили от Direct3D указатель на шрифт, можно начинать с ним работать. Как уже упоминалось выше, у нас имеется в распоряжении только один метод отрисовки текста, он называется DrawText и существует в двух вариантах: DrawTextA - рисует текст в формате ANSI, DrawTextW - рисует текст в формате UNICODE.

Отрисовка не должна вызвать у вас затруднений, но на всякий случай я приведу пример:

  Почистили буфер... 
  ------------------
  d3dev8  Clear, pd3dDevice, 0, NULL, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER, \
                 clearcolor , Zvalue , 0

  Отрисовали полигоны...    
  ----------------------
  d3dev8  DrawPrimitive, pd3dDevice, D3DPT_TRIANGLELIST, 0, CountPrimitive

  А теперь рисуем текст...
  ------------------------
  d3dxfont8 DrawTextA, pd3dFont, ADDR szText, -1, ADDR RECT, DT_NOCLIP, colortext          

  И все показываем...
  -------------------
  d3dev8  Present, pd3dDevice, NULL, NULL, NULL, NULL

Отрисовку текста нужно производить самым последним этапом перед показом буфера на экран. Думаю это обьяснять вам не надо.

Справка

  DrawText(А или W) передается 5 параметров.
  ----------------------------------------------------------------------------
  1. Адрес текста который нужно вывести
  2. Число символов в строке или -1, чтобы Direct3D сам вычислил его
  3. Адрес структуры типа RECT
  4. Сумма флагов
  5. Цвет текста в формате ARGB

  Флаги: ( приведены только самые используемые, специфические опущены )
  ----------------------------------------------------------------------------
  DT_BOTTOM      - выравнивает текст по нижней границе прямоугольника
                   Может использоваться совместно с DT_SINGLELINE

  DT_LEFT        - выравнивает текст по левой границе прямоугольника

  DT_RIGHT       - выравнивает текст по правой границе прямоугольника

  DT_TOP         - выравнивает текст по верхней границе прямоугольника

  DT_CENTER      - центрирует текст по горизонтали

  DT_VCENTER     - центрирует текст по вертикали

  DT_CALCRECT    - Direct3D сам вычислит прямоугольник, в который помещается
                   выводимый текст. Важно помнить, что при этом текст 
                   отрисован не будет.
  
  DT_NOCLIP      - не проверять выходит ли текст за границы прямоугольника

  Внимание !
  - Все флаги выравнивания текста действуют для того прямоугольника, в котором
    он должен быть выведен.
  - Метод действует только с теми шрифтами, в которых Escapement и Orientation
    равны нулю.
  - Если размер шрифта больше, чем область в которую он должен быть выведен,
    то ничего выведено не будет.

  Если все прошло успешно, метод возвращает высоту текста в логич. единицах
  Если нет, то - ноль

Ну вот, почти всю информацию относительно DrawText вы получили. Осталось только упомянуть о нескольких важных моментах.

В документации сказано, что вызов DrawText обязательно должен осуществляться внутри методов BeginScene и EndScene ( они относятся к Direct3DDevice ). Если проигнорировать это утверждение, то якобы нас ожидает кара небесная. Использовав DrawText без этих методов ничего страшного я не обнаружил. Также у самого D3DXFont имеются методы Begin и End. Они тоже призваны служить обрамляющими DrawText. Т.е вызов отрисовки текста должен проходит опять таки между ними. Но и без этих методов все прекрасно работает. Далее решайте сами использовать их или нет.

Второй важный момент заключается в использовании флага DT_NOCLIP. Используйте его всегда! Лучше заранее подсчитать входит текст в прямоугольник или нет, чем ждать от Direct3D что он обрежет слова. Использование этого флага РЕАЛЬНО повышает скорость прорисовки.

Еще очень важно НЕ использовать шрифты больших размеров, чем больше размер тем дольше все отрисовывается. У меня с увеличением размера букв происходило падение fps и довольно заметно. Ну и соответственно это количество выводимого, если его много, тогда опять все тормозней и т.д. и т.п.

Стоит упомянуть и про потерю устройства, которую мы рассматривали в одном из предыдущих уроков. При сбрасывании устройства нам нужно восстанавливать все данные и о шрифтах. Делается это двумя методами OnLostDevice и OnResetDevice. Вызывать их нужно при каждой потере устройства.

Справка

  OnLostDevice и OnResetDevice ничего не передается. 
  При удачном завершении возвращается 0. При ошибке D3DERR_INVALIDCALL

  Примечание
  ----------
  В системе Windows 2000 порядок вызова данных методов должен быть следующим:

  1. d3dxfont8  OnLostDevice, pd3dFont
  2. d3dev8     Reset, pd3dDevice, ADDR d3dpp.BackBufferWidth
  3. d3dxfont8  OnResetDevice, pd3dFont

  Системы 98 и XP более лояльны и вполне переваривают такой порядок:

  1. d3dev8     Reset, pd3dDevice, ADDR d3dpp.BackBufferWidth
  2. d3dxfont8  OnLostDevice, pd3dFont
  3. d3dxfont8  OnResetDevice, pd3dFont
  
  Если вы будете использовать несколько шрифтов в свое программе, то при
  Потере устройства достаточно вызвать OnLostDevice и OnResetDevice только
  для самого первого. Все остальные шрифты будут восстановлены автоматически.

Теперь о цвете шрифта. Он используется в формате ARGB, где буква A - альфа или прозрачность. Чем больше альфа тем непрозрачнее текст. Когда я впервые пытался отрисовать текст и ничего на экране не увидел, то не сразу сообразил в чем дело ( альфа была в ноль и соответственно текст абсолютно прозрачен ). Не повторяйте мою ошибку, всегда проверяйте значение альфа.

Ну и на последок, как я и обещал выше, поговорим о преимуществах и недостатках.

Преимущества:
С помощью данного метода можно легко и быстро вывести информацию с подчеркиванием нужных букв, выравниванием, а также многострочный текст одним махом. Даже хоть справа налево по - арабски.

Недостатки:
Не является слишком быстрым и расторопным. Нельзя напрямую указать координаты вывода, только посредством структуры типа RECT ( приходится ее все время модифицировать для вывода текста в различных местах ).

Вывод:
Подходит только для простого отображения не слишком большого количества текста.

В качестве примера даже придумывать нечего, я попробовал его хоть как-то поинтересней сделать. Что из этого получилось, судить вам. Скачивайте и смотрите непосредственно в действии. На этом спешу с вами попрощаться.

Да ! Чуть было не забыл, теперь стабильность работы всех примеров, начиная с этого урока проверяется в системах Windows 98, 2000 SP3, XP и под DirectX 8.1 и 9.0. Надеюсь, никаких проблем у вас при запуске примеров возникнуть не должно, как было ранее в Win2k.

PS:
В следующий раз будет рассмотрено использование стандартных обьектов типа куб, сфера, цилиндр и т.д.

Как всегда исходник прилагается.

Все вопросы мыльте сюда mybox@aib.ru

2002-2013 (c) wasm.ru