llimagegl.cpp

Go to the documentation of this file.
00001 
00033 // TODO: create 2 classes for images w/ and w/o discard levels?
00034 
00035 #include "linden_common.h"
00036 
00037 #include "llimagegl.h"
00038 
00039 #include "llerror.h"
00040 #include "llimage.h"
00041 
00042 #include "llmath.h"
00043 #include "llgl.h"
00044 #include "llglimmediate.h"
00045 
00046 
00047 //----------------------------------------------------------------------------
00048 
00049 const F32 MIN_TEXTURE_LIFETIME = 10.f;
00050 
00051 //statics
00052 LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 };
00053 
00054 U32 LLImageGL::sUniqueCount                             = 0;
00055 U32 LLImageGL::sBindCount                               = 0;
00056 S32 LLImageGL::sGlobalTextureMemory             = 0;
00057 S32 LLImageGL::sBoundTextureMemory              = 0;
00058 S32 LLImageGL::sCurBoundTextureMemory   = 0;
00059 S32 LLImageGL::sCount                                   = 0;
00060 
00061 BOOL LLImageGL::sGlobalUseAnisotropic   = FALSE;
00062 F32 LLImageGL::sLastFrameTime                   = 0.f;
00063 
00064 std::set<LLImageGL*> LLImageGL::sImageList;
00065 
00066 //----------------------------------------------------------------------------
00067 
00068 //static
00069 S32 LLImageGL::dataFormatBits(S32 dataformat)
00070 {
00071         switch (dataformat)
00072         {
00073           case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:        return 4;
00074           case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:        return 8;
00075           case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:        return 8;
00076           case GL_LUMINANCE:                                            return 8;
00077           case GL_ALPHA:                                                        return 8;
00078           case GL_COLOR_INDEX:                                          return 8;
00079           case GL_LUMINANCE_ALPHA:                                      return 16;
00080           case GL_RGB:                                                          return 24;
00081           case GL_RGB8:                                                         return 24;
00082           case GL_RGBA:                                                         return 32;
00083           case GL_BGRA:                                                         return 32;              // Used for QuickTime media textures on the Mac
00084           default:
00085                 llerrs << "LLImageGL::Unknown format: " << dataformat << llendl;
00086                 return 0;
00087         }
00088 }
00089 
00090 //static
00091 S32 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height)
00092 {
00093         if (dataformat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT &&
00094                 dataformat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
00095         {
00096                 if (width < 4) width = 4;
00097                 if (height < 4) height = 4;
00098         }
00099         S32 bytes ((width*height*dataFormatBits(dataformat)+7)>>3);
00100         S32 aligned = (bytes+3)&~3;
00101         return aligned;
00102 }
00103 
00104 //static
00105 S32 LLImageGL::dataFormatComponents(S32 dataformat)
00106 {
00107         switch (dataformat)
00108         {
00109           case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:        return 3;
00110           case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:        return 4;
00111           case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:        return 4;
00112           case GL_LUMINANCE:                                            return 1;
00113           case GL_ALPHA:                                                        return 1;
00114           case GL_COLOR_INDEX:                                          return 1;
00115           case GL_LUMINANCE_ALPHA:                                      return 2;
00116           case GL_RGB:                                                          return 3;
00117           case GL_RGBA:                                                         return 4;
00118           case GL_BGRA:                                                         return 4;               // Used for QuickTime media textures on the Mac
00119           default:
00120                 llerrs << "LLImageGL::Unknown format: " << dataformat << llendl;
00121                 return 0;
00122         }
00123 }
00124 
00125 //----------------------------------------------------------------------------
00126 
00127 // static
00128 void LLImageGL::bindExternalTexture(LLGLuint gl_name, S32 stage, LLGLenum bind_target )
00129 {
00130         gGL.flush();
00131         if (stage > 0)
00132         {
00133                 glActiveTextureARB(GL_TEXTURE0_ARB + stage);
00134         }
00135         glBindTexture(bind_target, gl_name);
00136         sCurrentBoundTextures[stage] = gl_name;
00137         if (stage > 0)
00138         {
00139                 glActiveTextureARB(GL_TEXTURE0_ARB);
00140         }
00141 }
00142 
00143 // static
00144 void LLImageGL::unbindTexture(S32 stage, LLGLenum bind_target)
00145 {
00146         // LLGLSLShader can return -1
00147         if (stage >= 0)
00148         {
00149                 gGL.flush();
00150                 if (stage > 0)
00151                 {
00152                         glActiveTextureARB(GL_TEXTURE0_ARB + stage);
00153                         glBindTexture(GL_TEXTURE_2D, 0);
00154                         glActiveTextureARB(GL_TEXTURE0_ARB);
00155                 }
00156                 else
00157                 {
00158                         glBindTexture(GL_TEXTURE_2D, 0);
00159                 }
00160                 sCurrentBoundTextures[stage] = 0;
00161         }
00162 }
00163 
00164 // static (duplicated for speed and to avoid GL_TEXTURE_2D default argument which requires GL header dependency)
00165 void LLImageGL::unbindTexture(S32 stage)
00166 {
00167         unbindTexture(stage, GL_TEXTURE_2D);
00168 }
00169 
00170 // static
00171 void LLImageGL::updateStats(F32 current_time)
00172 {
00173         sLastFrameTime = current_time;
00174         sBoundTextureMemory = sCurBoundTextureMemory;
00175         sCurBoundTextureMemory = 0;
00176 }
00177 
00178 //static
00179 S32 LLImageGL::updateBoundTexMem(const S32 delta)
00180 {
00181         LLImageGL::sCurBoundTextureMemory += delta;
00182         return LLImageGL::sCurBoundTextureMemory;
00183 }
00184 
00185 //----------------------------------------------------------------------------
00186 
00187 //static 
00188 void LLImageGL::destroyGL(BOOL save_state)
00189 {
00190         for (S32 stage = 0; stage < gGLManager.mNumTextureUnits; stage++)
00191         {
00192                 LLImageGL::unbindTexture(stage, GL_TEXTURE_2D);
00193         }
00194         for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
00195                  iter != sImageList.end(); iter++)
00196         {
00197                 LLImageGL* glimage = *iter;
00198                 if (glimage->mTexName && glimage->mComponents)
00199                 {
00200                         if (save_state)
00201                         {
00202                                 glimage->mSaveData = new LLImageRaw;
00203                                 glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false);
00204                         }
00205                         glimage->destroyGLTexture();
00206                         stop_glerror();
00207                 }
00208         }
00209 }
00210 
00211 //static 
00212 void LLImageGL::restoreGL()
00213 {
00214         for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
00215                  iter != sImageList.end(); iter++)
00216         {
00217                 LLImageGL* glimage = *iter;
00218                 if (glimage->mSaveData.notNull() && glimage->mSaveData->getComponents())
00219                 {
00220                         if (glimage->getComponents())
00221                         {
00222                                 glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData);
00223                                 stop_glerror();
00224                         }
00225                         glimage->mSaveData = NULL; // deletes data
00226                 }
00227         }
00228 }
00229 
00230 //----------------------------------------------------------------------------
00231 
00232 //static 
00233 BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, BOOL usemipmaps)
00234 {
00235         dest = new LLImageGL(usemipmaps);
00236         return TRUE;
00237 }
00238 
00239 BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, U32 width, U32 height, U8 components, BOOL usemipmaps)
00240 {
00241         dest = new LLImageGL(width, height, components, usemipmaps);
00242         return TRUE;
00243 }
00244 
00245 BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps)
00246 {
00247         dest = new LLImageGL(imageraw, usemipmaps);
00248         return TRUE;
00249 }
00250 
00251 //----------------------------------------------------------------------------
00252 
00253 LLImageGL::LLImageGL(BOOL usemipmaps)
00254         : mSaveData(0)
00255 {
00256         init(usemipmaps);
00257         setSize(0, 0, 0);
00258         sImageList.insert(this);
00259         sCount++;
00260 }
00261 
00262 LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps)
00263         : mSaveData(0)
00264 {
00265         llassert( components <= 4 );
00266         init(usemipmaps);
00267         setSize(width, height, components);
00268         sImageList.insert(this);
00269         sCount++;
00270 }
00271 
00272 LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps)
00273         : mSaveData(0)
00274 {
00275         init(usemipmaps);
00276         setSize(0, 0, 0);
00277         sImageList.insert(this);
00278         sCount++;
00279         createGLTexture(0, imageraw); 
00280 }
00281 
00282 LLImageGL::~LLImageGL()
00283 {
00284         LLImageGL::cleanup();
00285         sImageList.erase(this);
00286         sCount--;
00287 }
00288 
00289 void LLImageGL::init(BOOL usemipmaps)
00290 {
00291 #ifdef DEBUG_MISS
00292         mMissed                         = FALSE;
00293 #endif
00294 
00295         mTextureMemory    = 0;
00296         mLastBindTime     = 0.f;
00297 
00298         mTarget                   = GL_TEXTURE_2D;
00299         mBindTarget               = GL_TEXTURE_2D;
00300         mUseMipMaps               = usemipmaps;
00301         mHasMipMaps               = FALSE;
00302         mAutoGenMips      = FALSE;
00303         mTexName          = 0;
00304         mIsResident       = 0;
00305         mClampS                   = FALSE;
00306         mClampT                   = FALSE;
00307         mMipFilterNearest  = FALSE;
00308         mWidth                          = 0;
00309         mHeight                         = 0;
00310         mComponents                     = 0;
00311         
00312         mMaxDiscardLevel = MAX_DISCARD_LEVEL;
00313         mCurrentDiscardLevel = -1;
00314         mDontDiscard = FALSE;
00315         
00316         mFormatInternal = -1;
00317         mFormatPrimary = (LLGLenum) 0;
00318         mFormatType = GL_UNSIGNED_BYTE;
00319         mFormatSwapBytes = FALSE;
00320         mHasExplicitFormat = FALSE;
00321 }
00322 
00323 void LLImageGL::cleanup()
00324 {
00325         if (!gGLManager.mIsDisabled)
00326         {
00327                 destroyGLTexture();
00328         }
00329         mSaveData = NULL; // deletes data
00330 }
00331 
00332 //----------------------------------------------------------------------------
00333 
00334 static bool check_power_of_two(S32 dim)
00335 {
00336         while(dim > 1)
00337         {
00338                 if (dim & 1)
00339                 {
00340                         return false;
00341                 }
00342                 dim >>= 1;
00343         }
00344         return true;
00345 }
00346 
00347 //static
00348 bool LLImageGL::checkSize(S32 width, S32 height)
00349 {
00350         return check_power_of_two(width) && check_power_of_two(height);
00351 }
00352 
00353 void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents)
00354 {
00355         if (width != mWidth || height != mHeight || ncomponents != mComponents)
00356         {
00357                 // Check if dimensions are a power of two!
00358                 if (!checkSize(width,height))
00359                 {
00360                         llerrs << llformat("Texture has non power of two dimention: %dx%d",width,height) << llendl;
00361                 }
00362                 
00363                 if (mTexName)
00364                 {
00365 //                      llwarns << "Setting Size of LLImageGL with existing mTexName = " << mTexName << llendl;
00366                         destroyGLTexture();
00367                 }
00368                 
00369                 mWidth = width;
00370                 mHeight = height;
00371                 mComponents = ncomponents;
00372                 if (ncomponents > 0)
00373                 {
00374                         mMaxDiscardLevel = 0;
00375                         while (width > 1 && height > 1 && mMaxDiscardLevel < MAX_DISCARD_LEVEL)
00376                         {
00377                                 mMaxDiscardLevel++;
00378                                 width >>= 1;
00379                                 height >>= 1;
00380                         }
00381                 }
00382                 else
00383                 {
00384                         mMaxDiscardLevel = MAX_DISCARD_LEVEL;
00385                 }
00386         }
00387 }
00388 
00389 //----------------------------------------------------------------------------
00390 
00391 // virtual
00392 void LLImageGL::dump()
00393 {
00394         llinfos << "mMaxDiscardLevel " << S32(mMaxDiscardLevel)
00395                         << " mLastBindTime " << mLastBindTime
00396                         << " mTarget " << S32(mTarget)
00397                         << " mBindTarget " << S32(mBindTarget)
00398                         << " mUseMipMaps " << S32(mUseMipMaps)
00399                         << " mHasMipMaps " << S32(mHasMipMaps)
00400                         << " mCurrentDiscardLevel " << S32(mCurrentDiscardLevel)
00401                         << " mFormatInternal " << S32(mFormatInternal)
00402                         << " mFormatPrimary " << S32(mFormatPrimary)
00403                         << " mFormatType " << S32(mFormatType)
00404                         << " mFormatSwapBytes " << S32(mFormatSwapBytes)
00405                         << " mHasExplicitFormat " << S32(mHasExplicitFormat)
00406 #if DEBUG_MISS
00407                         << " mMissed " << mMissed
00408 #endif
00409                         << llendl;
00410 
00411         llinfos << " mTextureMemory " << mTextureMemory
00412                         << " mTexNames " << mTexName
00413                         << " mIsResident " << S32(mIsResident)
00414                         << llendl;
00415 }
00416 
00417 //----------------------------------------------------------------------------
00418 
00419 BOOL LLImageGL::bindTextureInternal(const S32 stage) const
00420 {
00421         if (gGLManager.mIsDisabled)
00422         {
00423                 llwarns << "Trying to bind a texture while GL is disabled!" << llendl;
00424         }
00425 
00426 
00427         if (sCurrentBoundTextures[stage] && sCurrentBoundTextures[stage] == mTexName)
00428         {
00429                 // already set!
00430                 return TRUE;
00431         }
00432 
00433         if (mTexName != 0)
00434         {
00435 #ifdef DEBUG_MISS
00436                 mMissed = ! getIsResident(TRUE);
00437 #endif
00438 
00439                 gGL.flush();
00440                 if (stage > 0)
00441                 {
00442                         glActiveTextureARB(GL_TEXTURE0_ARB + stage);
00443                 }
00444         
00445                 glBindTexture(mBindTarget, mTexName);
00446                 sCurrentBoundTextures[stage] = mTexName;
00447                 sBindCount++;
00448 
00449                 if (stage > 0)
00450                 {
00451                         glActiveTextureARB(GL_TEXTURE0_ARB);
00452                 }
00453                 
00454                 if (mLastBindTime != sLastFrameTime)
00455                 {
00456                         // we haven't accounted for this texture yet this frame
00457                         sUniqueCount++;
00458                         updateBoundTexMem(mTextureMemory);
00459                         mLastBindTime = sLastFrameTime;
00460                 }
00461                 
00462                 return TRUE;
00463         }
00464         else
00465         {
00466                 gGL.flush();
00467                 if (stage > 0)
00468                 {
00469                         glActiveTextureARB(GL_TEXTURE0_ARB+stage);
00470                 }
00471                 glBindTexture(mBindTarget, 0);
00472                 if (stage > 0)
00473                 {
00474                         glActiveTextureARB(GL_TEXTURE0_ARB+stage);
00475                 }
00476                 sCurrentBoundTextures[stage] = 0;
00477                 return FALSE;
00478         }
00479 }
00480 
00481 //virtual
00482 BOOL LLImageGL::bind(const S32 stage) const
00483 {
00484         if (stage == -1)
00485         {
00486                 return FALSE;
00487         }
00488         BOOL res = bindTextureInternal(stage);
00489         //llassert(res);
00490         return res;
00491 }
00492 
00493 void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes )
00494 {
00495         // Note: must be called before createTexture()
00496         // Note: it's up to the caller to ensure that the format matches the number of components.
00497         mHasExplicitFormat = TRUE;
00498         mFormatInternal = internal_format;
00499         mFormatPrimary = primary_format;
00500         if(type_format == 0)
00501                 mFormatType = GL_UNSIGNED_BYTE;
00502         else
00503                 mFormatType = type_format;
00504         mFormatSwapBytes = swap_bytes;
00505 }
00506 
00507 //----------------------------------------------------------------------------
00508 
00509 void LLImageGL::setImage(const LLImageRaw* imageraw)
00510 {
00511         llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) &&
00512                          (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) &&
00513                          (imageraw->getComponents() == getComponents()));
00514         const U8* rawdata = imageraw->getData();
00515         setImage(rawdata, FALSE);
00516 }
00517 
00518 void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
00519 {
00520 //      LLFastTimer t1(LLFastTimer::FTM_TEMP1);
00521         
00522         bool is_compressed = false;
00523         if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
00524         {
00525                 is_compressed = true;
00526         }
00527 
00528         {
00529 //              LLFastTimer t2(LLFastTimer::FTM_TEMP2);
00530                 llverify(bindTextureInternal(0));
00531         }
00532         
00533         if (mUseMipMaps)
00534         {
00535 //              LLFastTimer t2(LLFastTimer::FTM_TEMP3);
00536                 if (data_hasmips)
00537                 {
00538                         // NOTE: data_in points to largest image; smaller images
00539                         // are stored BEFORE the largest image
00540                         for (S32 d=mCurrentDiscardLevel; d<=mMaxDiscardLevel; d++)
00541                         {
00542                                 S32 w = getWidth(d);
00543                                 S32 h = getHeight(d);
00544                                 S32 gl_level = d-mCurrentDiscardLevel;
00545                                 if (d > mCurrentDiscardLevel)
00546                                 {
00547                                         data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment
00548                                 }
00549                                 if (is_compressed)
00550                                 {
00551 //                                      LLFastTimer t2(LLFastTimer::FTM_TEMP4);
00552                                         S32 tex_size = dataFormatBytes(mFormatPrimary, w, h);
00553                                         glCompressedTexImage2DARB(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in);
00554                                         stop_glerror();
00555                                 }
00556                                 else
00557                                 {
00558 //                                      LLFastTimer t2(LLFastTimer::FTM_TEMP4);
00559 
00560                                         if(mFormatSwapBytes)
00561                                         {
00562                                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
00563                                                 stop_glerror();
00564                                         }
00565                                                 
00566                                         glTexImage2D(mTarget, gl_level, mFormatInternal, w, h, 0, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in);
00567                                         
00568                                         if(mFormatSwapBytes)
00569                                         {
00570                                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
00571                                                 stop_glerror();
00572                                         }
00573                                                 
00574                                         stop_glerror();
00575                                 }
00576                                 stop_glerror();
00577                         }                       
00578                 }
00579                 else if (!is_compressed)
00580                 {
00581                         if (mAutoGenMips)
00582                         {
00583                                 glTexParameteri(mBindTarget, GL_GENERATE_MIPMAP_SGIS, TRUE);
00584                                 stop_glerror();
00585                                 {
00586 //                                      LLFastTimer t2(LLFastTimer::FTM_TEMP4);
00587 
00588                                         if(mFormatSwapBytes)
00589                                         {
00590                                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
00591                                                 stop_glerror();
00592                                         }
00593 
00594                                         glTexImage2D(mTarget, 0, mFormatInternal,
00595                                                                  getWidth(mCurrentDiscardLevel), getHeight(mCurrentDiscardLevel), 0,
00596                                                                  mFormatPrimary, mFormatType,
00597                                                                  data_in);
00598                                         stop_glerror();
00599 
00600                                         if(mFormatSwapBytes)
00601                                         {
00602                                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
00603                                                 stop_glerror();
00604                                         }
00605                                 }
00606                         }
00607                         else
00608                         {
00609                                 // Create mips by hand
00610                                 // about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800
00611                                 // ~4x faster than gluBuild2DMipmaps
00612                                 S32 width = getWidth(mCurrentDiscardLevel);
00613                                 S32 height = getHeight(mCurrentDiscardLevel);
00614                                 S32 nummips = mMaxDiscardLevel - mCurrentDiscardLevel + 1;
00615                                 S32 w = width, h = height;
00616                                 const U8* prev_mip_data = 0;
00617                                 const U8* cur_mip_data = 0;
00618                                 S32 prev_mip_size = 0;
00619                                 S32 cur_mip_size = 0;
00620                                 for (int m=0; m<nummips; m++)
00621                                 {
00622                                         if (m==0)
00623                                         {
00624                                                 cur_mip_data = data_in;
00625                                                 cur_mip_size = width * height * mComponents; 
00626                                         }
00627                                         else
00628                                         {
00629                                                 S32 bytes = w * h * mComponents;
00630                                                 llassert(prev_mip_data);
00631                                                 llassert(prev_mip_size == bytes*4);
00632                                                 U8* new_data = new U8[bytes];
00633                                                 llassert_always(new_data);
00634                                                 LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents);
00635                                                 cur_mip_data = new_data;
00636                                                 cur_mip_size = bytes; 
00637                                         }
00638                                         llassert(w > 0 && h > 0 && cur_mip_data);
00639                                         {
00640 //                                              LLFastTimer t1(LLFastTimer::FTM_TEMP4);
00641                                                 if(mFormatSwapBytes)
00642                                                 {
00643                                                         glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
00644                                                         stop_glerror();
00645                                                 }
00646 
00647                                                 glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data);
00648                                                 stop_glerror();
00649 
00650                                                 if(mFormatSwapBytes)
00651                                                 {
00652                                                         glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
00653                                                         stop_glerror();
00654                                                 }
00655                                         }
00656                                         if (prev_mip_data && prev_mip_data != data_in)
00657                                         {
00658                                                 delete[] prev_mip_data;
00659                                         }
00660                                         prev_mip_data = cur_mip_data;
00661                                         prev_mip_size = cur_mip_size;
00662                                         w >>= 1;
00663                                         h >>= 1;
00664                                 }
00665                                 if (prev_mip_data && prev_mip_data != data_in)
00666                                 {
00667                                         delete[] prev_mip_data;
00668                                         prev_mip_data = NULL;
00669                                 }
00670                         }
00671                 }
00672                 else
00673                 {
00674                         llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl;
00675                 }
00676                 mHasMipMaps = TRUE;
00677         }
00678         else
00679         {
00680 //              LLFastTimer t2(LLFastTimer::FTM_TEMP5);
00681                 S32 w = getWidth();
00682                 S32 h = getHeight();
00683                 if (is_compressed)
00684                 {
00685                         S32 tex_size = dataFormatBytes(mFormatPrimary, w, h);
00686                         glCompressedTexImage2DARB(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in);
00687                         stop_glerror();
00688                 }
00689                 else
00690                 {
00691                         if(mFormatSwapBytes)
00692                         {
00693                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
00694                                 stop_glerror();
00695                         }
00696 
00697                         glTexImage2D(mTarget, 0, mFormatInternal, w, h, 0,
00698                                                  mFormatPrimary, mFormatType, (GLvoid *)data_in);
00699                         stop_glerror();
00700 
00701                         if(mFormatSwapBytes)
00702                         {
00703                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
00704                                 stop_glerror();
00705                         }
00706 
00707                 }
00708                 mHasMipMaps = FALSE;
00709         }
00710         stop_glerror();
00711 }
00712 
00713 BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height)
00714 {
00715         if (!width || !height)
00716         {
00717                 return TRUE;
00718         }
00719         if (mTexName == 0)
00720         {
00721                 llwarns << "Setting subimage on image without GL texture" << llendl;
00722                 return FALSE;
00723         }
00724         if (datap == NULL)
00725         {
00726                 llwarns << "Setting subimage on image with NULL datap" << llendl;
00727                 return FALSE;
00728         }
00729         
00730         if (x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height)
00731         {
00732                 setImage(datap, FALSE);
00733         }
00734         else
00735         {
00736                 if (mUseMipMaps)
00737                 {
00738                         dump();
00739                         llerrs << "setSubImage called with mipmapped image (not supported)" << llendl;
00740                 }
00741                 llassert_always(mCurrentDiscardLevel == 0);
00742                 llassert_always(x_pos >= 0 && y_pos >= 0);
00743                 
00744                 if (((x_pos + width) > getWidth()) || 
00745                         (y_pos + height) > getHeight())
00746                 {
00747                         dump();
00748                         llerrs << "Subimage not wholly in target image!" 
00749                                    << " x_pos " << x_pos
00750                                    << " y_pos " << y_pos
00751                                    << " width " << width
00752                                    << " height " << height
00753                                    << " getWidth() " << getWidth()
00754                                    << " getHeight() " << getHeight()
00755                                    << llendl;
00756                 }
00757 
00758                 if ((x_pos + width) > data_width || 
00759                         (y_pos + height) > data_height)
00760                 {
00761                         dump();
00762                         llerrs << "Subimage not wholly in source image!" 
00763                                    << " x_pos " << x_pos
00764                                    << " y_pos " << y_pos
00765                                    << " width " << width
00766                                    << " height " << height
00767                                    << " source_width " << data_width
00768                                    << " source_height " << data_height
00769                                    << llendl;
00770                 }
00771 
00772 
00773                 glPixelStorei(GL_UNPACK_ROW_LENGTH, data_width);
00774                 stop_glerror();
00775 
00776                 if(mFormatSwapBytes)
00777                 {
00778                         glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
00779                         stop_glerror();
00780                 }
00781 
00782                 datap += (y_pos * data_width + x_pos) * getComponents();
00783                 // Update the GL texture
00784                 BOOL res = bindTextureInternal(0);
00785                 if (!res) llerrs << "LLImageGL::setSubImage(): bindTexture failed" << llendl;
00786                 stop_glerror();
00787 
00788                 LLGLEnable tex( GL_TEXTURE_2D ); 
00789 
00790                 glTexSubImage2D(mTarget, 0, x_pos, y_pos, 
00791                                                 width, height, mFormatPrimary, mFormatType, datap);
00792                 stop_glerror();
00793 
00794                 if(mFormatSwapBytes)
00795                 {
00796                         glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
00797                         stop_glerror();
00798                 }
00799 
00800                 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
00801                 stop_glerror();
00802         }
00803         
00804         return TRUE;
00805 }
00806 
00807 BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height)
00808 {
00809         return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height);
00810 }
00811 
00812 // Copy sub image from frame buffer
00813 BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height)
00814 {
00815         if (bindTextureInternal(0))
00816         {
00817                 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
00818                 stop_glerror();
00819                 return TRUE;
00820         }
00821         else
00822         {
00823                 return FALSE;
00824         }
00825 }
00826 
00827 BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/)
00828 {
00829         if (gGLManager.mIsDisabled)
00830         {
00831                 llwarns << "Trying to create a texture while GL is disabled!" << llendl;
00832                 return FALSE;
00833         }
00834         llassert(gGLManager.mInited || gNoRender);
00835         stop_glerror();
00836 
00837         if (discard_level < 0)
00838         {
00839                 llassert(mCurrentDiscardLevel >= 0);
00840                 discard_level = mCurrentDiscardLevel;
00841         }
00842         discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
00843 
00844         // Actual image width/height = raw image width/height * 2^discard_level
00845         S32 w = imageraw->getWidth() << discard_level;
00846         S32 h = imageraw->getHeight() << discard_level;
00847 
00848         // setSize may call destroyGLTexture if the size does not match
00849         setSize(w, h, imageraw->getComponents());
00850 
00851         if( !mHasExplicitFormat )
00852         {
00853                 switch (mComponents)
00854                 {
00855                   case 1:
00856                         // Use luminance alpha (for fonts)
00857                         mFormatInternal = GL_LUMINANCE8;
00858                         mFormatPrimary = GL_LUMINANCE;
00859                         mFormatType = GL_UNSIGNED_BYTE;
00860                         break;
00861                   case 2:
00862                         // Use luminance alpha (for fonts)
00863                         mFormatInternal = GL_LUMINANCE8_ALPHA8;
00864                         mFormatPrimary = GL_LUMINANCE_ALPHA;
00865                         mFormatType = GL_UNSIGNED_BYTE;
00866                         break;
00867                   case 3:
00868                         mFormatInternal = GL_RGB8;
00869                         mFormatPrimary = GL_RGB;
00870                         mFormatType = GL_UNSIGNED_BYTE;
00871                         break;
00872                   case 4:
00873                         mFormatInternal = GL_RGBA8;
00874                         mFormatPrimary = GL_RGBA;
00875                         mFormatType = GL_UNSIGNED_BYTE;
00876                         break;
00877                   default:
00878                         llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
00879                 }
00880         }
00881 
00882         const U8* rawdata = imageraw->getData();
00883         return createGLTexture(discard_level, rawdata, FALSE, usename);
00884 }
00885 
00886 BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
00887 {
00888         llassert(data_in);
00889 
00890         if (discard_level < 0)
00891         {
00892                 llassert(mCurrentDiscardLevel >= 0);
00893                 discard_level = mCurrentDiscardLevel;
00894         }
00895         discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
00896 
00897         if (mTexName != 0 && discard_level == mCurrentDiscardLevel)
00898         {
00899                 // This will only be true if the size has not changed
00900                 setImage(data_in, data_hasmips);
00901                 return TRUE;
00902         }
00903         
00904         GLuint old_name = mTexName;
00905 //      S32 old_discard = mCurrentDiscardLevel;
00906         
00907         if (usename != 0)
00908         {
00909                 mTexName = usename;
00910         }
00911         else
00912         {
00913                 glGenTextures(1, (GLuint*)&mTexName);
00914                 stop_glerror();
00915                 {
00916 //                      LLFastTimer t1(LLFastTimer::FTM_TEMP6);
00917                         llverify(bindTextureInternal(0));
00918                         glTexParameteri(mBindTarget, GL_TEXTURE_BASE_LEVEL, 0);
00919                         glTexParameteri(mBindTarget, GL_TEXTURE_MAX_LEVEL,  mMaxDiscardLevel-discard_level);
00920                 }
00921         }
00922         if (!mTexName)
00923         {
00924                 llerrs << "LLImageGL::createGLTexture failed to make texture" << llendl;
00925         }
00926 
00927         if (mUseMipMaps)
00928         {
00929                 mAutoGenMips = gGLManager.mHasMipMapGeneration;
00930 #if LL_DARWIN
00931                 // On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures.
00932                 if(gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA))
00933                 {
00934                         mAutoGenMips = FALSE;
00935                 }
00936 #endif
00937         }
00938 
00939         mCurrentDiscardLevel = discard_level;
00940 
00941         setImage(data_in, data_hasmips);
00942 
00943         setClamp(mClampS, mClampT);
00944         setMipFilterNearest(mMipFilterNearest);
00945         
00946         // things will break if we don't unbind after creation
00947         unbindTexture(0, mBindTarget);
00948         stop_glerror();
00949 
00950         if (old_name != 0)
00951         {
00952                 sGlobalTextureMemory -= mTextureMemory;
00953                 glDeleteTextures(1, &old_name);
00954                 stop_glerror();
00955         }
00956 
00957         mTextureMemory = getMipBytes(discard_level);
00958         sGlobalTextureMemory += mTextureMemory;
00959                 
00960         // mark this as bound at this point, so we don't throw it out immediately
00961         mLastBindTime = sLastFrameTime;
00962 
00963         return TRUE;
00964 }
00965 
00966 BOOL LLImageGL::setDiscardLevel(S32 discard_level)
00967 {
00968         llassert(discard_level >= 0);
00969         llassert(mCurrentDiscardLevel >= 0);
00970 
00971         discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);       
00972 
00973         if (mDontDiscard)
00974         {
00975                 // don't discard!
00976                 return FALSE;
00977         }
00978         else if (discard_level == mCurrentDiscardLevel)
00979         {
00980                 // nothing to do
00981                 return FALSE;
00982         }
00983         else if (discard_level < mCurrentDiscardLevel)
00984         {
00985                 // larger image
00986                 dump();
00987                 llerrs << "LLImageGL::setDiscardLevel() called with larger discard level; use createGLTexture()" << llendl;
00988                 return FALSE;
00989         }
00990         else if (mUseMipMaps)
00991         {
00992                 LLPointer<LLImageRaw> imageraw = new LLImageRaw;
00993                 while(discard_level > mCurrentDiscardLevel)
00994                 {
00995                         if (readBackRaw(discard_level, imageraw, false))
00996                         {
00997                                 break;
00998                         }
00999                         discard_level--;
01000                 }
01001                 if (discard_level == mCurrentDiscardLevel)
01002                 {
01003                         // unable to increase the discard level
01004                         return FALSE;
01005                 }
01006                 return createGLTexture(discard_level, imageraw);
01007         }
01008         else
01009         {
01010 #if !LL_LINUX && !LL_SOLARIS
01011                  // *FIX: This should not be skipped for the linux client.
01012                 llerrs << "LLImageGL::setDiscardLevel() called on image without mipmaps" << llendl;
01013 #endif
01014                 return FALSE;
01015         }
01016 }
01017 
01018 BOOL LLImageGL::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents)
01019 {
01020         assert_glerror();
01021         S32 gl_discard = discard_level - mCurrentDiscardLevel;
01022         LLGLint glwidth = 0;
01023         glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth);
01024         LLGLint glheight = 0;
01025         glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_HEIGHT, (GLint*)&glheight);
01026         LLGLint glcomponents = 0 ;
01027         glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&glcomponents);
01028         assert_glerror();
01029 
01030         return glwidth >= image_width && glheight >= image_height && (GL_RGB8 == glcomponents || GL_RGBA8 == glcomponents) ;
01031 }
01032 
01033 BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok)
01034 {
01035         if (discard_level < 0)
01036         {
01037                 discard_level = mCurrentDiscardLevel;
01038         }
01039         
01040         if (mTexName == 0 || discard_level < mCurrentDiscardLevel)
01041         {
01042                 return FALSE;
01043         }
01044 
01045         S32 gl_discard = discard_level - mCurrentDiscardLevel;
01046 
01047         llverify(bindTextureInternal(0));       
01048 
01049         LLGLint glwidth = 0;
01050         glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth);
01051         if (glwidth == 0)
01052         {
01053                 // No mip data smaller than current discard level
01054                 return FALSE;
01055         }
01056 
01057         S32 width = getWidth(discard_level);
01058         S32 height = getHeight(discard_level);
01059         S32 ncomponents = getComponents();
01060         if (ncomponents == 0)
01061         {
01062                 return FALSE;
01063         }
01064 
01065         if (width <= 0 || width > 2048 || height <= 0 || height > 2048 || ncomponents < 1 || ncomponents > 4)
01066         {
01067                 llerrs << llformat("LLImageGL::readBackRaw: bogus params: %d x %d x %d",width,height,ncomponents) << llendl;
01068         }
01069         
01070         LLGLint is_compressed = 0;
01071         if (compressed_ok)
01072         {
01073                 glGetTexLevelParameteriv(mTarget, is_compressed, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed);
01074         }
01075         
01076         //-----------------------------------------------------------------------------------------------
01077         GLenum error ;
01078         while((error = glGetError()) != GL_NO_ERROR)
01079         {
01080                 llwarns << "GL Error happens before reading back texture. Error code: " << error << llendl ;
01081         }
01082         //-----------------------------------------------------------------------------------------------
01083 
01084         if (is_compressed)
01085         {
01086                 LLGLint glbytes;
01087                 glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint*)&glbytes);
01088                 if(!imageraw->allocateDataSize(width, height, ncomponents, glbytes))
01089                 {
01090                         llwarns << "Memory allocation failed for reading back texture. Size is: " << glbytes << llendl ;
01091                         llwarns << "width: " << width << "height: " << height << "components: " << ncomponents << llendl ;
01092                         return FALSE ;
01093                 }
01094 
01095                 glGetCompressedTexImageARB(mTarget, gl_discard, (GLvoid*)(imageraw->getData()));                
01096                 //stop_glerror();
01097         }
01098         else
01099         {
01100                 if(!imageraw->allocateDataSize(width, height, ncomponents))
01101                 {
01102                         llwarns << "Memory allocation failed for reading back texture." << llendl ;
01103                         llwarns << "width: " << width << "height: " << height << "components: " << ncomponents << llendl ;
01104                         return FALSE ;
01105                 }
01106                 
01107                 glGetTexImage(GL_TEXTURE_2D, gl_discard, mFormatPrimary, mFormatType, (GLvoid*)(imageraw->getData()));          
01108                 //stop_glerror();
01109         }
01110                 
01111         //-----------------------------------------------------------------------------------------------
01112         if((error = glGetError()) != GL_NO_ERROR)
01113         {
01114                 llwarns << "GL Error happens after reading back texture. Error code: " << error << llendl ;
01115                 imageraw->deleteData() ;
01116 
01117                 while((error = glGetError()) != GL_NO_ERROR)
01118                 {
01119                         llwarns << "GL Error happens after reading back texture. Error code: " << error << llendl ;
01120                 }
01121 
01122                 return FALSE ;
01123         }
01124         //-----------------------------------------------------------------------------------------------
01125         
01126         return TRUE ;
01127 }
01128 
01129 void LLImageGL::destroyGLTexture()
01130 {
01131         stop_glerror();
01132 
01133         if (mTexName != 0)
01134         {
01135                 for (int i = 0; i < gGLManager.mNumTextureUnits; i++)
01136                 {
01137                         if (sCurrentBoundTextures[i] == mTexName)
01138                         {
01139                                 unbindTexture(i, GL_TEXTURE_2D);
01140                                 stop_glerror();
01141                         }
01142                 }
01143 
01144                 sGlobalTextureMemory -= mTextureMemory;
01145                 mTextureMemory = 0;
01146 
01147                 glDeleteTextures(1, (GLuint*)&mTexName);
01148                 mTexName = 0;
01149 
01150                 stop_glerror();
01151         }
01152 }
01153 
01154 //----------------------------------------------------------------------------
01155 
01156 void LLImageGL::setClamp(BOOL clamps, BOOL clampt)
01157 {
01158         mClampS = clamps;
01159         mClampT = clampt;
01160         if (mTexName != 0)
01161         {
01162                 glTexParameteri(mBindTarget, GL_TEXTURE_WRAP_S, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
01163                 glTexParameteri(mBindTarget, GL_TEXTURE_WRAP_T, clampt ? GL_CLAMP_TO_EDGE : GL_REPEAT);
01164         }
01165         stop_glerror();
01166 }
01167 
01168 void LLImageGL::setMipFilterNearest(BOOL nearest, BOOL min_nearest)
01169 {
01170         mMipFilterNearest = nearest;
01171 
01172         if (mTexName != 0)
01173         {
01174                 if (min_nearest)
01175                 {
01176                         glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01177                 }
01178                 else if (mHasMipMaps)
01179                 {
01180                         glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
01181                 }
01182                 else
01183                 {
01184                         glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01185                 }
01186                 if (mMipFilterNearest)
01187                 {
01188                         glTexParameteri(mBindTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01189                 }
01190                 else 
01191                 {
01192                         glTexParameteri(mBindTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01193                 }
01194                 if (gGLManager.mHasAnisotropic)
01195                 {
01196                         if (sGlobalUseAnisotropic && !mMipFilterNearest)
01197                         {
01198                                 F32 largest_anisotropy;
01199                                 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_anisotropy);
01200                                 glTexParameterf(mBindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_anisotropy);
01201                         }
01202                         else
01203                         {
01204                                 glTexParameterf(mBindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
01205                         }
01206                 }
01207         }
01208         
01209         stop_glerror();
01210 }
01211 
01212 BOOL LLImageGL::getIsResident(BOOL test_now)
01213 {
01214         if (test_now)
01215         {
01216                 if (mTexName != 0)
01217                 {
01218                         glAreTexturesResident(1, (GLuint*)&mTexName, &mIsResident);
01219                 }
01220                 else
01221                 {
01222                         mIsResident = FALSE;
01223                 }
01224         }
01225 
01226         return mIsResident;
01227 }
01228 
01229 S32 LLImageGL::getHeight(S32 discard_level) const
01230 {
01231         if (discard_level < 0)
01232         {
01233                 discard_level = mCurrentDiscardLevel;
01234         }
01235         S32 height = mHeight >> discard_level;
01236         if (height < 1) height = 1;
01237         return height;
01238 }
01239 
01240 S32 LLImageGL::getWidth(S32 discard_level) const
01241 {
01242         if (discard_level < 0)
01243         {
01244                 discard_level = mCurrentDiscardLevel;
01245         }
01246         S32 width = mWidth >> discard_level;
01247         if (width < 1) width = 1;
01248         return width;
01249 }
01250 
01251 S32 LLImageGL::getBytes(S32 discard_level) const
01252 {
01253         if (discard_level < 0)
01254         {
01255                 discard_level = mCurrentDiscardLevel;
01256         }
01257         S32 w = mWidth>>discard_level;
01258         S32 h = mHeight>>discard_level;
01259         if (w == 0) w = 1;
01260         if (h == 0) h = 1;
01261         return dataFormatBytes(mFormatPrimary, w, h);
01262 }
01263 
01264 S32 LLImageGL::getMipBytes(S32 discard_level) const
01265 {
01266         if (discard_level < 0)
01267         {
01268                 discard_level = mCurrentDiscardLevel;
01269         }
01270         S32 w = mWidth>>discard_level;
01271         S32 h = mHeight>>discard_level;
01272         S32 res = dataFormatBytes(mFormatPrimary, w, h);
01273         if (mUseMipMaps)
01274         {
01275                 while (w > 1 && h > 1)
01276                 {
01277                         w >>= 1; if (w == 0) w = 1;
01278                         h >>= 1; if (h == 0) h = 1;
01279                         res += dataFormatBytes(mFormatPrimary, w, h);
01280                 }
01281         }
01282         return res;
01283 }
01284 
01285 BOOL LLImageGL::getBoundRecently() const
01286 {
01287         return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME);
01288 }
01289 
01290 void LLImageGL::setTarget(const LLGLenum target, const LLGLenum bind_target)
01291 {
01292         mTarget = target;
01293         mBindTarget = bind_target;
01294 }
01295 
01296 //----------------------------------------------------------------------------
01297 
01298 // Manual Mip Generation
01299 /*
01300                 S32 width = getWidth(discard_level);
01301                 S32 height = getHeight(discard_level);
01302                 S32 w = width, h = height;
01303                 S32 nummips = 1;
01304                 while (w > 4 && h > 4)
01305                 {
01306                         w >>= 1; h >>= 1;
01307                         nummips++;
01308                 }
01309                 stop_glerror();
01310                 w = width, h = height;
01311                 const U8* prev_mip_data = 0;
01312                 const U8* cur_mip_data = 0;
01313                 for (int m=0; m<nummips; m++)
01314                 {
01315                         if (m==0)
01316                         {
01317                                 cur_mip_data = rawdata;
01318                         }
01319                         else
01320                         {
01321                                 S32 bytes = w * h * mComponents;
01322                                 U8* new_data = new U8[bytes];
01323                                 LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents);
01324                                 cur_mip_data = new_data;
01325                         }
01326                         llassert(w > 0 && h > 0 && cur_mip_data);
01327                         U8 test = cur_mip_data[w*h*mComponents-1];
01328                         {
01329                                 glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data);
01330                                 stop_glerror();
01331                         }
01332                         if (prev_mip_data && prev_mip_data != rawdata)
01333                         {
01334                                 delete prev_mip_data;
01335                         }
01336                         prev_mip_data = cur_mip_data;
01337                         w >>= 1;
01338                         h >>= 1;
01339                 }
01340                 if (prev_mip_data && prev_mip_data != rawdata)
01341                 {
01342                         delete prev_mip_data;
01343                 }
01344                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
01345                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL,  nummips);
01346 */  

Generated on Fri May 16 08:32:49 2008 for SecondLife by  doxygen 1.5.5