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

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 = img->sizeX;
00099                 d_height = 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 }
00167 
00168 
00169 /*************************************************************************
00170         Load texture from raw memory.   
00171 *************************************************************************/
00172 void OpenGLTexture::loadFromMemory(const void* buffPtr, uint buffWidth, uint buffHeight)
00173 {
00174         glBindTexture(GL_TEXTURE_2D, d_ogltexture);
00175         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, buffWidth, buffHeight, 0, GL_RGBA ,GL_UNSIGNED_BYTE, buffPtr);
00176 
00177         d_width  = buffWidth;
00178         d_height = buffHeight;
00179 }
00180 
00181 
00182 /*************************************************************************
00183         allocate atexture >= 'size'.  Previous texture is lost
00184 *************************************************************************/
00185 void OpenGLTexture::setOGLTextureSize(uint size)
00186 {
00187         // if not power of 2
00188         if ((size & (size - 1)) || !size)
00189         {
00190                 int log = 0;
00191 
00192                 // get integer log of 'size' to base 2
00193                 while (size >>= 1)
00194                 {
00195                         ++log;
00196                 }
00197 
00198                 // use log to calculate value to use as size.
00199                 size = (2 << log);
00200         }
00201 
00202         // allocate temp buffer for texture
00203         uchar* buff = new uchar[size * size * 4];
00204 
00205         // load empty buffer to texture
00206         glBindTexture(GL_TEXTURE_2D, d_ogltexture);
00207         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA ,GL_UNSIGNED_BYTE, buff);
00208 
00209         // delete buffer
00210         delete[] buff;
00211 
00212         d_height = d_width = size;
00213 }
00214 
00215 
00217 /*************************************************************************
00218         
00219         The following are included if DevIL is not being used for image
00220         loading
00221 
00222 *************************************************************************/
00224 
00225 #ifndef USE_DEVIL_LIBRARY
00226 /*************************************************************************
00227         flips data for tImageTGA 'img'  
00228 *************************************************************************/
00229 void OpenGLTexture::flipImageTGA(OpenGLTexture::tImageTGA* img)
00230 {
00231         int pitch = img->sizeX * img->channels;
00232 
00233         // flip the image bits...
00234         for (int line = 0; line < img->sizeY / 2; ++line)
00235         {
00236                 int srcOffset = (line * pitch);
00237                 int dstOffest = ((img->sizeY - line - 1) * pitch);
00238 
00239                 for (int colBit = 0; colBit < pitch; ++colBit)
00240                 {
00241                         uchar tmp = img->data[dstOffest + colBit];
00242                         img->data[dstOffest + colBit] = img->data[srcOffset + colBit];
00243                         img->data[srcOffset + colBit] = tmp;
00244                 }
00245 
00246         }
00247 
00248 }
00249 
00250 
00259 
00260 OpenGLTexture::tImageTGA* OpenGLTexture::LoadTGA(const unsigned char* buffer, unsigned int buffer_size)
00261 {
00262         tImageTGA *pImageData = NULL;           // This stores our important image data
00263         short width = 0, height = 0;                    // The dimensions of the image
00264         GLbyte length = 0;                                      // The length in bytes to the pixels
00265         GLbyte imageType = 0;                                   // The image type (RLE, RGB, Alpha...)
00266 
00267         GLbyte bits = 0;                                                // The bits per pixel for the image (16, 24, 32)
00268         int channels = 0;                                       // The channels of the image (3 = RGA : 4 = RGBA)
00269         int stride = 0;                                         // The stride (channels * width)
00270         int i = 0;                                                      // A counter
00271 
00272         // This function loads in a TARGA (.TGA) file and returns its data to be
00273         // used as a texture or what have you.  This currently loads in a 16, 24
00274         // and 32-bit targa file, along with RLE compressed files.  Eventually you
00275         // will want to do more error checking to make it more robust.  This is
00276         // also a perfect start to go into a modular class for an engine.
00277         // Basically, how it works is, you read in the header information, then
00278         // move your file pointer to the pixel data.  Before reading in the pixel
00279         // data, we check to see the if it's an RLE compressed image.  This is because
00280         // we will handle it different.  If it isn't compressed, then we need another
00281         // check to see if we need to convert it from 16-bit to 24 bit.  24-bit and
00282         // 32-bit textures are very similar, so there's no need to do anything special.
00283         // We do, however, read in an extra bit for each color.
00284 
00285         // Allocate the structure that will hold our eventual image data (must free it!)
00286         pImageData = (tImageTGA*)malloc(sizeof(tImageTGA));
00287 
00288         // Read in the length in bytes from the header to the pixel data
00289         memcpy(&length, buffer, sizeof(GLbyte));
00290         buffer += sizeof(GLbyte);
00291 
00292         // Jump over one byte
00293         ++buffer;
00294 
00295         // Read in the imageType (RLE, RGB, etc...)
00296         memcpy(&imageType, buffer, sizeof(GLbyte));
00297         buffer += sizeof(GLbyte);
00298 
00299         // Skip past general information we don't care about
00300         buffer += 9;
00301 
00302         // Read the width, height and bits per pixel (16, 24 or 32)
00303         memcpy(&width, buffer, sizeof(short));
00304         buffer += sizeof(short);
00305         memcpy(&height, buffer, sizeof(short));
00306         buffer += sizeof(short);
00307         memcpy(&bits, buffer, sizeof(GLbyte));
00308         buffer += sizeof(GLbyte);
00309 
00310         // Now we move the file pointer to the pixel data
00311         buffer += length + 1;
00312 
00313         // Check if the image is RLE compressed or not
00314         if(imageType != TGA_RLE)
00315         {
00316                 // Check if the image is a 24 or 32-bit image
00317                 if(bits == 24 || bits == 32)
00318                 {
00319                         // Calculate the channels (3 or 4) - (use bits >> 3 for more speed).
00320                         // Next, we calculate the stride and allocate enough memory for the pixels.
00321                         channels = bits / 8;
00322                         stride = channels * width;
00323                         pImageData->data = new unsigned char[stride * height];
00324 
00325                         // Load in all the pixel data line by line
00326                         for(int y = 0; y < height; y++)
00327                         {
00328                                 // Store a pointer to the current line of pixels
00329                                 unsigned char *pLine = &(pImageData->data[stride * y]);
00330 
00331                                 // Read in the current line of pixels
00332                                 memcpy(pLine, buffer, stride);
00333                                 buffer += stride;
00334 
00335                                 // Go through all of the pixels and swap the B and R values since TGA
00336                                 // files are stored as BGR instead of RGB (or use GL_BGR_EXT verses GL_RGB)
00337                                 for(i = 0; i < stride; i += channels)
00338                                 {
00339                                         int temp     = pLine[i];
00340                                         pLine[i]     = pLine[i + 2];
00341                                         pLine[i + 2] = temp;
00342                                 }
00343                         }
00344                 }
00345                 // Check if the image is a 16 bit image (RGB stored in 1 unsigned short)
00346                 else if(bits == 16)
00347                 {
00348                         unsigned short pixels = 0;
00349                         int r=0, g=0, b=0;
00350 
00351                         // Since we convert 16-bit images to 24 bit, we hardcode the channels to 3.
00352                         // We then calculate the stride and allocate memory for the pixels.
00353                         channels = 3;
00354                         stride = channels * width;
00355                         pImageData->data = new unsigned char[stride * height];
00356 
00357                         // Load in all the pixel data pixel by pixel
00358                         for(int i = 0; i < width*height; i++)
00359                         {
00360                                 // Read in the current pixel
00361                                 memcpy(&pixels, buffer, sizeof(unsigned short));
00362                                 buffer += sizeof(unsigned short);
00363 
00364                                 // To convert a 16-bit pixel into an R, G, B, we need to
00365                                 // do some masking and such to isolate each color value.
00366                                 // 0x1f = 11111 in binary, so since 5 bits are reserved in
00367                                 // each unsigned short for the R, G and B, we bit shift and mask
00368                                 // to find each value.  We then bit shift up by 3 to get the full color.
00369                                 b = (pixels & 0x1f) << 3;
00370                                 g = ((pixels >> 5) & 0x1f) << 3;
00371                                 r = ((pixels >> 10) & 0x1f) << 3;
00372 
00373                                 // This essentially assigns the color to our array and swaps the
00374                                 // B and R values at the same time.
00375                                 pImageData->data[i * 3 + 0] = r;
00376                                 pImageData->data[i * 3 + 1] = g;
00377                                 pImageData->data[i * 3 + 2] = b;
00378                         }
00379                 }       
00380                 // Else return a NULL for a bad or unsupported pixel format
00381                 else
00382                         return NULL;
00383         }
00384         // Else, it must be Run-Length Encoded (RLE)
00385         else
00386         {
00387                 // First, let me explain real quickly what RLE is.  
00388                 // For further information, check out Paul Bourke's intro article at: 
00389                 // http://astronomy.swin.edu.au/~pbourke/dataformats/rle/
00390                 // 
00391                 // Anyway, we know that RLE is a basic type compression.  It takes
00392                 // colors that are next to each other and then shrinks that info down
00393                 // into the color and a integer that tells how much of that color is used.
00394                 // For instance:
00395                 // aaaaabbcccccccc would turn into a5b2c8
00396                 // Well, that's fine and dandy and all, but how is it down with RGB colors?
00397                 // Simple, you read in an color count (rleID), and if that number is less than 128,
00398                 // it does NOT have any optimization for those colors, so we just read the next
00399                 // pixels normally.  Say, the color count was 28, we read in 28 colors like normal.
00400                 // If the color count is over 128, that means that the next color is optimized and
00401                 // we want to read in the same pixel color for a count of (colorCount - 127).
00402                 // It's 127 because we add 1 to the color count, as you'll notice in the code.
00403 
00404                 // Create some variables to hold the rleID, current colors read, channels, & stride.
00405                 unsigned char rleID = 0;
00406                 int colorsRead = 0;
00407                 channels = bits / 8;
00408                 stride = channels * width;
00409 
00410                 // Next we want to allocate the memory for the pixels and create an array,
00411                 // depending on the channel count, to read in for each pixel.
00412                 pImageData->data = new unsigned char[stride * height];
00413                 GLbyte *pColors = new GLbyte [channels];
00414 
00415                 // Load in all the pixel data
00416                 while(i < width*height)
00417                 {
00418                         // Read in the current color count + 1
00419                         memcpy(&rleID, buffer, sizeof(unsigned char));
00420                         buffer += sizeof(unsigned char);
00421 
00422                         // Check if we don't have an encoded string of colors
00423                         if(rleID < 128)
00424                         {
00425                                 // Increase the count by 1
00426                                 rleID++;
00427 
00428                                 // Go through and read all the unique colors found
00429                                 while(rleID)
00430                                 {
00431                                         // Read in the current color
00432                                         memcpy(pColors, buffer, sizeof(GLbyte) * channels);
00433                                         buffer += sizeof(GLbyte) * channels;
00434 
00435                                         // Store the current pixel in our image array
00436                                         pImageData->data[colorsRead + 0] = pColors[2];
00437                                         pImageData->data[colorsRead + 1] = pColors[1];
00438                                         pImageData->data[colorsRead + 2] = pColors[0];
00439 
00440                                         // If we have a 4 channel 32-bit image, assign one more for the alpha
00441                                         if(bits == 32)
00442                                                 pImageData->data[colorsRead + 3] = pColors[3];
00443 
00444                                         // Increase the current pixels read, decrease the amount
00445                                         // of pixels left, and increase the starting index for the next pixel.
00446                                         i++;
00447                                         rleID--;
00448                                         colorsRead += channels;
00449                                 }
00450                         }
00451                         // Else, let's read in a string of the same character
00452                         else
00453                         {
00454                                 // Minus the 128 ID + 1 (127) to get the color count that needs to be read
00455                                 rleID -= 127;
00456 
00457                                 // Read in the current color, which is the same for a while
00458                                 memcpy(pColors, buffer, sizeof(GLbyte) * channels);
00459                                 buffer += sizeof(GLbyte) * channels;
00460 
00461                                 // Go and read as many pixels as are the same
00462                                 while(rleID)
00463                                 {
00464                                         // Assign the current pixel to the current index in our pixel array
00465                                         pImageData->data[colorsRead + 0] = pColors[2];
00466                                         pImageData->data[colorsRead + 1] = pColors[1];
00467                                         pImageData->data[colorsRead + 2] = pColors[0];
00468 
00469                                         // If we have a 4 channel 32-bit image, assign one more for the alpha
00470                                         if(bits == 32)
00471                                                 pImageData->data[colorsRead + 3] = pColors[3];
00472 
00473                                         // Increase the current pixels read, decrease the amount
00474                                         // of pixels left, and increase the starting index for the next pixel.
00475                                         i++;
00476                                         rleID--;
00477                                         colorsRead += channels;
00478                                 }
00479 
00480                         }
00481 
00482                 }
00483 
00484                 // Free up pColors
00485                 delete[] pColors;
00486         }
00487 
00488         // Fill in our tImageTGA structure to pass back
00489         pImageData->channels = channels;
00490         pImageData->sizeX    = width;
00491         pImageData->sizeY    = height;
00492 
00493         // Return the TGA data (remember, you must free this data after you are done)
00494         return pImageData;
00495 }
00496 #endif
00497 
00498 } // End of  CEGUI namespace section

Generated on Wed Feb 16 12:41:08 2005 for Crazy Eddies GUI System by  doxygen 1.3.9.1