Книги

OpenGL / FPC - Глава 18

В прошлый раз я рассказал вам основы текстурного отображения. Сейчас я продолжу, уже углубляясь в детали. Мне кажется, что вместо того, чтобы рассказать, как подгружать файлы .bmp или .jpg, лучше объяснить еще раз, как работает текстурное отображение в OpenGL. На этот раз снабдив вас работающими примерами.

Текстуры в наших примерах будут генерироваться в процессе выполнения программы, а не загружаться из внешних файлов. Однако основные принципы одинаковы: определите указатель и заполните его данными о пикселях. После этого грузите их в OpenGL — и все. Отличие только в том, что сгенерированные текстуры создаются по какому-то алгоритму, и их, следовательно, также иногда называют математическими текстурами. При работе с картинками информация о пикселях хранится в некотором графическом формате. Она считывается и передается по указателю на текстуру.

Так зачем же использовать математические текстуры? Во-первых — из соображений размера изображения. Democoders используют сгенерированные текстуры в intro, так как те не занимают никакого места — только лишь одна процедура/функция. Вторая причина — качество. При использовании рисунка у вас есть только этот рисунок. Если приблизиться, картинка остается неизменной, и только выглядит более зернисто. А вот при использовании математических текстур можно приближаться сколь угодно близко: все, что потребуется сделать — это увеличить выход данных алгоритма и перезагрузить текстуру.

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

  TextureID : GLuint;
  TextureData : pByte;

Теперь зарезервируем немного места для нашей текстуры. На этот раз хотим текстуру с 128 пикселями в ширину и 128 пикселями в высоту. Используя 3 байта для задания цвета (RGB), найдем требуемый размер памяти, перемножив эти числа.

 GetMem(TextureData, 128*128*3); // make room for a 128x128 RGB texture

Теперь место под нашу текстуру отведено. Но, конечно же, там ничего нету. Давайте заполним его сплошным цветом. Поскольку выбрана модель RGB, один пиксель задается тремя байтами. Первый — значение красного цвета, второй — зеленого, третий — красного. Указатель определен как pByte, так что диапазон для цвета — от 0 (нет цвета) до 255 (максимальное количество цвета).

Сплошной цвет — это довольно просто. В нашем примере мы установим первый из трех цветов в максимум, а остальные — в 0. То есть у нас будет что-то вроде этого.

  i := 0;
  while i < 128*128*3 do
   begin
    TextureData[i] := 255;
    TextureData[i+1] := 0;
    TextureData[i+2] := 0;
    i := i + 3;
   end;

Теперь инициализируем текстуру и подгрузим ее так, как делалось в прошлой главе.

 glEnable(GL_TEXTURE_2D);
  glGenTextures(1, @TextureID);
  glBindTexture(GL_TEXTURE_2D, TextureID);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, 128, 128, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureData);
 glBindTexture(GL_TEXTURE_2D, TextureID);

Возьмите исходник примера. Ознакомьтесь с заполнением данных текстуры, попробуйте что-нибудь свое.

С этого момента, мы можем очистить указатель. Почему? Мы подгрузили содержимое памяти с этого адреса в систему OpenGL, и, следовательно, (надеюсь, что так) в память видеокарты. Так почему же мы не делаем это? А потому, что, как было сказано, математические текстуры имеют преимущество в том, что можно менять их внешний вид путем изменения алгоритма. Если удалить указатель, то потом придется создавать его снова и опять заполнять память по новому адресу, вместо того, чтобы просто ее изменить. То есть часть мощности cpu будет расходоваться впустую. Конечно, при загрузке изображений из файлов, указатель может быть удален.

А теперь воспитанники старой школы могут углядеть вот что: в текстуру можно писать так же, как и в виртуальный экран. В ней, в сущности, можно осуществлять анимацию! Все, что нам нужно — это что-нибудь наподобие процедуры putpixel, например, вот это.

procedure TexPutPixel(TexTarget : pByte; 
 iTexX, iTexY : Longint; iTexColorR, iTexColorG, iTexColorB : Byte);
var
	iTemp : Longint;
begin
 // do primitive clipping. No values <> size of texture are allowed
   if (iTexX<0) or (iTexX>128) or (iTexY<0) or (iTexY>128) then exit;
 iTemp := (iTexX*3) + (iTexY*128*3);
 (TexTarget + iTemp + 0)^ := iTexColorR;
 (TexTarget + iTemp + 1)^ := iTexColorG;
 (TexTarget + iTemp + 2)^ := iTexColorB;
end;

Здесь лежит небольшой пример того, что я имею ввиду. Скажу лишь по секрету о препятствии, прежде чем вы кинетесь программировать анимацию с помощью текстур: это тормозит. Фактически тормозит настолько сильно, что лишает этот прием всей его прелести. Но не волнуйтесь — существуют другие способы проделывать это.

Теперь, когда вы знакомы с основами, можно уже показать, как подгружать растры из ресурсов, что делается в следующей главе. Обратите внимание, что я объясню то, как подгружать ресурсы, а не то, как считывать внешние растровые изображения, поскольку последнее совсем очевидно. Считывайте информацию о пикселе из файла соответствующего графического формата и передавайте ее по указателю. Если вы не слишком сведущи в форматах графических файлов, то существует множество библиотек и модулей, которые могут в этом помочь. Просто зайдите на сайт FreePascal и поищите такие модули.

Актуальные версии
FPC3.2.2release
Lazarus3.2release
MSE5.10.0release
fpGUI1.4.1release
links