Вывод графики - первые очертания
Графические ресурсы
Простите, но другого названия для раздела я придумать не смог. Согласен, что звучит довольно туманно, поэтому постараюсь все сразу объяснить. Во-первых, нам известно, что для того чтобы вывести что-нибудь на экран, в Direct3D используются вершины, индексные буферы, текстуры и т.д. Можно было пойти по пути наименьшего сопротивления и написать по классу для каждого из них. Но тогда в программе пришлось бы определять по объекту класса для каждой текстуры или буфера вершин, что бывает не совсем удобно. Поэтому волевым решением решил я ввести в движок новое понятие - индентификаторы. Что они из себя представляют?
Индентификатор - это простое целое число, типа int, которое содержит уникальный номер для каждого графического ресурса: буфер вершин, текстура, эффект и т.д. Чтобы получить индентификатор, достаточно лишь вызвать функцию загрузки ресурса, например:
idTexture = engine->LoadTexture("skin.tga");
Потом, вся дальнейшая работа с этой тестурой будет производится через ее индентификатор.
Реализация
Начал я с того, что определил шаблонный класс стека. Вообще, стек - полезная вещь в любой программе, а создание именно шаблонного класса позволит нам хранить в нем любые типы данных.
/*--------------------------------------------------------------
tStack
Шаблонный класс стека
--------------------------------------------------------------*/
template
{
public:
tStack(int size);
virtual ~tStack();
//
T PopStack(void);
void PushStack(T stackElement);
protected:
int m_size; // Размер или глубина стека
T* m_top; // Указатель на начало стека
T* m_current; // Указатель на текущий элемент стека
};
/*--------------------------------------------------------------
tStack::tStack()
Конструктор, инициализирующий стек
--------------------------------------------------------------*/
template
{
m_size = size;
m_top = m_current = new T[m_size];
};
/*--------------------------------------------------------------
tStack::~tStack()
Деструктор
--------------------------------------------------------------*/
template
{
delete[] m_top;
};
/*--------------------------------------------------------------
tStack::PopStack()
Извлечь из стека
--------------------------------------------------------------*/
template
{
if(m_current!=m_top)
m_current--;
return *m_current;
};
/*--------------------------------------------------------------
tStack::PushStack()
Занести в стек
--------------------------------------------------------------*/
template
{
if(m_current<=(m_top+m_size-1))
{
*m_current = stackElement;
m_current++;
}
else
*(m_current-1) = stackElement;
};
Как видно, класс прост до безобразия. Применим его в менджере текстур - новом классе, работающим с текстурами.
/*--------------------------------------------------------------
tTextures
Класс менеджера текстур
--------------------------------------------------------------*/
class TENGINE_DLL tTextures : virtual public tD3D
{
public:
tTextures();
virtual ~tTextures();
//
int LoadTexture(const char* name);
void SetTexture(int id,int stage);
void ReleaseTexture(int id);
protected:
LPDIRECT3DTEXTURE8 m_textures[TTEXTURESMAXCOUNT]; //
Массив текстур
tStack
};
В менеджере хранится массив из указателей на текстуры Direct3D и организован стек для динамического управления этим массивом. Как это происходит:
Для полной ясности посмотрите на реализацию функции LoadTexture():
/*--------------------------------------------------------------
tTextures::LoadTexture()
Загрузить текстуру из файла
--------------------------------------------------------------*/
int tTextures::LoadTexture(const char* name)
{
HRESULT hResult;
// Извлекаем номер индекса из стека
int id = m_indexStack->PopStack();
// Загружаем текстуру
hResult = D3DXCreateTextureFromFileEx(m_d3dDevice,
name,
D3DX_DEFAULT,D3DX_DEFAULT,D3DX_DEFAULT,
0,
D3DFMT_UNKNOWN,
D3DPOOL_MANAGED,
D3DX_DEFAULT,
D3DX_DEFAULT,
0,
NULL,
NULL,
&m_textures[id-1]);
if(hResult!=D3D_OK)
throw tError(__FILE__,__LINE__,"tTextures::LoadTexture",
"Fail
to load texture! / name - %s (%s)",name,DXGetErrorString8(hResult));
return id;
}
Структура движка
Не в первый и в непоследний раз меняется наш движок.
Как видно добавились новые классы: tTextures, tVertexBuffers, tIndexBuffers, tEffects, которые являются менеджерами соответствующих графических ресурсов, о которых говорилось в самом начале.
Пример
В качестве примера, решил я показать вывод двух квадратов. Вы уж меня простите, что я опустился до такого простейшего уровня, хотел продемострировать то, как теперь легко работать с движком.
/*--------------------------------------------------------------
Главная функция игры
--------------------------------------------------------------*/
void Main(void)
{
try
{
engine->InitRender(100,100,400,300);
//
vb1 = engine->LoadVertexBuffer(&vertices,sizeof(vertices));
effect1 = engine->LoadEffect("Base\\Effects\\first.eff");
//
engine->SetEngineThread(Render);
}
catch(tError &error)
{
error.AddErrorHistory(" <-thread
0x%x",&Main);
throw;
}
}
Во-первых, в функции Main() загружаем наши ресурсы. А в Render(), организовываем вывод.
/*--------------------------------------------------------------
Вывод
--------------------------------------------------------------*/
void Render(void)
{
engine->BeginRender();
{
SetMatrices();
engine->BeginEffect(effect1);
{
engine->PassEffect(effect1,0);
engine->SetVertexBuffer(vb1,0);
engine->DrawRender(4);
}
engine->EndEffect(effect1);
}
engine->EndRender();
}
В итоге получаем вот это: