the line inside the loop reads a character from our file and stores it in the texture buffer at our current pointer location. If our image has 4 bytes per pixel, the first 3 bytes will be read from the .RAW file (format-1), and the 4th byte will be manually set to 255. After we set the 4th byte to 255 we increase the pointer location by one so that our 4th byte is not overwritten with the next byte in the file.
After a all of the bytes have been read in per pixel, and all of the pixels have been read in per row, and all of the rows have been read in, we are done! We can close the file.
for (k = 0 ; k < buffer->format-1 ; k++, p++, done++) {
*p = fgetc(f); // Read Value From File And Store In Memory
}
*p = 255; p++; // Store 255 In Alpha Channel And Increase Pointer
}
}
fclose(f); // Close The File
}
If there was a problem opening the file (does not exist, etc), the code below will pop up a message box letting the user know that the file could not be opened.
The last thing we do is return done. If the file couldn't be opened, done will equal 0. If everything went ok, done should equal the number of bytes read from the file. Remember, we were increasing done every time we read a byte in the loop above (k loop).
else // Otherwise
{
MessageBox(NULL, "Unable To Open Image File", "IMAGE ERROR", MB_OK | MB_ICONINFORMATION);
}
return done; // Returns Number Of Bytes Read In
}
This shouldn't need explaining. By now you should know how to build a texture. tex is the pointer to the TEXTURE_IMAGE structure that we want to use. We build a linear filtered texture. In this example, we're building mipmaps (smoother looking). We pass the width, height and data just like we would if we were using glaux, but this time we get the information from the selected TEXTURE_IMAGE structure.
void BuildTexture (P_TEXTURE_IMAGE tex) {
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, tex->width, tex->height, GL_RGBA, GL_UNSIGNED_BYTE, tex->data);
}
Now for the blitter code :) The blitter code is very powerful. It lets you copy any section of a (src) texture and paste it into a destination (dst) texture. You can combine as many textures as you want, you can set the alpha value used for blending, and you can select whether the two images blend together or cancel eachother out.
src is the TEXTURE_IMAGE structure to use as the source image. dst is the TEXTURE_IMAGE structure to use for the destination image. src_xstart is where you want to start copying from on the x axis of the source image. src_ystart is where you want to start copying from on the y axis of the source image. src_width is the width in pixels of the area you want to copy from the source image. src_height is the height in pixels of the area you want to copy from the source image. dst_xstart and dst_ystart is where you want to place the copied pixels from the source image onto the destination image. If blend is 1, the two images will be blended. alpha sets how tranparent the copied image will be when it mapped onto the destination image. 0 is completely clear, and 255 is solid.
We set up all our misc loop variables, along with pointers for our source image (s) and destination image (d). We check to see if the alpha value is within range. If not, we clamp it. We do the same for the blend value. If it's not 0-off or 1-on, we clamp it.
void Blit(P_TEXTURE_IMAGE src, P_TEXTURE_IMAGE dst, int src_xstart, int src_ystart, int src_width, int src_height, int dst_xstart, int dst_ystart, int blend, int alpha) {
int i,j,k;
unsigned char *s, *d; // Source & Destination
// Clamp Alpha If Value Is Out Of Range
if (alpha > 255) alpha = 255;
if (alpha < 0) alpha = 0;
// Check For Incorrect Blend Flag Values
if (blend > 1) blend = 1;
Now we have to set up the pointers. The destination pointer is the location of the destination data plus the starting location on the destination images y axis (dst_ystart) * the destination images width in pixels * the destination images bytes per pixel (format). This should give us the starting row for our destination image.
We do pretty much the same thing for the source pointer. The source pointer is the location of the source data plus the starting location on the source images y axis (src_ystart) * the source images width in pixels * the source images bytes per pixel (format). This should give us the starting row for our source image.
i loops from 0 to src_height which is the number of pixels to copy up and down from the source image.
d = dst->data + (dst_ystart * dst->width * dst->format); // Start Row – dst (Row * Width In Pixels * Bytes Per Pixel)
s = src->data + (src_ystart * src->width * src->format); // Start Row – src (Row * Width In Pixels * Bytes Per Pixel)
for (i = 0; i < src_height ; i++) // Height Loop
{
We already set the source and destination pointers to the correct rows in each image. Now we have to move to the correct location from left to right in each image before we can start blitting the data. We increase the location of the source pointer (s) by src_xstart which is the starting location on the x axis of the source image times the source images bytes per pixel. This moves the source (s) pointer to the starting pixel location on the x axis (from left to right) on the source image.
We do the exact same thing for the destination pointer. We increase the location of the destination pointer (d) by dst_xstart which is the starting location on the x axis of the destination image multiplied by the destination images bytes per pixel (format). This moves the destination (d) pointer to the starting pixel location on the x axis (from left to right) on the destination image.
After we have calculated where in memory we want to grab our pixels from (s) and where we want to move them to (d), we start the j loop. We'll use the j loop to travel from left to right through the source image.
s = s + (src_xstart * src->format); // Move Through Src Data By Bytes Per Pixel
d = d + (dst_xstart * dst->format); // Move Through Dst Data By Bytes Per Pixel
for (j = 0 ; j < src_width ; j++ ) // Width Loop
{
The k loop is used to go through all the bytes per pixel. Notice as k increases, our pointers for the source and destination images also increase.
Inside the loop we check to see if blending is on or off. If blend is 1, meaning we should blend, we do some fancy math to calculate the color of our blended pixels. The destination value (d) will equal our source value (s) multiplied by our alpha value + our current destination value (d) times 255 minus the alpha value. The shift operator (>>8) keeps the value in a 0-255 range.
If blending is disabled (0), we copy the data from the source image directly into the destination image. No blending is done and the alpha value is ignored.
for (k = 0; k < src->format ; k++, d++, s++) // "n" Bytes At A Time
{
if (blend) // If Blending Is On
*d = ( (*s * alpha) + (*d * (255-alpha)) )>> 8; // Multiply Src Data*alpha Add Dst Data*(255-alpha)