Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

opengltexture.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002         filename:       opengltexture.cpp
00003         created:        9/4/2004
00004         author:         Mark Strom
00005                                 mwstrom@gmail.com
00006 
00007         purpose:        Interface to Texture implemented via Opengl
00008 *************************************************************************/
00009 /*************************************************************************
00010     Crazy Eddie's GUI System (http://www.cegui.org.uk)
00011     Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)
00012 
00013     This library is free software; you can redistribute it and/or
00014     modify it under the terms of the GNU Lesser General Public
00015     License as published by the Free Software Foundation; either
00016     version 2.1 of the License, or (at your option) any later version.
00017 
00018     This library is distributed in the hope that it will be useful,
00019     but WITHOUT ANY WARRANTY; without even the implied warranty of
00020     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021     Lesser General Public License for more details.
00022 
00023     You should have received a copy of the GNU Lesser General Public
00024     License along with this library; if not, write to the Free Software
00025     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026 *************************************************************************/
00027 #include "renderers/OpenGLGUIRenderer/opengltexture.h"
00028 #include "CEGUIExceptions.h"
00029 #include "CEGUISystem.h"
00030 
00031 #ifdef USE_DEVIL_LIBRARY
00032 #       include <IL/il.h>
00033 #       include <IL/ilu.h>
00034 
00035 // handle DevIL libs under MSVC
00036 #       ifdef _MSC_VER
00037 #               pragma comment (lib, "DevIL.lib")
00038 #               pragma comment (lib, "ilu.lib")
00039 #       endif
00040 
00041 #endif
00042 
00043 // Start of CEGUI namespace section
00044 namespace CEGUI
00045 {
00046 
00047 /*************************************************************************
00048         Constructor
00049 *************************************************************************/
00050 OpenGLTexture::OpenGLTexture(Renderer* owner) :
00051         Texture(owner)
00052 {
00053         // generate a OGL texture that we will use.
00054         glGenTextures(1, &d_ogltexture);
00055 
00056         // set some parameters for this texture.
00057         glBindTexture(GL_TEXTURE_2D, d_ogltexture);
00058         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00059         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00060         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 0x812F);      // GL_CLAMP_TO_EDGE
00061         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 0x812F);      // GL_CLAMP_TO_EDGE
00062         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00063 
00064 #ifdef USE_DEVIL_LIBRARY
00065         // init DevIL libs we use
00066         ilInit();
00067         iluInit();
00068 #endif
00069 }
00070 
00071 /*************************************************************************
00072         Destructor
00073 *************************************************************************/
00074 OpenGLTexture::~OpenGLTexture(void)
00075 {
00076         // delete OGL texture associated with this object.
00077         glDeleteTextures(1, &d_ogltexture);
00078 }
00079 
00080 
00081 /*************************************************************************
00082         Load texture from file.  Texture is made to be same size as image in
00083         file.
00084 *************************************************************************/
00085 void OpenGLTexture::loadFromFile(const String& filename, const String& resourceGroup)
00086 {
00087         glBindTexture(GL_TEXTURE_2D, d_ogltexture);
00088 
00089         // load file to memory via resource provider
00090         RawDataContainer texFile;
00091         System::getSingleton().getResourceProvider()->loadRawDataContainer(filename, texFile, resourceGroup);
00092 
00093 #ifndef USE_DEVIL_LIBRARY
00094         tImageTGA*      img = LoadTGA(texFile.getDataPtr(), texFile.getSize());
00095 
00096         if (img != 0)
00097         {
00098                 d_width = static_cast<ushort>(img->sizeX);
00099                 d_height = static_cast<ushort>(img->sizeY);
00100 
00101                 // flip the image...
00102                 flipImageTGA(img);
00103 
00104                 // If the image is 32-bit (4 channels), then we need to specify GL_RGBA for an alpha, else we use GL_RGB.
00105                 int textureType = (img->channels == 4) ? GL_RGBA : GL_RGB;
00106 
00107                 glTexImage2D(GL_TEXTURE_2D, 0, textureType, d_width, d_height, 0, textureType, GL_UNSIGNED_BYTE, img->data);
00108 
00109                 // Free texture data, we don't need it anymore
00110                 if (img->data)                                                  
00111                 {
00112                         delete[] img->data;
00113                 }
00114 
00115                 // Free the image structure
00116                 free(img);
00117         }
00118         else
00119         {
00120                 throw RendererException("OpenGLTexture::loadFromFile - internal Targa loader failed to load image '" + filename + "'.");
00121         }
00122 
00123 # else
00124         ILuint imgName;
00125         ilGenImages(1, &imgName);
00126         ilBindImage(imgName);
00127 
00128         if (ilLoadL(IL_TYPE_UNKNOWN, texFile.getDataPtr(), texFile.getSize()) != IL_FALSE)
00129         {
00130                 // flip the image
00131                 iluFlipImage();
00132 
00133                 // get details about size of loaded image
00134                 ILinfo imgInfo;
00135                 iluGetImageInfo(&imgInfo);
00136 
00137                 // set dimensions of texture
00138                 d_width = imgInfo.Width;
00139                 d_height = imgInfo.Height;
00140 
00141                 // allocate temp buffer to receive image data
00142                 uchar* tmpBuff = new uchar[d_width * d_height * 4];
00143 
00144                 // get image data in required format
00145                 ilCopyPixels(0, 0, 0, d_width, d_height, 1, IL_RGBA, IL_UNSIGNED_BYTE, (ILvoid*)tmpBuff);
00146 
00147                 // delete DevIL image
00148                 ilDeleteImages(1, &imgName);
00149 
00150                 // load image data into texture
00151                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, d_width, d_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tmpBuff);
00152 
00153                 // free temp buffer
00154                 delete[] tmpBuff;
00155         }
00156         // failed to load image properly.
00157         else
00158         {
00159                 // delete DevIL image
00160                 ilDeleteImages(1, &imgName);
00161 
00162                 throw RendererException("OpenGLTexture::loadFromFile - DevIL returned IL_FALSE when trying to load file '" + filename + "'.");
00163         }
00164 
00165 # endif
00166     // unload file data buffer
00167         System::getSingleton().getResourceProvider()->unloadRawDataContainer(texFile);
00168 
00169 }
00170 
00171 
00172 /*************************************************************************
00173         Load texture from raw memory.   
00174 *************************************************************************/
00175 void OpenGLTexture::loadFromMemory(const void* buffPtr, uint buffWidth, uint buffHeight)
00176 {
00177         glBindTexture(GL_TEXTURE_2D, d_ogltexture);
00178         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, buffWidth, buffHeight, 0, GL_RGBA ,GL_UNSIGNED_BYTE, buffPtr);
00179 
00180         d_width  = static_cast<ushort>(buffWidth);
00181         d_height = static_cast<ushort>(buffHeight);
00182 }
00183 
00184 
00185 /*************************************************************************
00186         allocate atexture >= 'size'.  Previous texture is lost
00187 *************************************************************************/
00188 void OpenGLTexture::setOGLTextureSize(uint size)
00189 {
00190         // if not power of 2
00191         if ((size & (size - 1)) || !size)
00192         {
00193                 int log = 0;
00194 
00195                 // get integer log of 'size' to base 2
00196                 while (size >>= 1)
00197                 {
00198                         ++log;
00199                 }
00200 
00201                 // use log to calculate value to use as size.
00202                 size = (2 << log);
00203         }
00204 
00205         // allocate temp buffer for texture
00206         uchar* buff = new uchar[size * size * 4];
00207 
00208         // load empty buffer to texture
00209         glBindTexture(GL_TEXTURE_2D, d_ogltexture);
00210         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA ,GL_UNSIGNED_BYTE, buff);
00211 
00212         // delete buffer
00213         delete[] buff;
00214 
00215         d_height = d_width = static_cast<ushort>(size);
00216 }
00217 
00218 
00220 /*************************************************************************
00221         
00222         The following are included if DevIL is not being used for image
00223         loading
00224 
00225 *************************************************************************/
00227 
00228 #ifndef USE_DEVIL_LIBRARY
00229 /*************************************************************************
00230         flips data for tImageTGA 'img'  
00231 *************************************************************************/
00232 void OpenGLTexture::flipImageTGA(OpenGLTexture::tImageTGA* img)
00233 {
00234         int pitch = img->sizeX * img->channels;
00235 
00236         // flip the image bits...
00237         for (int line = 0; line < img->sizeY / 2; ++line)
00238         {
00239                 int srcOffset = (line * pitch);
00240                 int dstOffest = ((img->sizeY - line - 1) * pitch);
00241 
00242                 for (int colBit = 0; colBit < pitch; ++colBit)
00243                 {
00244                         uchar tmp = img->data[dstOffest + colBit];
00245                         img->data[dstOffest + colBit] = img->data[srcOffset + colBit];
00246                         img->data[srcOffset + colBit] = tmp;
00247                 }
00248 
00249         }
00250 
00251 }
00252 
00253 
00262 
00263 OpenGLTexture::tImageTGA* OpenGLTexture::LoadTGA(const unsigned char* buffer, size_t buffer_size)
00264 {
00265         tImageTGA *pImageData = NULL;           // This stores our important image data
00266         short width = 0, height = 0;                    // The dimensions of the image
00267         GLbyte length = 0;                                      // The length in bytes to the pixels
00268         GLbyte imageType = 0;                                   // The image type (RLE, RGB, Alpha...)
00269 
00270         GLbyte bits = 0;                                                // The bits per pixel for the image (16, 24, 32)
00271         int channels = 0;                                       // The channels of the image (3 = RGA : 4 = RGBA)
00272         int stride = 0;                                         // The stride (channels * width)
00273         int i = 0;                                                      // A counter
00274 
00275         // This function loads in a TARGA (.TGA) file and returns its data to be
00276         // used as a texture or what have you.  This currently loads in a 16, 24
00277         // and 32-bit targa file, along with RLE compressed files.  Eventually you
00278         // will want to do more error checking to make it more robust.  This is
00279         // also a perfect start to go into a modular class for an engine.
00280         // Basically, how it works is, you read in the header information, then
00281         // move your file pointer to the pixel data.  Before reading in the pixel
00282         // data, we check to see the if it's an RLE compressed image.  This is because
00283         // we will handle it different.  If it isn't compressed, then we need another
00284         // check to see if we need to convert it from 16-bit to 24 bit.  24-bit and
00285         // 32-bit textures are very similar, so there's no need to do anything special.
00286         // We do, however, read in an extra bit for each color.
00287 
00288         // Allocate the structure that will hold our eventual image data (must free it!)
00289         pImageData = (tImageTGA*)malloc(sizeof(tImageTGA));
00290 
00291         // Read in the length in bytes from the header to the pixel data
00292         memcpy(&length, buffer, sizeof(GLbyte));
00293         buffer += sizeof(GLbyte);
00294 
00295         // Jump over one byte
00296         ++buffer;
00297 
00298         // Read in the imageType (RLE, RGB, etc...)
00299         memcpy(&imageType, buffer, sizeof(GLbyte));
00300         buffer += sizeof(GLbyte);
00301 
00302         // Skip past general information we don't care about
00303         buffer += 9;
00304 
00305         // Read the width, height and bits per pixel (16, 24 or 32)
00306         memcpy(&width, buffer, sizeof(short));
00307         buffer += sizeof(short);
00308         memcpy(&height, buffer, sizeof(short));
00309         buffer += sizeof(short);
00310         memcpy(&bits, buffer, sizeof(GLbyte));
00311         buffer += sizeof(GLbyte);
00312 
00313         // Now we move the file pointer to the pixel data
00314         buffer += length + 1;
00315 
00316         // Check if the image is RLE compressed or not
00317         if(imageType != TGA_RLE)
00318         {
00319                 // Check if the image is a 24 or 32-bit image
00320                 if(bits == 24 || bits == 32)
00321                 {
00322                         // Calculate the channels (3 or 4) - (use bits >> 3 for more speed).
00323                         // Next, we calculate the stride and allocate enough memory for the pixels.
00324                         channels = bits / 8;
00325                         stride = channels * width;
00326                         pImageData->data = new unsigned char[stride * height];
00327 
00328                         // Load in all the pixel data line by line
00329                         for(int y = 0; y < height; y++)
00330                         {
00331                                 // Store a pointer to the current line of pixels
00332                                 unsigned char *pLine = &(pImageData->data[stride * y]);
00333 
00334                                 // Read in the current line of pixels
00335                                 memcpy(pLine, buffer, stride);
00336                                 buffer += stride;
00337 
00338                                 // Go through all of the pixels and swap the B and R values since TGA
00339                                 // files are stored as BGR instead of RGB (or use GL_BGR_EXT verses GL_RGB)
00340                                 for(i = 0; i < stride; i += channels)
00341                                 {
00342                                         unsigned char temp     = pLine[i];
00343                                         pLine[i]     = pLine[i + 2];
00344                                         pLine[i + 2] = temp;
00345                                 }
00346                         }
00347                 }
00348                 // Check if the image is a 16 bit image (RGB stored in 1 unsigned short)
00349                 else if(bits == 16)
00350                 {
00351                         unsigned short pixels = 0;
00352                         unsigned char r=0, g=0, b=0;
00353 
00354                         // Since we convert 16-bit images to 24 bit, we hardcode the channels to 3.
00355                         // We then calculate the stride and allocate memory for the pixels.
00356                         channels = 3;
00357                         stride = channels * width;
00358                         pImageData->data = new unsigned char[stride * height];
00359 
00360                         // Load in all the pixel data pixel by pixel
00361                         for(int i = 0; i < width*height; i++)
00362                         {
00363                                 // Read in the current pixel
00364                                 memcpy(&pixels, buffer, sizeof(unsigned short));
00365                                 buffer += sizeof(unsigned short);
00366 
00367                                 // To convert a 16-bit pixel into an R, G, B, we need to
00368                                 // do some masking and such to isolate each color value.
00369                                 // 0x1f = 11111 in binary, so since 5 bits are reserved in
00370                                 // each unsigned short for the R, G and B, we bit shift and mask
00371                                 // to find each value.  We then bit shift up by 3 to get the full color.
00372                                 b = static_cast<unsigned char>((pixels & 0x1f) << 3);
00373                                 g = static_cast<unsigned char>(((pixels >> 5) & 0x1f) << 3);
00374                                 r = static_cast<unsigned char>(((pixels >> 10) & 0x1f) << 3);
00375 
00376                                 // This essentially assigns the color to our array and swaps the
00377                                 // B and R values at the same time.
00378                                 pImageData->data[i * 3 + 0] = r;
00379                                 pImageData->data[i * 3 + 1] = g;
00380                                 pImageData->data[i * 3 + 2] = b;
00381                         }
00382                 }       
00383                 // Else return a NULL for a bad or unsupported pixel format
00384                 else
00385                         return NULL;
00386         }
00387         // Else, it must be Run-Length Encoded (RLE)
00388         else
00389         {
00390                 // First, let me explain real quickly what RLE is.  
00391                 // For further information, check out Paul Bourke's intro article at: 
00392                 // http://astronomy.swin.edu.au/~pbourke/dataformats/rle/
00393                 // 
00394                 // Anyway, we know that RLE is a basic type compression.  It takes
00395                 // colors that are next to each other and then shrinks that info down
00396                 // into the color and a integer that tells how much of that color is used.
00397                 // For instance:
00398                 // aaaaabbcccccccc would turn into a5b2c8
00399                 // Well, that's fine and dandy and all, but how is it down with RGB colors?
00400                 // Simple, you read in an color count (rleID), and if that number is less than 128,
00401                 // it does NOT have any optimization for those colors, so we just read the next
00402                 // pixels normally.  Say, the color count was 28, we read in 28 colors like normal.
00403                 // If the color count is over 128, that means that the next color is optimized and
00404                 // we want to read in the same pixel color for a count of (colorCount - 127).
00405                 // It's 127 because we add 1 to the color count, as you'll notice in the code.
00406 
00407                 // Create some variables to hold the rleID, current colors read, channels, & stride.
00408                 unsigned char rleID = 0;
00409                 int colorsRead = 0;
00410                 channels = bits / 8;
00411                 stride = channels * width;
00412 
00413                 // Next we want to allocate the memory for the pixels and create an array,
00414                 // depending on the channel count, to read in for each pixel.
00415                 pImageData->data = new unsigned char[stride * height];
00416                 GLbyte *pColors = new GLbyte [channels];
00417 
00418                 // Load in all the pixel data
00419                 while(i < width*height)
00420                 {
00421                         // Read in the current color count + 1
00422                         memcpy(&rleID, buffer, sizeof(unsigned char));
00423                         buffer += sizeof(unsigned char);
00424 
00425                         // Check if we don't have an encoded string of colors
00426                         if(rleID < 128)
00427                         {
00428                                 // Increase the count by 1
00429                                 rleID++;
00430 
00431                                 // Go through and read all the unique colors found
00432                                 while(rleID)
00433                                 {
00434                                         // Read in the current color
00435                                         memcpy(pColors, buffer, sizeof(GLbyte) * channels);
00436                                         buffer += sizeof(GLbyte) * channels;
00437 
00438                                         // Store the current pixel in our image array
00439                                         pImageData->data[colorsRead + 0] = pColors[2];
00440                                         pImageData->data[colorsRead + 1] = pColors[1];
00441                                         pImageData->data[colorsRead + 2] = pColors[0];
00442 
00443                                         // If we have a 4 channel 32-bit image, assign one more for the alpha
00444                                         if(bits == 32)
00445                                                 pImageData->data[colorsRead + 3] = pColors[3];
00446 
00447                                         // Increase the current pixels read, decrease the amount
00448                                         // of pixels left, and increase the starting index for the next pixel.
00449                                         i++;
00450                                         rleID--;
00451                                         colorsRead += channels;
00452                                 }
00453                         }
00454                         // Else, let's read in a string of the same character
00455                         else
00456                         {
00457                                 // Minus the 128 ID + 1 (127) to get the color count that needs to be read
00458                                 rleID -= 127;
00459 
00460                                 // Read in the current color, which is the same for a while
00461                                 memcpy(pColors, buffer, sizeof(GLbyte) * channels);
00462                                 buffer += sizeof(GLbyte) * channels;
00463 
00464                                 // Go and read as many pixels as are the same
00465                                 while(rleID)
00466                                 {
00467                                         // Assign the current pixel to the current index in our pixel array
00468                                         pImageData->data[colorsRead + 0] = pColors[2];
00469                                         pImageData->data[colorsRead + 1] = pColors[1];
00470                                         pImageData->data[colorsRead + 2] = pColors[0];
00471 
00472                                         // If we have a 4 channel 32-bit image, assign one more for the alpha
00473                                         if(bits == 32)
00474                                                 pImageData->data[colorsRead + 3] = pColors[3];
00475 
00476                                         // Increase the current pixels read, decrease the amount
00477                                         // of pixels left, and increase the starting index for the next pixel.
00478                                         i++;
00479                                         rleID--;
00480                                         colorsRead += channels;
00481                                 }
00482 
00483                         }
00484 
00485                 }
00486 
00487                 // Free up pColors
00488                 delete[] pColors;
00489         }
00490 
00491         // Fill in our tImageTGA structure to pass back
00492         pImageData->channels = channels;
00493         pImageData->sizeX    = width;
00494         pImageData->sizeY    = height;
00495 
00496         // Return the TGA data (remember, you must free this data after you are done)
00497         return pImageData;
00498 }
00499 #endif
00500 
00501 } // End of  CEGUI namespace section

Generated on Wed Sep 7 09:56:35 2005 for Crazy Eddies GUI System by  doxygen 1.4.3