AaronCameron.net
Because you all make me very, very tired.
Not a Member? - Login or Create an Account
Sunday the 20th of May 2012 @ 03:59pm
Front Page Journal Projects Your Profile About
[]

LibN2L-4 Library Code Reference

Classes
Compounds
Files
Members
Method Index
Full Reference

cGLTexture.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002 Nova-2 Library (libN2L, or simply n2l) Game development C++ Library
00003 Copyright (C) 2002  Aaron Cameron
00004 
00005 This library is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU Lesser General Public
00007 License as published by the Free Software Foundation; either
00008 version 2.1 of the License, or (at your option) any later version.
00009 
00010 This library is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 Lesser General Public License for more details.
00014 
00015 You should have received a copy of the GNU Lesser General Public
00016 License along with this library; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00018 
00019 A copy of the GNU Lesser General Public License has been provided with
00020 this library in the file 'COPYING'.
00021 
00022 Contact information for the author of this library has been provided
00023 with this library in the file 'AUTHOR'.
00024 ************************************************************************/
00025 #include "cGLTexture.h"
00026 
00027 #include "n2l/vfs.h"
00028 #include "n2l/video.h"
00029 
00030 #include <GL/glu.h>
00031 #include <GL/gl.h>
00032 
00033 #include <iostream>
00034 using namespace std;
00035 
00036 namespace n2l {
00037 
00038     tBool cGLTexture::smRequiresRefreshable = true;
00039 
00040     /**************************************************************************/
00041     cGLTexture::cGLTexture( const GLenum &iFormat, const tVector2u &iSize ) :
00042         mGLName(0),
00043         mHasAlpha(true),    // Assume, like an idiot.
00044         mRefreshable(false),
00045         mSurface(0),
00046         mRawData(0)
00047     {
00048         glGenTextures(1,&mGLName);
00049         const tUint UnpackedDataSize = iSize.x()*iSize.y()*4;
00050         mRawData = new tUint8[ UnpackedDataSize ];
00051         mRefreshable = true;
00052         bind();
00053         glTexImage2D( GL_TEXTURE_2D, 0, 4, iSize.x(),iSize.y(), 0,
00054             GL_RGBA, GL_UNSIGNED_BYTE, mRawData );
00055 
00056         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
00057         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
00058 //      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
00059 //      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
00060     }
00061 
00062     /**************************************************************************/
00063     cGLTexture::cGLTexture( const cSurfaceInterface &iSurface ) :
00064         mGLName(0),
00065         mRefreshable(false),
00066         mRawData(0)
00067     {
00068         mSurface = new cSurface;
00069         mSurface->create(
00070             iSurface.properties().size().x(),
00071             iSurface.properties().size().y(),
00072             iSurface.format().bitsPerPixel(),
00073             iSurface.format().channelMask(cPixelFormat::Channel_Red),
00074             iSurface.format().channelMask(cPixelFormat::Channel_Green),
00075             iSurface.format().channelMask(cPixelFormat::Channel_Blue),
00076             iSurface.format().channelMask(cPixelFormat::Channel_Alpha) );
00077         mSurface->literalCopyBlit( tVector2s(0,0), iSurface );
00078         mRefreshable = true;
00079         readRawFromSurface(*mSurface);
00080         regenTexture();
00081     }
00082 
00083     /**************************************************************************/
00084     cGLTexture::cGLTexture( const cVfsNodeInterface &iFile ) :
00085         mGLName(0),
00086         mRefreshable(false),
00087         mRawData(0)
00088     {
00089         if (!iFile.likeFile())
00090             throw cBadDataUseException( "cGLTexture::cGLTexture",
00091                 tString("Node isn\'t like a file: ") + iFile.name() );
00092         mSurface = new cSurface;
00093         mSurface->load(iFile);
00094         mRefreshable = true;
00095         readRawFromSurface(*mSurface);
00096         regenTexture();
00097     }
00098     
00099 
00100     /**************************************************************************/
00101     const tBool cGLTexture::hasAlpha() const
00102     {
00103         return mHasAlpha;
00104     }
00105 
00106     /**************************************************************************/
00107     cGLTexture::~cGLTexture()
00108     {
00109         // We'll delete the texture here
00110         tGLTextureName temp[1];
00111         temp[0] = mGLName;
00112         glDeleteTextures( 1,temp );
00113         if (mSurface) delete mSurface;
00114         if (mRawData) delete [](tUint8*)(mRawData);
00115     }
00116 
00117     /**************************************************************************/
00118     const tVector2u & cGLTexture::size() const
00119     {
00120         return mSize;
00121     }
00122 
00123     /**************************************************************************/
00124     void cGLTexture::bindTexture2D() const
00125     {
00126         glBindTexture(GL_TEXTURE_2D,mGLName);
00127 //cout << "Binding Tex name: " << mGLName << endl;
00128     }
00129 
00130     /**************************************************************************/
00131     const tUint cGLTexture::bitsForFormat( const GLenum &iFormat )
00132     {
00133         switch (iFormat)
00134         {
00135             case GL_ALPHA4: return 4;
00136             case GL_ALPHA8: return 8;
00137             case GL_ALPHA12: return 12;
00138             case GL_ALPHA16: return 16;
00139 
00140             case GL_LUMINANCE4: return 4;
00141             case GL_LUMINANCE8: return 8;
00142             case GL_LUMINANCE12: return 12;
00143             case GL_LUMINANCE16: return 16;
00144 
00145             case GL_LUMINANCE4_ALPHA4: return 8;
00146             case GL_LUMINANCE6_ALPHA2: return 8;
00147             case GL_LUMINANCE8_ALPHA8: return 16;
00148             case GL_LUMINANCE12_ALPHA4: return 16;
00149             case GL_LUMINANCE16_ALPHA16: return 32;
00150 
00151             case GL_INTENSITY4: return 4;
00152             case GL_INTENSITY8: return 8;
00153             case GL_INTENSITY12: return 12;
00154             case GL_INTENSITY16: return 16;
00155 
00156             case GL_R3_G3_B2: return 8;
00157 
00158             case GL_RGB4: return 12;
00159             case GL_RGB5: return 15;
00160             case GL_RGB8: return 24;
00161             case GL_RGB10: return 30;
00162             case GL_RGB12: return 36;
00163             case GL_RGB16: return 48;
00164             
00165             case GL_RGBA2: return 8;
00166             case GL_RGBA4: return 16;
00167 
00168             case GL_RGB5_A1: return 16;
00169 
00170             case GL_RGBA8: return 32;
00171 
00172             case GL_RGB10_A2: return 32;
00173             case GL_RGBA12: return 48;
00174             case GL_RGBA16: return 64;
00175 
00176             default:
00177                 break;
00178         }
00179         throw cOutOfBoundsException( "cGLTexture::bitsForFormat",
00180             "Format provided is not known", asString(tUint(iFormat)) );
00181     }
00182 
00183     /**************************************************************************/
00184     void cGLTexture::refresh() const
00185     {
00186         if (smRequiresRefreshable && !mRefreshable)
00187             throw cUnsupportedMethodException( "cGLTexture::refresh",
00188                 "Called refresh on a texture which doesn\'t support it." );
00189 
00190         // Delete the old texture (do I have to do this?)
00191         tGLTextureName temp[1];
00192         temp[0] = mGLName;
00193         glDeleteTextures( 1,temp );
00194         // re-read the texture.
00195         readRawFromSurface( *mSurface );
00196         regenTexture();
00197     }
00198 
00199     /**************************************************************************/
00200     void cGLTexture::readRawFromSurface(
00201         const cSurfaceInterface &iSurface ) const
00202     {
00203         cSurface tempSurface;
00204 
00205         // Does this have an alpha surface?
00206         mHasAlpha = (0!=iSurface.format().channelMask(
00207             cPixelFormat::Channel_Alpha));
00208 
00209         // Make sure the surface in question is the proper dimentions,
00210         // xSize and ySize are both ^2
00211         tUint nWidth, nHeight;
00212         tUint nWidthPow, nHeightPow;
00213         isTwoToThe(iSurface.properties().size().x(),nWidthPow);
00214         isTwoToThe(iSurface.properties().size().y(),nHeightPow);
00215         nWidth = tUint(::pow(2.0f,nWidthPow));
00216         nHeight = tUint(::pow(2.0f,nHeightPow));
00217         tBool exactSize = (iSurface.properties().size().x()==nWidth && 
00218             iSurface.properties().size().y()==nHeight);
00219         // For now just drop an error if the size isn't ok.
00220         if (!exactSize) {
00221             try
00222             {
00223                 tempSurface.create( nWidth,nHeight,
00224                     iSurface.format().bitsPerPixel(),
00225                     iSurface.format().channelMask(cPixelFormat::Channel_Red),
00226                     iSurface.format().channelMask(cPixelFormat::Channel_Green),
00227                     iSurface.format().channelMask(cPixelFormat::Channel_Blue),
00228                     iSurface.format().channelMask(cPixelFormat::Channel_Alpha) );
00229                 tUint32 emptyPixel;
00230                 if (iSurface.format().channelMask(cPixelFormat::Channel_Alpha))
00231                     emptyPixel = tempSurface.mapRGBA(0,0,0,0);
00232                 else emptyPixel = tempSurface.mapRGB(0,0,0);
00233                 tempSurface.clearSurface( emptyPixel );
00234                 //cornerCopy( tempSurface, iSurface );
00235                 tempSurface.literalCopyBlit( tVector2u(0,0), iSurface );
00236             }
00237             catch( const cSDLException & iException )
00238             {
00239                 throw cBadDataUseException( "cGLTexture::cGLTexture",
00240                     tString("Size not power 2, and "
00241                     "couldn\'t create a suitable conversion surface: ")+
00242                     tString(iException) );
00243             }
00244 
00245         }   // !exactSize
00246 
00247         if (mRawData) delete [](tUint8*)(mRawData);
00248 
00249         if (exactSize)
00250             getRawSurfaceData(iSurface, mNumComponents,
00251                 mSize.x(), mSize.y(), mFormat, mType, mRawData);
00252         else getRawSurfaceData(tempSurface, mNumComponents,
00253             mSize.x(), mSize.y(), mFormat, mType, mRawData);
00254     }
00255 
00256     /**************************************************************************/
00257     void cGLTexture::regenTexture() const
00258     {
00259         // Generate a new name for this texture
00260         glGenTextures(1,&mGLName);
00261         GLenum error;
00262         while ( (error=glGetError()) != GL_NO_ERROR )
00263             throw cOpenGLException( "cGLTexture::cGLTexture",
00264                 "glGenTextures:", error );
00265 
00266         glBindTexture(GL_TEXTURE_2D,mGLName);
00267         while ( (error=glGetError()) != GL_NO_ERROR )
00268             throw cOpenGLException( "cGLTexture::cGLTexture",
00269                 "glBindTexture:", error );
00270 
00271         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
00272             GL_LINEAR);
00273 
00274         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
00275             GL_LINEAR_MIPMAP_NEAREST);
00276 
00277         gluBuild2DMipmaps( GL_TEXTURE_2D, mNumComponents,
00278             mSize.x(), mSize.y(), mFormat, mType, mRawData );
00279 
00280         while ( (error=glGetError()) != GL_NO_ERROR )
00281             throw cOpenGLException( "cGLTexture::cGLTexture",
00282                 "glBindTexture:", error );
00283     }
00284 
00285     /**************************************************************************/
00286     void cGLTexture::getRawSurfaceData( const cSurfaceInterface & i_surface,
00287         tUint &o_numComponents, tUint &o_width, tUint &o_height,
00288         GLenum &o_format, GLenum &o_type, void *&o_data ) const
00289     {
00290         if (i_surface.empty())
00291             throw cBadDataUseException( "cGLTexture::getRawSurfaceData",
00292                 "Tried to convert an uninitalized surface" );
00293         // Set some values to be safe
00294         o_data = 0;
00295 
00296         // Set the stuff we already know
00297         o_width = i_surface.properties().size().getX();
00298         o_height = i_surface.properties().size().getY();
00299         o_type = GL_UNSIGNED_BYTE;
00300 
00301         // Get some information about the surface
00302         cPixelFormat::tChannelMask rMask,gMask,bMask,aMask;
00303         cPixelFormat::tBitCount rShift,gShift,bShift,aShift;
00304         cPixelFormat::tBitCount rLoss,gLoss,bLoss,aLoss;
00305         
00306         i_surface.format().channelMasks(rMask,gMask,bMask,aMask);
00307         i_surface.format().channelShifts(rShift,gShift,bShift,aShift);
00308         i_surface.format().channelLosses(rLoss,gLoss,bLoss,aLoss);
00309 
00310         // Figure out how many components we have
00311         o_numComponents = 0;
00312         if (rMask) ++o_numComponents;
00313         if (gMask) ++o_numComponents;
00314         if (bMask) ++o_numComponents;
00315         if (aMask) ++o_numComponents;
00316         switch (o_numComponents)
00317         {
00318             case 0:
00319                 throw cBadDataUseException( "cGLTexture::getRawSurfaceData",
00320                     "Tried to convert an 0 component surface? (Indexed?)" );
00321             case 1:
00322                 if (rMask) o_format = GL_RED;
00323                 else if (gMask) o_format = GL_GREEN;
00324                 else if (bMask) o_format = GL_BLUE;
00325                 else o_format = GL_ALPHA;
00326                 break;
00327 
00328             case 3:
00329                 if ( !rMask || !gMask || !bMask )
00330                     throw cBadDataUseException(
00331                         "cGLTexture::getRawSurfaceData",
00332                         "Tried to convert a 3 component surface mixed "
00333                         "with alpha" );
00334                 o_format = GL_RGB;
00335                 break;
00336 
00337             case 4:
00338                 o_format = GL_RGBA;
00339                 break;
00340                 
00341             default:
00342                 throw cBadDataUseException( "cGLTexture::getRawSurfaceData",
00343                     "Tried to convert an 2 component surface" );
00344         } // switch
00345 
00346 
00347         // Get Some values we'll need
00348         const cPixelFormat::tByteCount BytesPerPixel =
00349             i_surface.format().bytesPerPixel();
00350 
00351         const tUint NumPixels = o_width*o_height;
00352         const tUint ActualScanLineBytes = o_width*BytesPerPixel;
00353         const tUint PitchDiff = i_surface.properties().pitch() -
00354             ActualScanLineBytes;
00355         const tUint UnpackedDataSize = o_numComponents*NumPixels;
00356 
00357         // Aquire the surface for reading
00358         tUint8 *pixels = (tUint8*)(i_surface.aquireROBuffer());
00359         const tUint8 *EOPixels = pixels + 
00360             (o_height*i_surface.properties().pitch());
00361         if (!pixels) 
00362             throw cException( "cGLTexture::getRawSurfaceData",
00363                 "Unable to aquire RO Buffer for conversion");
00364 
00365         o_data = new tUint8[ UnpackedDataSize ];
00366         tUint8 * dataPtr = (tUint8*)(o_data);
00367         tUint lineByteCount = 0;
00368 
00369         switch (o_format) {
00371             case GL_RGB:
00372             {
00373                 while (EOPixels!=pixels) {
00374                     tUint32 *unalignedData = (tUint32*)(pixels);
00375                     *dataPtr = tUint8((((*unalignedData)&rMask) >> rShift
00376                         << rLoss));
00377 
00378                     ++dataPtr;
00379                     *dataPtr = tUint8((((*unalignedData)&gMask) >> gShift
00380                         << gLoss));
00381 
00382                     ++dataPtr;
00383                     *dataPtr = tUint8((((*unalignedData)&bMask) >> bShift
00384                         << bLoss));
00385 
00386                     ++dataPtr;
00387                     lineByteCount += 3;
00388                     if (lineByteCount==ActualScanLineBytes) {
00389                         lineByteCount = 0;
00390                         pixels += PitchDiff;
00391                     }
00392                     pixels+=BytesPerPixel;
00393                 }
00394 
00395                 break;
00396             }
00398             case GL_RGBA:
00399             {
00400                 while (EOPixels!=pixels) {
00401                     tUint32 *unalignedData = (tUint32*)(pixels);
00402                     *dataPtr = tUint8((((*unalignedData)&rMask) >> rShift
00403                         << rLoss));
00404                     ++dataPtr;
00405                     *dataPtr = tUint8((((*unalignedData)&gMask) >> gShift
00406                         << gLoss));
00407                     ++dataPtr;
00408                     *dataPtr = tUint8((((*unalignedData)&bMask) >> bShift
00409                         << bLoss));
00410                     ++dataPtr;
00411                     *dataPtr = tUint8((((*unalignedData)&aMask) >> aShift
00412                         << aLoss));
00413                     ++dataPtr;
00414                     
00415                     lineByteCount += 4;
00416                     if (lineByteCount==ActualScanLineBytes) {
00417                         lineByteCount = 0;
00418                         pixels += PitchDiff;
00419                     }
00420                     pixels+=BytesPerPixel;
00421                 }
00422                 break;
00423             }
00424 
00425 
00427             default:
00428             {
00429                 // Release the buffers and die
00430                 i_surface.releaseROBuffer();
00431                 delete [](tUint8*)o_data;
00432                 throw cException( "cGLTexture::getRawSurfaceData",
00433                     "Requested conversion not supported, yet.");
00434             }
00435         }   // Format switch
00436 
00437         // Release the buffer
00438         i_surface.releaseROBuffer();
00439     }
00440 
00441     /**************************************************************************/
00442     const tBool cGLTexture::isTwoToThe( const tUint iNum,
00443         tUint &oClosest ) const
00444     {
00445         oClosest = 0;
00446         tDouble p;
00447         do {
00448             ++oClosest;
00449             p = ::pow(2.0f,oClosest);
00450             if (iNum==tUint(p)) return true;
00451         } while (p<iNum);
00452         return false;
00453     }
00454 
00455 } // Namespace
©2012 Aaron Cameron