Рисование подразделений

Все эти классы великолепны, но как насчет визуализации? Если вы откроете файл main.cpp из проекта D3DFrame_UnitTemplate, я покажу вам! Спускайтесь вниз до функции vInitTileVB().

Вы, возможно, еще помните пример визуализации блоков, который я демонстрировал в главе 5. Там я создавал отдельный буфер вершин для хранения геометрии текстуры. Базовая точка геометрии находилась в левом нижнем углу квадрата. Это упрощает выравнивание квадратов при визуализации блоков, но не слишком подходит для поворотов.
Итак, какое отношение это имеет к моему примеру? Основной момент заключается в том, что вам необходимо иметь два буффера для геометрии: один для блоков игрового поля и один для подразделений. Чтобы создать квадрат, базовая точка которого находится в центре, вы должны создать вершины вокруг центра. Вот как выглядит код для этого:

// Создание вершин
pVertices[0].position = D3DXVECTOR3(-0.5f, -0.5f, 0.0f);
pVertices[0].tu = 0.0f;
pVertices[0].tv = 1.0f;
pVertices[0].vecNorm = D3DXVECTOR3(0.0f,0.0f,1.0f);
pVertices[1].position = D3DXVECTOR3(-0.5f, 0.5f, 0.0f);
pVertices[1].tu = 0.0f;
pVertices[1].tv = 0.0f;
pVertices[1].vecNorm = D3DXVECTOR3(0.0f,0.0f,1.0f);
pVertices[2].position = D3DXVECTOR3(0.5f, -0.5f, 0.0f);
pVertices[2].tu = 1.0f;
pVertices[2].tv = 1.0f;
pVertices[2].vecNorm = D3DXVECTOR3(0.0f,0.0f,1.0f);
pVertices[3].position = D3DXVECTOR3(0.5f, 0.5f, 0.0f);
pVertices[3].tu = 1.0f;
pVertices[3].tv = 0.0f;
pVertices[3].vecNorm = D3DXVECTOR3(0.0f,0.0f,1.0f);

Код создает четыре вершины — по одной для каждого из углов квадрата.
Функция vDrawUnit()
Теперь, когда у вас есть буфер вершин для подразделения, необходимо место для выполнения визуализации. Здесь выходит на сцену функция рисования подразделения. Она работает точно так же, как функция рисования блока игрового поля, которую я показывал в главе 5, за исключением некоторых добавленных функций. Вот ее код:

void CD3DFramework::vDrawUnit(
float fXPos,
float fYPos,
float fXSize,
float fYSize,
float fRot,
CUnitAnimation *animObj,
int iTexture,
int iOwner)
{
D3DXMATRIX matWorld;
D3DXMATRIX matRotation;
D3DXMATRIX matTranslation;
D3DXMATRIX matScale;

// Установка значений по умолчанию для
// местоположения, масштабирования и вращения
D3DXMatrixIdentity(&matTranslation);
// Масштабирование блока
D3DXMatrixScaling(&matScale, fXSize, fYSize, 1.0f);
D3DXMatrixMultiply(&matTranslation,&matTranslation,&matScale);
// Вращение блока
D3DXMatrixRotationZ(&matRotation, (float)DegToRad(-fRot));
D3DXMatrixMultiply(&matWorld, &matTranslation, &matRotation);
// Перемещение блока
matWorld._41 = fXPos - 0.5f; // X-Pos
matWorld._42 = fYPos + 0.5f; // Y-Pos
// Установка матрицы
m_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);
// Используем буфер вершин блока
m_pd3dDevice->SetStreamSource(
0, m_pVBUnit,
0, sizeof(TILEVERTEX));
// Используем фрмат вершин блока
m_pd3dDevice->SetFVF(D3DFVF_TILEVERTEX);
// Задаем используемую текстуру
m_pd3dDevice->SetTexture(
0, animObj->m_Textures[iTexture].m_pTexture);
// Отображаем квадрат
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
// Задаем используемую текстуру
m_pd3dDevice->SetTexture(
0, animObj->m_Textures[iTexture + iOwner + 1].m_pTexture);
// Отображаем квадрат
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
// Разыменовываем текстуру
m_pd3dDevice->SetTexture(0, NULL);
}

Первое отличие данной функции от ранее рассмотренной vDrawTile() — добавление параметра вращения. Он позволяет вам развернуть двухмерное изображение на любой необходимый угол. Само вращение реализуется перемножением матриц поворота и преобразования. Матрица поворота создается вспомогательной функцией DirectX D3DXMatrixRotationZ().

Следующее отличие рассматриваемой функции заключается в том, что я использую буфер вершин m_pVBUnit вместо буфера m_pVBTile. Это сделано для того, чтобы базовая точка располагалась в центре, о чем я говорил ранее.

Самое большое отличие данной функции — добавление параметра CUnitAnimation. Он сообщает функции откуда она должна брать текстуры. Указатель на класс анимации необходим потому, что именно в нем хранятся используемые для визуализации текстуры.

Я задаю используемую для визуализации текстуру путем передачи в функцию параметра, указывающего ее местоположение во внутреннем массиве класса анимации. В результате отображается базовое изображение подразделения. В следующием вызове функции визуализации изменена позиция в массиве для того, чтобы отображались цвета владельца. Если вы помните, раньше я говорил о том, что цвета владельца хранятся следом за кадром анимации. Данные о цветах накладываются на базовое изображение подразделения, чтобы в результате отображалось изображение подразделения, раскрашенного в цвета его владельца.

Функция vRender()
Сейчас у вас есть буфер вершин для подразделения и функция, помогающая при визуализации. Белым пятном остается место, где создается изображение каждого кадра. Встречайте старого знакомого — функцию vRender().

Функция визуализации в программе D3DFrame_UnitTemplate работает во многом так же, как и одноименная функция из программы D3DFrame_2DTiles. В первой части выполняется визуализация карты посредством цикла, в котором перебираются и отображаются отдельные блоки карты. На этом подобие заканчивается.

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

// Включение прозрачности
m_pd3dDevice->SetRenderState(
D3DRS_ALPHABLENDENABLE,
TRUE);
m_pd3dDevice->SetRenderState(
D3DRS_SRCBLEND,
D3DBLEND_SRCALPHA);
m_pd3dDevice->SetRenderState(
D3DRS_DESTBLEND,
D3DBLEND_INVSRCALPHA);

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