Сетка загружается из ресурсов программы. Структура resinfo идентифицирует элемент ресурсов, содержащий сетку. Для загрузки сетки, как обычно, используется функция Load() интерфейса Direct3DRMMeshBuilder. После загрузки сетка масштабируется функцией RMWin::ScaleMesh().
На втором этапе создается анимационная последовательность, использующаяся для анимации сетки цели:
Сначала для инициализации экземпляра интерфейса Direct3DRMAnimation вызывается функция CreateAnimation() интерфейса Direct3DRM. Затем вызывается функция SetOptions() интерфейса Direct3DRMAnimation,которой передается три флага. Флаг D3DRMANIMATION_SPLINEPOSITION указывает, что при расчете анимационной последовательности будут применяться сплайны. Флаг D3DRMANIMATION_CLOSED позволяет использовать непрерывно увеличивающиеся значения временных меток для повторного выполнения анимационной последовательности. Флаг D3DRMANIMATION_POSITION указывает объекту анимации, что нас интересует изменение местоположения анимируемого фрейма. Обратите внимание, что флаг D3DRMANIMATION_SCALEANDROTATION отсутствует (мы использовали его в приложении Rocket). Благодаря этому объект анимации не выполняет вычисления для изменения ориентации и масштаба, что позволяет анимационной последовательности выполняться быстрее.
Оставшаяся часть кода, относящегося ко второму этапу работы функции представляет собой несколько вызовов функции AddPositionKey() интерфейса Direct3DRMAnimation. Когда мы создавали анимационную последовательность в приложении Rocket, то использовали цикл для добавления ключей, которые были определены в элементах массива. В приложении Target не используется ни цикл ни массив. Каждый ключ добавляется с помощью отдельного вызова функции AddPositionKey(). Также, как и в приложении Rocket, используемые для анимационной последовательности позиции выбраны экспериментальным путем.
На следующем этапе выполняется создание фрейма для размещения и анимации сетки цели:
Сначала для инициализации локального указателя targetframe используется функция CreateFrame() интерфейса Direct3DRM. Затем указатель на новый фрейм используется в качестве аргумента функции SetFrame() интерфейса Direct3DRMAnimation.
Этот вызов функции связывает фрейм с анимационной последовательностью, после чего местоположение фрейма контролируется объектом анимации.
Функция AddVisual() интерфейса Direct3DRMFrame используется чтобы присоединить к фрейму сетку цели. Затем с помощью функции AddMoveCallback() интерфейса Direct3DRMFrame устанавливается функция обратного вызова MoveTarget(). Обратите внимание, что в качестве второго аргумента функции AddMoveCallback() передается указатель animation. Это обеспечивает возможность доступа к объекту анимации для функции обратного вызова. В заключение, освобождается указатель targetbuilder (который был инициализирован на первом этапе).
СОВЕТ
Нарушение соглашений COM. Обычно, перед завершением функции освобождаются все локальные указатели на интерфейсы Direct3D. В приложении Target мы видим два исключения из этого правила. Указатели animation и targetframe не освобождаются, поскольку используются в функциях обратного вызова. Освобождение этих указателей приведет к тому, что COM уничтожит соответствующие объекты, и обращение к функции обратного вызова приведет к краху программы.
Другое возможное решение — оставить вызов функции Release(), но только после вызова функции AddRef(). Благодаря этому COM получает уведомление о создании дополнительной ссылки на объект. Согласно спецификации COM второй метод предпочтительнее. Мы используем первый метод только для того, чтобы сделать код приложения как можно более простым.
На четвертом этапе загружается сетка, изображающая ракету:
Также как и сетка мишени, сетка ракеты хранится в ресурсах программы. После того, как сетка загружена, она окрашивается в светло-синий цвет, с помощью функции SetColorRGB() интерфейса Direct3DRMMeshBuilder.
Функция SetQuality() вызывается для того, чтобы указать Direct3D, что при визуализации сетки ракеты должен использоваться плоский метод. Потом метод визуализации можно будет изменить с помощью меню Render. И, наконец, функция ScaleMesh() используется для масштабирования размеров сетки до семи единиц.
На пятом этапе чтобы создать 15 фреймов и присоединить к каждому из них сетку ракеты, используются вложенные циклы. Также на этом этапе для каждого фрейма устанавливается функция обратного вызова:
Указатель meshframe используется при инициализации каждого фрейма. Позиция нового фрейма зависит от текущей итерации двух вложенных циклов. Затем функция AddVisual() интерфейса Direct3DRMFrame используется для присоединения к фрейму сетки ракеты. Функция AddMoveCallback() применяется для установки функции обратного вызова OrientFrame(). Обратите внимание, что в качестве второго аргумента функции AddMoveCallback() используется указатель targetframe. Это обеспечивает функции обратного вызова доступ к фрейму за которым будут следить ракеты. После вызова функции AddMoveCallback() указатель meshframe освобождается.
На шестом и седьмом этапах выполняется создание источников света и порта просмотра. Давайте воздержимся от обсуждения этих этапов, поскольку источники света и порты просмотра подробно рассматриваются в главах 6 и 9 соответственно.