![[]](/images/special/trans.gif)
LibN2L-4 Library Code ReferenceClassesCompounds Files Members Method Index Full Reference cGLTexture.cppGo 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 |