Разработка программы начинается с создания оболочки
Создайте окно программы и разместите на ней элемент openglsimplecontrol, как показано на рисунке 1, после чего установите его размеры 500х500. Переименуйте данный объект, дав ему имя AnT.Рисунок 1. Окно создаваемой программы.
Также не забудьте установить ссылки на используемые библиотеки Tao (рис. 2). Обратите внимание на ссылку на Tao.DevIL - данная библиотека необходима нам для загрузки текстур (и не забудьте using Tao.DevIl; иначе вы не сможете работать с данной библиотекой) .
Рисунок 2. Подключение библиотек Tao.
Для реализации визуализации будет использоваться таймер – после инициализации окна он будет генерировать событие, называемое тиком таймера раз в 30 миллисекунд. Добавьте элемент таймер, переименуйте экземпляр в RenderTimer и установите время тика 30 миллисекунд (как показано на рисунке 3), а также добавьте ему событие для обработки тика.
Рисунок 3. Настройка таймера.
Также необходимо добавить меню для выбора файлов. Для этого добавьте новое меню на форму, объект openFileDialog. В свойствах объекта openFileDialog установите параметр Filter равным «JPG files|*.jpg|All files|*.*».
Рисунок 4. Создание меню.
Инициализация OpenGl происходит как обычно, следует отметить только дополнительную инициализация библиотеки openIL. Нам потребуется объявить ряд переменных для дальнейшей работы программы:
/*http://esate.ru, Anvi*/
// ряд вспомогательных переменных
// поворот
private int rot = 0;
// флаг - загружена ли текстура
private bool textureIsLoad = false;
// имя текстуры
public string texture_name = "";
// идентификатор текстуры
public int imageId = 0;
// текстурный объект
public uint mGlTextureObject = 0;
// событие загрузки формы
private void Form1_Load( object sender, EventArgs e)
{
// инициализация библиотеки glut
Glut.glutInit();
// инициализация режима экрана
Glut.glutInitDisplayMode( Glut.GLUT_RGB | Glut.GLUT_DOUBLE);
// инициализация библиотеки openIL
Il.ilInit();
Il.ilEnable( Il.IL_ORIGIN_SET);
// установка цвета очистки экрана (RGBA)
Gl.glClearColor(255, 255, 255, 1);
// установка порта вывода
Gl.glViewport(0, 0, AnT.Width, AnT.Height);
// активация проекционной матрицы
Gl.glMatrixMode( Gl.GL_PROJECTION);
// очистка матрицы
Gl.glLoadIdentity();
// установка перспективы
Glu.gluPerspective(30, AnT.Width / AnT.Height, 1, 100);
// установка объектно-видовой матрицы
Gl.glMatrixMode( Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
// начальные настройки OpenGL
Gl.glEnable( Gl.GL_DEPTH_TEST);
Gl.glEnable( Gl.GL_LIGHTING);
Gl.glEnable( Gl.GL_LIGHT0);
// активация таймера
RenderTimer.Start();
}
Теперь рассмотрим процесс загрузки текстуры. Для этого мы реализуем две функции – первая выполняется как обработка события активации меню, размещенного на нашей форме. Получив имя текстуры мы проведем начальную подготовку к загрузке текстуры в память графического адаптера. В дальнейшем мы выполним дополнительные настройки текстуры, после которых сразу же увидим результат.
/*http://esate.ru, Anvi*/
// обработка пункта меню загрузки изображения
private void loadImageToolStripMenuItem_Click( object sender, EventArgs e)
{
// открываем окно выбора файла
DialogResult res = openFileDialog1.ShowDialog(); // если файл выбран - и возвращен результат OK
if (res == DialogResult.OK)
{
// создаем изображение с идентификатором imageId
Il.ilGenImages(1, out imageId);
// делаем изображение текущим
Il.ilBindImage(imageId);
// адрес изображения полученный с помощью окна выбора файла
string url = openFileDialog1.FileName;
// пробуем загрузить изображение
if ( Il.ilLoadImage(url))
{
// если загрузка прошла успешно
// сохраняем размеры изображения
int width = Il.ilGetInteger( Il.IL_IMAGE_WIDTH);
int height = Il.ilGetInteger( Il.IL_IMAGE_HEIGHT);
// определяем число бит на пиксель
int bitspp = Il.ilGetInteger( Il.IL_IMAGE_BITS_PER_PIXEL);
switch (bitspp) // в зависимости от полученного результата
{
// создаем текстуру, используя режим GL_RGB или GL_RGBA
case 24:
mGlTextureObject = MakeGlTexture( Gl.GL_RGB, Il.ilGetData(), width, height);
break ;
case 32:
mGlTextureObject = MakeGlTexture( Gl.GL_RGBA, Il.ilGetData(), width, height);
break ;
}
// активируем флаг, сигнализирующий загрузку текстуры
textureIsLoad = true ;
// очищаем память
Il.ilDeleteImages(1, ref imageId);
}
}
}
// создание текстуры в памяти openGL
private static uint MakeGlTexture( int Format, IntPtr pixels, int w, int h)
{
// идентификатор текстурного объекта
uint texObject;
// генерируем текстурный объект
Gl.glGenTextures(1, out texObject);
// устанавливаем режим упаковки пикселей
Gl.glPixelStorei( Gl.GL_UNPACK_ALIGNMENT, 1);
// создаем привязку к только что созданной текстуре
Gl.glBindTexture( Gl.GL_TEXTURE_2D, texObject);
// устанавливаем режим фильтрации и повторения текстуры
Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
Gl.glTexEnvf( Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, Gl.GL_REPLACE);
// создаем RGB или RGBA текстуру
switch (Format)
{
case Gl.GL_RGB:
Gl.glTexImage2D( Gl.GL_TEXTURE_2D, 0, Gl.GL_RGB, w, h, 0, Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, pixels);
break;
case Gl.GL_RGBA:
Gl.glTexImage2D( Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, w, h, 0, Gl.GL_RGBA, Gl.GL_UNSIGNED_BYTE, pixels);
break;
}
// возвращаем идентификатор текстурного объекта
return texObject;
}
Теперь остается обработать событие отклика таймера и реализовать функцию визуализации сцены. При визуализации текстуры нам необходимо включить режим текстурирования, а также при выводе вершин объектов привязывать к ним текстурные координаты, в соответствии с которыми произойдет наложение текстуры.
/*http://esate.ru, Anvi*/
// отклик таймера
private void RenderTimer_Tick( object sender, EventArgs e)
{
// вызов функции отрисовки сцены
Draw();
}
// функция отрисовки
private void Draw()
{
// если текстура загружена
if (textureIsLoad)
{
// увеличиваем угол поворота
rot++;
// корректируем угол
if (rot > 360)
rot = 0;
// очистка буфера цвета и буфера глубины
Gl.glClear( Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
Gl.glClearColor(255, 255, 255, 1);
// очищение текущей матрицы
Gl.glLoadIdentity();
// включаем режим текстурирования
Gl.glEnable( Gl.GL_TEXTURE_2D);
// включаем режим текстурирования, указывая идентификатор mGlTextureObject
Gl.glBindTexture( Gl.GL_TEXTURE_2D, mGlTextureObject);
// сохраняем состояние матрицы
Gl.glPushMatrix();
// выполняем перемещение для более наглядного представления сцены
Gl.glTranslated(0, -1, -5);
// реализуем поворот объекта
Gl.glRotated(rot, 0, 1, 0);
// отрисовываем полигон
Gl.glBegin( Gl.GL_QUADS);
// указываем поочередно вершины и текстурные координаты
Gl.glVertex3d(1, 1, 0);
Gl.glTexCoord2f(0, 0);
Gl.glVertex3d(1, 0, 0);
Gl.glTexCoord2f(1, 0);
Gl.glVertex3d(0, 0, 0);
Gl.glTexCoord2f(1, 1);
Gl.glVertex3d(0, 1, 0);
Gl.glTexCoord2f(0, 1);
// завершаем отрисовку
Gl.glEnd();
// возвращаем матрицу
Gl.glPopMatrix();
// отключаем режим текстурирования
Gl.glDisable( Gl.GL_TEXTURE_2D);
// обновляем элемент со сценой
AnT.Invalidate();
}
}
Результат работы программы - вращающаяся плоскость с изображением текстуры.
Рисунок 5. Результат работы программы.
Примечания
В случае возникновения ошибки: Unable to find an entry point named 'ilInit' in DLL 'DevIL.dll'. или подобных:- Перейдите: Мой компьютер -> Свойства -> Дополнительные параметры системы -> Переменные среды...
- В списках системных переменных выберите Path, нажмите «Изменить...»
- Поставьте в конце ; (точку с запятой) и затем добавь путь к TaoFramework\bin, например, C:\Program Files (x86)\TaoFramework\bin;, а также к TaoFramework\lib (путь полностью).