|

OpenGL/ FPC - Chapter 18 - by Delax
Last time I showed you the basics of texture mapping. This time I will go deeper into the fine detail. I decided against just showing you how to load .bmp or .jpg images and rather explain again how texture mapping in OpenGL really works. But this time with some working examples.
The textures in our exmples will be generated at runtime and not loaded from picture files. But basically it's the same principle: define a pointer and fill it with pixel information. Then just load it up and that's it. Only that generated textures are created by some algorithm - and therefor are also called mathematical textures sometimes. With pictures you have the pixel information stored in some graphics format. This pixel information is read out and stored into the texture pointer.
So why would someone use mathematical textures? Well, first off there are size considerations. Democoders use generated textures for intros as they are taking up virtually no space at all - just one procedure/ function. The second reason is quality. With a picture you only got the picture. If you zoom in, the picture stays that way and only gets more pixelled. With mathematical textures you can zoom in as much as you want - all you would have to do is increase the output of the algorithm and reload the texture.
So let's start by defining the needed variables again. As explained last time we need one ID for the texture and one pointer to the actual content.
TextureID : GLuint;
TextureData : pByte;
Now we get a little space for our texture. This time we want a texture with 128 pixels wide and 128 pixels in height. With 3 bytes per color (RGB), we get the needed space for our texture by multiplying these values.
GetMem(TextureData, 128*128*3); // make room for a 128x128 RGB texture
Now we have the needed space for our texture. But of course there is nothing in it yet. So we fill it up with a solid color. As we have chosen RGB, 3 Bytes make up one pixel. The first byte is the value for red, the second for green and the third for blue. And as we defined the pointer as pByte, the maximum range of a color would be from 0 (black) to 255 (maximum color).
A solid color is quite easy. In this example we just set the first of the 3 colors to the maximum and the rest to 0. So we get something like this.
for i := 0 to 128*128*3 do begin
TextureData[i] := 255;
TextureData[i+1] := 0;
TextureData[i+2] := 0;
i += 2;
end;
Now we initialize the texture and load it up as shown in the last chapter.
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);
Get the example here. Take a look at the filling of the texture data and play around with it.
At this point, we could clear the pointer. Why? We have loaded the content of the pointer into the OpenGL system, and therefor (hopefully) into the memory of the graphics card. So why don't we do it? Because as said mathematical textures have the advantage that you can change their appearance by changing the algorithm. If we would delete the pointer we'd have to create it again and fill it up instead of just changing it. So we would waste cpu power. Of course with normal pictures loaded from files we would delete the pointer of course.
Now the oldschool-people will see one cool thing: we can write to a texture just like to a virtual screen. We could actually do animation on a texture! All we need would be some kind of putpixel routine like this one.
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;
Here is some little example of what I mean. Just to blurt out the drawback before you start writing animations to textures this way: it's slow. As a matter of fact too slow to do all this cool stuff you just thought about ;). But don't worry - there are ways to do all this stuff.
Now that we now all the basics I'll show you how to load Bitmaps from resources in the next chapter. Note that I will only explain how to load resources and NOT how to read out external bitmaps as it should be perfectly obvious. Read out the pixel information from the respective graphics format and store them into a pointer. If you are not experienced with file formats, there are many libs and units that will help you with that. Just look at the FreePascal website for contributed units.
Delax/ Sundancer Inc.
[delax@sundancerinc.de]
Back to previous page
|