| 1 | /* | 
|---|
| 2 | ----------------------------------------------------------------------------- | 
|---|
| 3 | This source file is part of OGRE | 
|---|
| 4 |     (Object-oriented Graphics Rendering Engine) | 
|---|
| 5 | For the latest info, see http://www.ogre3d.org/ | 
|---|
| 6 |  | 
|---|
| 7 | Copyright (c) 2000-2006 Torus Knot Software Ltd | 
|---|
| 8 | Also see acknowledgements in Readme.html | 
|---|
| 9 |  | 
|---|
| 10 | This program is free software; you can redistribute it and/or modify it under | 
|---|
| 11 | the terms of the GNU Lesser General Public License as published by the Free Software | 
|---|
| 12 | Foundation; either version 2 of the License, or (at your option) any later | 
|---|
| 13 | version. | 
|---|
| 14 |  | 
|---|
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT | 
|---|
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
|---|
| 17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. | 
|---|
| 18 |  | 
|---|
| 19 | You should have received a copy of the GNU Lesser General Public License along with | 
|---|
| 20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 
|---|
| 21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to | 
|---|
| 22 | http://www.gnu.org/copyleft/lesser.txt. | 
|---|
| 23 |  | 
|---|
| 24 | You may alternatively use this source under the terms of a specific version of | 
|---|
| 25 | the OGRE Unrestricted License provided you have obtained such a license from | 
|---|
| 26 | Torus Knot Software Ltd. | 
|---|
| 27 | ----------------------------------------------------------------------------- | 
|---|
| 28 | */ | 
|---|
| 29 | #include "OgreGLHardwarePixelBuffer.h" | 
|---|
| 30 | #include "OgreGLTexture.h" | 
|---|
| 31 | #include "OgreGLSupport.h" | 
|---|
| 32 | #include "OgreGLPixelFormat.h" | 
|---|
| 33 | #include "OgreException.h" | 
|---|
| 34 | #include "OgreLogManager.h" | 
|---|
| 35 | #include "OgreStringConverter.h" | 
|---|
| 36 | #include "OgreBitwise.h" | 
|---|
| 37 | #include "OgreGLFBORenderTexture.h" | 
|---|
| 38 | #include "OgreRoot.h" | 
|---|
| 39 |  | 
|---|
| 40 | namespace Ogre { | 
|---|
| 41 | //-----------------------------------------------------------------------------  | 
|---|
| 42 | GLHardwarePixelBuffer::GLHardwarePixelBuffer(size_t mWidth, size_t mHeight, size_t mDepth, | 
|---|
| 43 |                 PixelFormat mFormat, | 
|---|
| 44 |                 HardwareBuffer::Usage usage): | 
|---|
| 45 |       HardwarePixelBuffer(mWidth, mHeight, mDepth, mFormat, usage, false, false), | 
|---|
| 46 |       mBuffer(mWidth, mHeight, mDepth, mFormat), | 
|---|
| 47 |       mGLInternalFormat(GL_NONE) | 
|---|
| 48 | { | 
|---|
| 49 | } | 
|---|
| 50 |  | 
|---|
| 51 | //-----------------------------------------------------------------------------   | 
|---|
| 52 | GLHardwarePixelBuffer::~GLHardwarePixelBuffer() | 
|---|
| 53 | { | 
|---|
| 54 |         // Force free buffer | 
|---|
| 55 |         delete [] (uint8*)mBuffer.data; | 
|---|
| 56 | } | 
|---|
| 57 | //-----------------------------------------------------------------------------   | 
|---|
| 58 | void GLHardwarePixelBuffer::allocateBuffer() | 
|---|
| 59 | { | 
|---|
| 60 |         if(mBuffer.data) | 
|---|
| 61 |                 // Already allocated | 
|---|
| 62 |                 return; | 
|---|
| 63 |         mBuffer.data = new uint8[mSizeInBytes]; | 
|---|
| 64 |         // TODO: use PBO if we're HBU_DYNAMIC | 
|---|
| 65 | } | 
|---|
| 66 | //-----------------------------------------------------------------------------   | 
|---|
| 67 | void GLHardwarePixelBuffer::freeBuffer() | 
|---|
| 68 | { | 
|---|
| 69 |         // Free buffer if we're STATIC to save memory | 
|---|
| 70 |         if(mUsage & HBU_STATIC) | 
|---|
| 71 |         { | 
|---|
| 72 |                 delete [] (uint8*)mBuffer.data; | 
|---|
| 73 |                 mBuffer.data = 0; | 
|---|
| 74 |         } | 
|---|
| 75 | } | 
|---|
| 76 | //-----------------------------------------------------------------------------   | 
|---|
| 77 | PixelBox GLHardwarePixelBuffer::lockImpl(const Image::Box lockBox,  LockOptions options) | 
|---|
| 78 | { | 
|---|
| 79 |         allocateBuffer(); | 
|---|
| 80 |         if(options != HardwareBuffer::HBL_DISCARD | 
|---|
| 81 |                 && (mUsage & HardwareBuffer::HBU_WRITE_ONLY) == 0)  | 
|---|
| 82 |         { | 
|---|
| 83 |                 // Download the old contents of the texture | 
|---|
| 84 |                 download(mBuffer); | 
|---|
| 85 |         } | 
|---|
| 86 |         mCurrentLockOptions = options; | 
|---|
| 87 |         return mBuffer.getSubVolume(lockBox); | 
|---|
| 88 | } | 
|---|
| 89 | //-----------------------------------------------------------------------------   | 
|---|
| 90 | void GLHardwarePixelBuffer::unlockImpl(void) | 
|---|
| 91 | { | 
|---|
| 92 |         if (mCurrentLockOptions != HardwareBuffer::HBL_READ_ONLY) | 
|---|
| 93 |         { | 
|---|
| 94 |                 // From buffer to card, only upload if was locked for writing | 
|---|
| 95 |                 upload(mCurrentLock); | 
|---|
| 96 |         } | 
|---|
| 97 |          | 
|---|
| 98 |         freeBuffer(); | 
|---|
| 99 | } | 
|---|
| 100 |  | 
|---|
| 101 | //-----------------------------------------------------------------------------   | 
|---|
| 102 | void GLHardwarePixelBuffer::blitFromMemory(const PixelBox &src, const Image::Box &dstBox) | 
|---|
| 103 | { | 
|---|
| 104 |         if(!mBuffer.contains(dstBox)) | 
|---|
| 105 |                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "destination box out of range", | 
|---|
| 106 |                  "GLHardwarePixelBuffer::blitFromMemory"); | 
|---|
| 107 |         PixelBox scaled; | 
|---|
| 108 |          | 
|---|
| 109 |         if(src.getWidth() != dstBox.getWidth() || | 
|---|
| 110 |                 src.getHeight() != dstBox.getHeight() || | 
|---|
| 111 |                 src.getDepth() != dstBox.getDepth()) | 
|---|
| 112 |         { | 
|---|
| 113 |                 // Scale to destination size. Use DevIL and not iluScale because ILU screws up for  | 
|---|
| 114 |                 // floating point textures and cannot cope with 3D images. | 
|---|
| 115 |                 // This also does pixel format conversion if needed | 
|---|
| 116 |                 allocateBuffer(); | 
|---|
| 117 |                 scaled = mBuffer.getSubVolume(dstBox); | 
|---|
| 118 |                 Image::scale(src, scaled, Image::FILTER_BILINEAR); | 
|---|
| 119 |         } | 
|---|
| 120 |         else if(GLPixelUtil::getGLOriginFormat(src.format) == 0) | 
|---|
| 121 |         { | 
|---|
| 122 |                 // Extents match, but format is not accepted as valid source format for GL | 
|---|
| 123 |                 // do conversion in temporary buffer | 
|---|
| 124 |                 allocateBuffer(); | 
|---|
| 125 |                 scaled = mBuffer.getSubVolume(dstBox); | 
|---|
| 126 |                 PixelUtil::bulkPixelConversion(src, scaled); | 
|---|
| 127 |         } | 
|---|
| 128 |         else | 
|---|
| 129 |         { | 
|---|
| 130 |                 // No scaling or conversion needed | 
|---|
| 131 |                 scaled = src; | 
|---|
| 132 |                 // Set extents for upload | 
|---|
| 133 |                 scaled.left = dstBox.left; | 
|---|
| 134 |                 scaled.right = dstBox.right; | 
|---|
| 135 |                 scaled.top = dstBox.top; | 
|---|
| 136 |                 scaled.bottom = dstBox.bottom; | 
|---|
| 137 |                 scaled.front = dstBox.front; | 
|---|
| 138 |                 scaled.back = dstBox.back; | 
|---|
| 139 |         } | 
|---|
| 140 |          | 
|---|
| 141 |         upload(scaled); | 
|---|
| 142 |         freeBuffer(); | 
|---|
| 143 | } | 
|---|
| 144 | //-----------------------------------------------------------------------------   | 
|---|
| 145 | void GLHardwarePixelBuffer::blitToMemory(const Image::Box &srcBox, const PixelBox &dst) | 
|---|
| 146 | { | 
|---|
| 147 |         if(!mBuffer.contains(srcBox)) | 
|---|
| 148 |                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "source box out of range", | 
|---|
| 149 |                  "GLHardwarePixelBuffer::blitToMemory"); | 
|---|
| 150 |         if(srcBox.left == 0 && srcBox.right == getWidth() && | 
|---|
| 151 |            srcBox.top == 0 && srcBox.bottom == getHeight() && | 
|---|
| 152 |            srcBox.front == 0 && srcBox.back == getDepth() && | 
|---|
| 153 |            dst.getWidth() == getWidth() && | 
|---|
| 154 |            dst.getHeight() == getHeight() && | 
|---|
| 155 |            dst.getDepth() == getDepth() && | 
|---|
| 156 |            GLPixelUtil::getGLOriginFormat(dst.format) != 0) | 
|---|
| 157 |         { | 
|---|
| 158 |                 // The direct case: the user wants the entire texture in a format supported by GL | 
|---|
| 159 |                 // so we don't need an intermediate buffer | 
|---|
| 160 |                 download(dst); | 
|---|
| 161 |         } | 
|---|
| 162 |         else | 
|---|
| 163 |         { | 
|---|
| 164 |                 // Use buffer for intermediate copy | 
|---|
| 165 |                 allocateBuffer(); | 
|---|
| 166 |                 // Download entire buffer | 
|---|
| 167 |                 download(mBuffer); | 
|---|
| 168 |                 if(srcBox.getWidth() != dst.getWidth() || | 
|---|
| 169 |                         srcBox.getHeight() != dst.getHeight() || | 
|---|
| 170 |                         srcBox.getDepth() != dst.getDepth()) | 
|---|
| 171 |                 { | 
|---|
| 172 |                         // We need scaling | 
|---|
| 173 |                         Image::scale(mBuffer.getSubVolume(srcBox), dst, Image::FILTER_BILINEAR); | 
|---|
| 174 |                 } | 
|---|
| 175 |                 else | 
|---|
| 176 |                 { | 
|---|
| 177 |                         // Just copy the bit that we need | 
|---|
| 178 |                         PixelUtil::bulkPixelConversion(mBuffer.getSubVolume(srcBox), dst); | 
|---|
| 179 |                 } | 
|---|
| 180 |                 freeBuffer(); | 
|---|
| 181 |         } | 
|---|
| 182 | } | 
|---|
| 183 | //----------------------------------------------------------------------------- | 
|---|
| 184 | void GLHardwarePixelBuffer::upload(const PixelBox &data) | 
|---|
| 185 | { | 
|---|
| 186 |     OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,  | 
|---|
| 187 |                 "Upload not possible for this pixelbuffer type", | 
|---|
| 188 |         "GLHardwarePixelBuffer::upload"); | 
|---|
| 189 | } | 
|---|
| 190 | //-----------------------------------------------------------------------------   | 
|---|
| 191 | void GLHardwarePixelBuffer::download(const PixelBox &data) | 
|---|
| 192 | { | 
|---|
| 193 |     OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Download not possible for this pixelbuffer type", | 
|---|
| 194 |         "GLHardwarePixelBuffer::download"); | 
|---|
| 195 | } | 
|---|
| 196 | //-----------------------------------------------------------------------------   | 
|---|
| 197 | void GLHardwarePixelBuffer::bindToFramebuffer(GLenum attachment, size_t zoffset) | 
|---|
| 198 | { | 
|---|
| 199 |     OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Framebuffer bind not possible for this pixelbuffer type", | 
|---|
| 200 |         "GLHardwarePixelBuffer::bindToFramebuffer"); | 
|---|
| 201 | } | 
|---|
| 202 | //********* GLTextureBuffer | 
|---|
| 203 | GLTextureBuffer::GLTextureBuffer(const String &baseName, GLenum target, GLuint id, GLint face, GLint level, Usage usage, bool crappyCard): | 
|---|
| 204 |         GLHardwarePixelBuffer(0, 0, 0, PF_UNKNOWN, usage), | 
|---|
| 205 |         mTarget(target), mTextureID(id), mFace(face), mLevel(level), mSoftwareMipmap(crappyCard) | 
|---|
| 206 | { | 
|---|
| 207 |         // devise mWidth, mHeight and mDepth and mFormat | 
|---|
| 208 |         GLint value; | 
|---|
| 209 |          | 
|---|
| 210 |         glBindTexture( mTarget, mTextureID ); | 
|---|
| 211 |          | 
|---|
| 212 |         // Get face identifier | 
|---|
| 213 |         mFaceTarget = mTarget; | 
|---|
| 214 |         if(mTarget == GL_TEXTURE_CUBE_MAP) | 
|---|
| 215 |                 mFaceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; | 
|---|
| 216 |          | 
|---|
| 217 |         // Get width | 
|---|
| 218 |         glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_WIDTH, &value); | 
|---|
| 219 |         mWidth = value; | 
|---|
| 220 |          | 
|---|
| 221 |         // Get height | 
|---|
| 222 |         if(target == GL_TEXTURE_1D) | 
|---|
| 223 |                 value = 1;      // Height always 1 for 1D textures | 
|---|
| 224 |         else | 
|---|
| 225 |                 glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_HEIGHT, &value); | 
|---|
| 226 |         mHeight = value; | 
|---|
| 227 |          | 
|---|
| 228 |         // Get depth | 
|---|
| 229 |         if(target != GL_TEXTURE_3D) | 
|---|
| 230 |                 value = 1; // Depth always 1 for non-3D textures | 
|---|
| 231 |         else | 
|---|
| 232 |                 glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_DEPTH, &value); | 
|---|
| 233 |         mDepth = value; | 
|---|
| 234 |  | 
|---|
| 235 |         // Get format | 
|---|
| 236 |         glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_INTERNAL_FORMAT, &value); | 
|---|
| 237 |         mGLInternalFormat = value; | 
|---|
| 238 |         mFormat = GLPixelUtil::getClosestOGREFormat(value); | 
|---|
| 239 |          | 
|---|
| 240 |         // Default | 
|---|
| 241 |         mRowPitch = mWidth; | 
|---|
| 242 |         mSlicePitch = mHeight*mWidth; | 
|---|
| 243 |         mSizeInBytes = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat); | 
|---|
| 244 |          | 
|---|
| 245 |         // Log a message | 
|---|
| 246 |         /* | 
|---|
| 247 |         std::stringstream str; | 
|---|
| 248 |         str << "GLHardwarePixelBuffer constructed for texture " << mTextureID  | 
|---|
| 249 |                 << " face " << mFace << " level " << mLevel << ": " | 
|---|
| 250 |                 << "width=" << mWidth << " height="<< mHeight << " depth=" << mDepth | 
|---|
| 251 |                 << "format=" << PixelUtil::getFormatName(mFormat) << "(internal 0x" | 
|---|
| 252 |                 << std::hex << value << ")"; | 
|---|
| 253 |         LogManager::getSingleton().logMessage(  | 
|---|
| 254 |                 LML_NORMAL, str.str()); | 
|---|
| 255 |         */ | 
|---|
| 256 |         // Set up pixel box | 
|---|
| 257 |         mBuffer = PixelBox(mWidth, mHeight, mDepth, mFormat); | 
|---|
| 258 |          | 
|---|
| 259 |     if(mWidth==0 || mHeight==0 || mDepth==0) | 
|---|
| 260 |         /// We are invalid, do not allocate a buffer | 
|---|
| 261 |         return; | 
|---|
| 262 |         // Allocate buffer | 
|---|
| 263 |         //if(mUsage & HBU_STATIC) | 
|---|
| 264 |         //      allocateBuffer(); | 
|---|
| 265 |     // Is this a render target? | 
|---|
| 266 |     if(mUsage & TU_RENDERTARGET) | 
|---|
| 267 |     { | 
|---|
| 268 |         // Create render target for each slice | 
|---|
| 269 |         mSliceTRT.reserve(mDepth); | 
|---|
| 270 |         for(size_t zoffset=0; zoffset<mDepth; ++zoffset) | 
|---|
| 271 |         { | 
|---|
| 272 |             String name; | 
|---|
| 273 |                         name = "rtt/" + baseName + "/" + StringConverter::toString((size_t)this); | 
|---|
| 274 |             GLSurfaceDesc target; | 
|---|
| 275 |             target.buffer = this; | 
|---|
| 276 |             target.zoffset = zoffset; | 
|---|
| 277 |             RenderTexture *trt = GLRTTManager::getSingleton().createRenderTexture(name, target); | 
|---|
| 278 |             mSliceTRT.push_back(trt); | 
|---|
| 279 |             Root::getSingleton().getRenderSystem()->attachRenderTarget(*mSliceTRT[zoffset]); | 
|---|
| 280 |         } | 
|---|
| 281 |         } | 
|---|
| 282 | } | 
|---|
| 283 | GLTextureBuffer::~GLTextureBuffer() | 
|---|
| 284 | { | 
|---|
| 285 |     if(mUsage & TU_RENDERTARGET) | 
|---|
| 286 |     { | 
|---|
| 287 |         // Delete all render targets that are not yet deleted via _clearSliceRTT because the rendertarget | 
|---|
| 288 |         // was deleted by the user. | 
|---|
| 289 |         for (SliceTRT::const_iterator it = mSliceTRT.begin(); it != mSliceTRT.end(); ++it) | 
|---|
| 290 |         { | 
|---|
| 291 |             Root::getSingleton().getRenderSystem()->destroyRenderTarget((*it)->getName()); | 
|---|
| 292 |         } | 
|---|
| 293 |         } | 
|---|
| 294 | } | 
|---|
| 295 | //----------------------------------------------------------------------------- | 
|---|
| 296 | void GLTextureBuffer::upload(const PixelBox &data) | 
|---|
| 297 | { | 
|---|
| 298 |         glBindTexture( mTarget, mTextureID ); | 
|---|
| 299 |         if(PixelUtil::isCompressed(data.format)) | 
|---|
| 300 |         { | 
|---|
| 301 |                 if(data.format != mFormat || !data.isConsecutive()) | 
|---|
| 302 |                         OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,  | 
|---|
| 303 |                         "Compressed images must be consecutive, in the source format", | 
|---|
| 304 |                         "GLHardwarePixelBuffer::upload"); | 
|---|
| 305 |                 GLenum format = GLPixelUtil::getClosestGLInternalFormat(mFormat); | 
|---|
| 306 |                 // Data must be consecutive and at beginning of buffer as PixelStorei not allowed | 
|---|
| 307 |                 // for compressed formats | 
|---|
| 308 |                 switch(mTarget) { | 
|---|
| 309 |                         case GL_TEXTURE_1D: | 
|---|
| 310 |                                 glCompressedTexSubImage1DARB(GL_TEXTURE_1D, mLevel,  | 
|---|
| 311 |                                         data.left, | 
|---|
| 312 |                                         data.getWidth(), | 
|---|
| 313 |                                         format, data.getConsecutiveSize(), | 
|---|
| 314 |                                         data.data); | 
|---|
| 315 |                                 break; | 
|---|
| 316 |                         case GL_TEXTURE_2D: | 
|---|
| 317 |                         case GL_TEXTURE_CUBE_MAP: | 
|---|
| 318 |                                 glCompressedTexSubImage2DARB(mFaceTarget, mLevel,  | 
|---|
| 319 |                                         data.left, data.top,  | 
|---|
| 320 |                                         data.getWidth(), data.getHeight(), | 
|---|
| 321 |                                         format, data.getConsecutiveSize(), | 
|---|
| 322 |                                         data.data); | 
|---|
| 323 |                                 break; | 
|---|
| 324 |                         case GL_TEXTURE_3D: | 
|---|
| 325 |                                 glCompressedTexSubImage3DARB(GL_TEXTURE_3D, mLevel,  | 
|---|
| 326 |                                         data.left, data.top, data.front, | 
|---|
| 327 |                                         data.getWidth(), data.getHeight(), data.getDepth(), | 
|---|
| 328 |                                         format, data.getConsecutiveSize(), | 
|---|
| 329 |                                         data.data); | 
|---|
| 330 |                                 break; | 
|---|
| 331 |                 } | 
|---|
| 332 |                  | 
|---|
| 333 |         }  | 
|---|
| 334 |         else if(mSoftwareMipmap) | 
|---|
| 335 |         { | 
|---|
| 336 |                 GLint internalFormat; | 
|---|
| 337 |                 glGetTexLevelParameteriv(mTarget, mLevel, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat); | 
|---|
| 338 |                 if(data.getWidth() != data.rowPitch) | 
|---|
| 339 |                         glPixelStorei(GL_UNPACK_ROW_LENGTH, data.rowPitch); | 
|---|
| 340 |                 if(data.getHeight()*data.getWidth() != data.slicePitch) | 
|---|
| 341 |                         glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth())); | 
|---|
| 342 |                 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | 
|---|
| 343 |                  | 
|---|
| 344 |                 switch(mTarget) | 
|---|
| 345 |                 { | 
|---|
| 346 |                 case GL_TEXTURE_1D: | 
|---|
| 347 |                         gluBuild1DMipmaps( | 
|---|
| 348 |                                 GL_TEXTURE_1D, internalFormat, | 
|---|
| 349 |                                 data.getWidth(), | 
|---|
| 350 |                                 GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format), | 
|---|
| 351 |                                 data.data); | 
|---|
| 352 |                         break; | 
|---|
| 353 |                 case GL_TEXTURE_2D: | 
|---|
| 354 |                 case GL_TEXTURE_CUBE_MAP: | 
|---|
| 355 |                         gluBuild2DMipmaps( | 
|---|
| 356 |                                 mFaceTarget, | 
|---|
| 357 |                                 internalFormat, data.getWidth(), data.getHeight(),  | 
|---|
| 358 |                                 GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format),  | 
|---|
| 359 |                                 data.data); | 
|---|
| 360 |                         break;           | 
|---|
| 361 |                 case GL_TEXTURE_3D: | 
|---|
| 362 |                         /* Requires GLU 1.3 which is harder to come by than cards doing hardware mipmapping | 
|---|
| 363 |                                 Most 3D textures don't need mipmaps? | 
|---|
| 364 |                         gluBuild3DMipmaps( | 
|---|
| 365 |                                 GL_TEXTURE_3D, internalFormat,  | 
|---|
| 366 |                                 data.getWidth(), data.getHeight(), data.getDepth(), | 
|---|
| 367 |                                 GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format), | 
|---|
| 368 |                                 data.data); | 
|---|
| 369 |                         */ | 
|---|
| 370 |                         glTexImage3D( | 
|---|
| 371 |                                 GL_TEXTURE_3D, 0, internalFormat,  | 
|---|
| 372 |                                 data.getWidth(), data.getHeight(), data.getDepth(), 0,  | 
|---|
| 373 |                                 GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format), | 
|---|
| 374 |                                 data.data ); | 
|---|
| 375 |                         break; | 
|---|
| 376 |                 } | 
|---|
| 377 |         }  | 
|---|
| 378 |         else | 
|---|
| 379 |         { | 
|---|
| 380 |                 if(data.getWidth() != data.rowPitch) | 
|---|
| 381 |                         glPixelStorei(GL_UNPACK_ROW_LENGTH, data.rowPitch); | 
|---|
| 382 |                 if(data.getHeight()*data.getWidth() != data.slicePitch) | 
|---|
| 383 |                         glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth())); | 
|---|
| 384 |                 if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) { | 
|---|
| 385 |                         // Standard alignment of 4 is not right | 
|---|
| 386 |                         glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | 
|---|
| 387 |                 } | 
|---|
| 388 |                 switch(mTarget) { | 
|---|
| 389 |                         case GL_TEXTURE_1D: | 
|---|
| 390 |                                 glTexSubImage1D(GL_TEXTURE_1D, mLevel,  | 
|---|
| 391 |                                         data.left, | 
|---|
| 392 |                                         data.getWidth(), | 
|---|
| 393 |                                         GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format), | 
|---|
| 394 |                                         data.data); | 
|---|
| 395 |                                 break; | 
|---|
| 396 |                         case GL_TEXTURE_2D: | 
|---|
| 397 |                         case GL_TEXTURE_CUBE_MAP: | 
|---|
| 398 |                                 glTexSubImage2D(mFaceTarget, mLevel,  | 
|---|
| 399 |                                         data.left, data.top,  | 
|---|
| 400 |                                         data.getWidth(), data.getHeight(), | 
|---|
| 401 |                                         GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format), | 
|---|
| 402 |                                         data.data); | 
|---|
| 403 |                                 break; | 
|---|
| 404 |                         case GL_TEXTURE_3D: | 
|---|
| 405 |                                 glTexSubImage3D( | 
|---|
| 406 |                                         GL_TEXTURE_3D, mLevel,  | 
|---|
| 407 |                                         data.left, data.top, data.front, | 
|---|
| 408 |                                         data.getWidth(), data.getHeight(), data.getDepth(), | 
|---|
| 409 |                                         GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format), | 
|---|
| 410 |                                         data.data); | 
|---|
| 411 |                                 break; | 
|---|
| 412 |                 }        | 
|---|
| 413 |         } | 
|---|
| 414 |         // Restore defaults | 
|---|
| 415 |         glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | 
|---|
| 416 |         glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); | 
|---|
| 417 |         glPixelStorei(GL_UNPACK_ALIGNMENT, 4); | 
|---|
| 418 | } | 
|---|
| 419 | //-----------------------------------------------------------------------------   | 
|---|
| 420 | void GLTextureBuffer::download(const PixelBox &data) | 
|---|
| 421 | { | 
|---|
| 422 |         if(data.getWidth() != getWidth() || | 
|---|
| 423 |                 data.getHeight() != getHeight() || | 
|---|
| 424 |                 data.getDepth() != getDepth()) | 
|---|
| 425 |                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "only download of entire buffer is supported by GL", | 
|---|
| 426 |                         "GLHardwarePixelBuffer::download"); | 
|---|
| 427 |         glBindTexture( mTarget, mTextureID ); | 
|---|
| 428 |         if(PixelUtil::isCompressed(data.format)) | 
|---|
| 429 |         { | 
|---|
| 430 |                 if(data.format != mFormat || !data.isConsecutive()) | 
|---|
| 431 |                         OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,  | 
|---|
| 432 |                         "Compressed images must be consecutive, in the source format", | 
|---|
| 433 |                         "GLHardwarePixelBuffer::upload"); | 
|---|
| 434 |                 // Data must be consecutive and at beginning of buffer as PixelStorei not allowed | 
|---|
| 435 |                 // for compressed formate | 
|---|
| 436 |                 glGetCompressedTexImageARB(mFaceTarget, mLevel, data.data); | 
|---|
| 437 |         }  | 
|---|
| 438 |         else | 
|---|
| 439 |         { | 
|---|
| 440 |                 if(data.getWidth() != data.rowPitch) | 
|---|
| 441 |                         glPixelStorei(GL_PACK_ROW_LENGTH, data.rowPitch); | 
|---|
| 442 |                 if(data.getHeight()*data.getWidth() != data.slicePitch) | 
|---|
| 443 |                         glPixelStorei(GL_PACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth())); | 
|---|
| 444 |                 if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) { | 
|---|
| 445 |                         // Standard alignment of 4 is not right | 
|---|
| 446 |                         glPixelStorei(GL_PACK_ALIGNMENT, 1); | 
|---|
| 447 |                 } | 
|---|
| 448 |                 // We can only get the entire texture | 
|---|
| 449 |                 glGetTexImage(mFaceTarget, mLevel,  | 
|---|
| 450 |                         GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format), | 
|---|
| 451 |                         data.data); | 
|---|
| 452 |                 // Restore defaults | 
|---|
| 453 |                 glPixelStorei(GL_PACK_ROW_LENGTH, 0); | 
|---|
| 454 |                 glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0); | 
|---|
| 455 |                 glPixelStorei(GL_PACK_ALIGNMENT, 4); | 
|---|
| 456 |         } | 
|---|
| 457 | } | 
|---|
| 458 | //-----------------------------------------------------------------------------   | 
|---|
| 459 | void GLTextureBuffer::bindToFramebuffer(GLenum attachment, size_t zoffset) | 
|---|
| 460 | { | 
|---|
| 461 |     assert(zoffset < mDepth); | 
|---|
| 462 |     switch(mTarget) | 
|---|
| 463 |     { | 
|---|
| 464 |     case GL_TEXTURE_1D: | 
|---|
| 465 |         glFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, attachment, | 
|---|
| 466 |                             mFaceTarget, mTextureID, mLevel); | 
|---|
| 467 |         break; | 
|---|
| 468 |     case GL_TEXTURE_2D: | 
|---|
| 469 |     case GL_TEXTURE_CUBE_MAP: | 
|---|
| 470 |         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, | 
|---|
| 471 |                             mFaceTarget, mTextureID, mLevel); | 
|---|
| 472 |         break; | 
|---|
| 473 |     case GL_TEXTURE_3D: | 
|---|
| 474 |         glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, attachment, | 
|---|
| 475 |                             mFaceTarget, mTextureID, mLevel, zoffset); | 
|---|
| 476 |         break; | 
|---|
| 477 |     } | 
|---|
| 478 | } | 
|---|
| 479 | //----------------------------------------------------------------------------- | 
|---|
| 480 | void GLTextureBuffer::copyFromFramebuffer(size_t zoffset) | 
|---|
| 481 | { | 
|---|
| 482 |     glBindTexture(mTarget, mTextureID); | 
|---|
| 483 |     switch(mTarget) | 
|---|
| 484 |     { | 
|---|
| 485 |     case GL_TEXTURE_1D: | 
|---|
| 486 |         glCopyTexSubImage1D(mFaceTarget, mLevel, 0, 0, 0, mWidth); | 
|---|
| 487 |         break; | 
|---|
| 488 |     case GL_TEXTURE_2D: | 
|---|
| 489 |     case GL_TEXTURE_CUBE_MAP: | 
|---|
| 490 |         glCopyTexSubImage2D(mFaceTarget, mLevel, 0, 0, 0, 0, mWidth, mHeight); | 
|---|
| 491 |         break; | 
|---|
| 492 |     case GL_TEXTURE_3D: | 
|---|
| 493 |         glCopyTexSubImage3D(mFaceTarget, mLevel, 0, 0, zoffset, 0, 0, mWidth, mHeight); | 
|---|
| 494 |         break; | 
|---|
| 495 |     } | 
|---|
| 496 | } | 
|---|
| 497 | //-----------------------------------------------------------------------------   | 
|---|
| 498 | void GLTextureBuffer::blit(const HardwarePixelBufferSharedPtr &src, const Image::Box &srcBox, const Image::Box &dstBox) | 
|---|
| 499 | { | 
|---|
| 500 |     GLTextureBuffer *srct = static_cast<GLTextureBuffer *>(src.getPointer()); | 
|---|
| 501 |     /// Check for FBO support first | 
|---|
| 502 |     /// Destination texture must be 1D, 2D, 3D, or Cube | 
|---|
| 503 |     /// Source texture must be 1D, 2D or 3D | 
|---|
| 504 |     if(GLEW_EXT_framebuffer_object && | 
|---|
| 505 |         (srct->mTarget==GL_TEXTURE_1D||srct->mTarget==GL_TEXTURE_2D||srct->mTarget==GL_TEXTURE_3D)) | 
|---|
| 506 |     { | 
|---|
| 507 |         blitFromTexture(srct, srcBox, dstBox); | 
|---|
| 508 |     } | 
|---|
| 509 |     else | 
|---|
| 510 |     { | 
|---|
| 511 |         GLHardwarePixelBuffer::blit(src, srcBox, dstBox); | 
|---|
| 512 |     } | 
|---|
| 513 | } | 
|---|
| 514 |  | 
|---|
| 515 | //-----------------------------------------------------------------------------   | 
|---|
| 516 | /// Very fast texture-to-texture blitter and hardware bi/trilinear scaling implementation using FBO | 
|---|
| 517 | /// Destination texture must be 1D, 2D, 3D, or Cube | 
|---|
| 518 | /// Source texture must be 1D, 2D or 3D | 
|---|
| 519 | /// Supports compressed formats as both source and destination format, it will use the hardware DXT compressor | 
|---|
| 520 | /// if available. | 
|---|
| 521 | /// @author W.J. van der Laan | 
|---|
| 522 | void GLTextureBuffer::blitFromTexture(GLTextureBuffer *src, const Image::Box &srcBox, const Image::Box &dstBox) | 
|---|
| 523 | { | 
|---|
| 524 |     //std::cerr << "GLTextureBuffer::blitFromTexture " << | 
|---|
| 525 |     //src->mTextureID << ":" << srcBox.left << "," << srcBox.top << "," << srcBox.right << "," << srcBox.bottom << " " <<  | 
|---|
| 526 |     //mTextureID << ":" << dstBox.left << "," << dstBox.top << "," << dstBox.right << "," << dstBox.bottom << std::endl; | 
|---|
| 527 |     /// Store reference to FBO manager | 
|---|
| 528 |     GLFBOManager *fboMan = static_cast<GLFBOManager *>(GLRTTManager::getSingletonPtr()); | 
|---|
| 529 |      | 
|---|
| 530 |     /// Save and clear GL state for rendering | 
|---|
| 531 |     glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT |  | 
|---|
| 532 |         GL_FOG_BIT | GL_LIGHTING_BIT | GL_POLYGON_BIT | GL_SCISSOR_BIT | GL_STENCIL_BUFFER_BIT | | 
|---|
| 533 |         GL_TEXTURE_BIT | GL_VIEWPORT_BIT); | 
|---|
| 534 |  | 
|---|
| 535 |     /// Disable alpha, depth and scissor testing, disable blending,  | 
|---|
| 536 |     /// disable culling, disble lighting, disable fog and reset foreground | 
|---|
| 537 |     /// colour. | 
|---|
| 538 |     glDisable(GL_ALPHA_TEST); | 
|---|
| 539 |     glDisable(GL_DEPTH_TEST); | 
|---|
| 540 |     glDisable(GL_SCISSOR_TEST); | 
|---|
| 541 |     glDisable(GL_BLEND); | 
|---|
| 542 |     glDisable(GL_CULL_FACE); | 
|---|
| 543 |     glDisable(GL_LIGHTING); | 
|---|
| 544 |     glDisable(GL_FOG); | 
|---|
| 545 |     glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | 
|---|
| 546 |      | 
|---|
| 547 |     /// Save and reset matrices | 
|---|
| 548 |     glMatrixMode(GL_MODELVIEW); | 
|---|
| 549 |     glPushMatrix(); | 
|---|
| 550 |     glLoadIdentity(); | 
|---|
| 551 |     glMatrixMode(GL_PROJECTION); | 
|---|
| 552 |     glPushMatrix(); | 
|---|
| 553 |     glLoadIdentity(); | 
|---|
| 554 |     glMatrixMode(GL_TEXTURE); | 
|---|
| 555 |     glPushMatrix(); | 
|---|
| 556 |     glLoadIdentity(); | 
|---|
| 557 |      | 
|---|
| 558 |     /// Set up source texture | 
|---|
| 559 |     glBindTexture(src->mTarget, src->mTextureID); | 
|---|
| 560 |      | 
|---|
| 561 |     /// Set filtering modes depending on the dimensions and source | 
|---|
| 562 |     if(srcBox.getWidth()==dstBox.getWidth() && | 
|---|
| 563 |         srcBox.getHeight()==dstBox.getHeight() && | 
|---|
| 564 |         srcBox.getDepth()==dstBox.getDepth()) | 
|---|
| 565 |     { | 
|---|
| 566 |         /// Dimensions match -- use nearest filtering (fastest and pixel correct) | 
|---|
| 567 |         glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | 
|---|
| 568 |         glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 
|---|
| 569 |     } | 
|---|
| 570 |     else | 
|---|
| 571 |     { | 
|---|
| 572 |         /// Dimensions don't match -- use bi or trilinear filtering depending on the | 
|---|
| 573 |         /// source texture. | 
|---|
| 574 |         if(src->mUsage & TU_AUTOMIPMAP) | 
|---|
| 575 |         { | 
|---|
| 576 |             /// Automatic mipmaps, we can safely use trilinear filter which | 
|---|
| 577 |             /// brings greatly imporoved quality for minimisation. | 
|---|
| 578 |             glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | 
|---|
| 579 |             glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);     | 
|---|
| 580 |         } | 
|---|
| 581 |         else | 
|---|
| 582 |         { | 
|---|
| 583 |             /// Manual mipmaps, stay safe with bilinear filtering so that no | 
|---|
| 584 |             /// intermipmap leakage occurs. | 
|---|
| 585 |             glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 
|---|
| 586 |             glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 
|---|
| 587 |         } | 
|---|
| 588 |     } | 
|---|
| 589 |     /// Clamp to edge (fastest) | 
|---|
| 590 |     glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 
|---|
| 591 |     glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 
|---|
| 592 |     glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); | 
|---|
| 593 |      | 
|---|
| 594 |     /// Set origin base level mipmap to make sure we source from the right mip | 
|---|
| 595 |     /// level. | 
|---|
| 596 |     glTexParameteri(src->mTarget, GL_TEXTURE_BASE_LEVEL, src->mLevel); | 
|---|
| 597 |      | 
|---|
| 598 |     /// Store old binding so it can be restored later | 
|---|
| 599 |     GLint oldfb; | 
|---|
| 600 |     glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &oldfb); | 
|---|
| 601 |      | 
|---|
| 602 |     /// Set up temporary FBO | 
|---|
| 603 |     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboMan->getTemporaryFBO()); | 
|---|
| 604 |      | 
|---|
| 605 |     GLuint tempTex = 0; | 
|---|
| 606 |     if(!fboMan->checkFormat(mFormat)) | 
|---|
| 607 |     { | 
|---|
| 608 |         /// If target format not directly supported, create intermediate texture | 
|---|
| 609 |         GLenum tempFormat = GLPixelUtil::getClosestGLInternalFormat(fboMan->getSupportedAlternative(mFormat)); | 
|---|
| 610 |         glGenTextures(1, &tempTex); | 
|---|
| 611 |         glBindTexture(GL_TEXTURE_2D, tempTex); | 
|---|
| 612 |         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); | 
|---|
| 613 |         /// Allocate temporary texture of the size of the destination area | 
|---|
| 614 |         glTexImage2D(GL_TEXTURE_2D, 0, tempFormat,  | 
|---|
| 615 |             GLPixelUtil::optionalPO2(dstBox.getWidth()), GLPixelUtil::optionalPO2(dstBox.getHeight()),  | 
|---|
| 616 |             0, GL_RGBA, GL_UNSIGNED_BYTE, 0); | 
|---|
| 617 |         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, | 
|---|
| 618 |             GL_TEXTURE_2D, tempTex, 0); | 
|---|
| 619 |         /// Set viewport to size of destination slice | 
|---|
| 620 |         glViewport(0, 0, dstBox.getWidth(), dstBox.getHeight()); | 
|---|
| 621 |     } | 
|---|
| 622 |     else | 
|---|
| 623 |     { | 
|---|
| 624 |         /// We are going to bind directly, so set viewport to size and position of destination slice | 
|---|
| 625 |         glViewport(dstBox.left, dstBox.top, dstBox.getWidth(), dstBox.getHeight()); | 
|---|
| 626 |     } | 
|---|
| 627 |      | 
|---|
| 628 |     /// Process each destination slice | 
|---|
| 629 |     for(size_t slice=dstBox.front; slice<dstBox.back; ++slice) | 
|---|
| 630 |     { | 
|---|
| 631 |         if(!tempTex) | 
|---|
| 632 |         { | 
|---|
| 633 |             /// Bind directly | 
|---|
| 634 |             bindToFramebuffer(GL_COLOR_ATTACHMENT0_EXT, slice); | 
|---|
| 635 |         } | 
|---|
| 636 |         /// Calculate source texture coordinates | 
|---|
| 637 |         float u1 = (float)srcBox.left / (float)src->mWidth; | 
|---|
| 638 |         float v1 = (float)srcBox.top / (float)src->mHeight; | 
|---|
| 639 |         float u2 = (float)srcBox.right / (float)src->mWidth; | 
|---|
| 640 |         float v2 = (float)srcBox.bottom / (float)src->mHeight; | 
|---|
| 641 |         /// Calculate source slice for this destination slice | 
|---|
| 642 |         float w = (float)(slice - dstBox.front) / (float)dstBox.getDepth(); | 
|---|
| 643 |         /// Get slice # in source | 
|---|
| 644 |         w = w * (float)srcBox.getDepth() + srcBox.front; | 
|---|
| 645 |         /// Normalise to texture coordinate in 0.0 .. 1.0 | 
|---|
| 646 |         w = (w+0.5f) / (float)src->mDepth; | 
|---|
| 647 |          | 
|---|
| 648 |         /// Finally we're ready to rumble | 
|---|
| 649 |         glBindTexture(src->mTarget, src->mTextureID); | 
|---|
| 650 |         glEnable(src->mTarget); | 
|---|
| 651 |         glBegin(GL_QUADS); | 
|---|
| 652 |         glTexCoord3f(u1, v1, w); | 
|---|
| 653 |         glVertex2f(-1.0f, -1.0f); | 
|---|
| 654 |         glTexCoord3f(u2, v1, w); | 
|---|
| 655 |         glVertex2f(1.0f, -1.0f); | 
|---|
| 656 |         glTexCoord3f(u2, v2, w); | 
|---|
| 657 |         glVertex2f(1.0f, 1.0f); | 
|---|
| 658 |         glTexCoord3f(u1, v2, w); | 
|---|
| 659 |         glVertex2f(-1.0f, 1.0f); | 
|---|
| 660 |         glEnd(); | 
|---|
| 661 |         glDisable(src->mTarget); | 
|---|
| 662 |          | 
|---|
| 663 |         if(tempTex) | 
|---|
| 664 |         { | 
|---|
| 665 |             /// Copy temporary texture | 
|---|
| 666 |             glBindTexture(mTarget, mTextureID); | 
|---|
| 667 |             switch(mTarget) | 
|---|
| 668 |             { | 
|---|
| 669 |             case GL_TEXTURE_1D: | 
|---|
| 670 |                 glCopyTexSubImage1D(mFaceTarget, mLevel,  | 
|---|
| 671 |                     dstBox.left,  | 
|---|
| 672 |                     0, 0, dstBox.getWidth()); | 
|---|
| 673 |                 break; | 
|---|
| 674 |             case GL_TEXTURE_2D: | 
|---|
| 675 |             case GL_TEXTURE_CUBE_MAP: | 
|---|
| 676 |                 glCopyTexSubImage2D(mFaceTarget, mLevel,  | 
|---|
| 677 |                     dstBox.left, dstBox.top,  | 
|---|
| 678 |                     0, 0, dstBox.getWidth(), dstBox.getHeight()); | 
|---|
| 679 |                 break; | 
|---|
| 680 |             case GL_TEXTURE_3D: | 
|---|
| 681 |                 glCopyTexSubImage3D(mFaceTarget, mLevel,  | 
|---|
| 682 |                     dstBox.left, dstBox.top, slice,  | 
|---|
| 683 |                     0, 0, dstBox.getWidth(), dstBox.getHeight()); | 
|---|
| 684 |                 break; | 
|---|
| 685 |             } | 
|---|
| 686 |         } | 
|---|
| 687 |     } | 
|---|
| 688 |     /// Finish up  | 
|---|
| 689 |     if(!tempTex) | 
|---|
| 690 |     { | 
|---|
| 691 |         /// Generate mipmaps | 
|---|
| 692 |         if(mUsage & TU_AUTOMIPMAP) | 
|---|
| 693 |         { | 
|---|
| 694 |             glBindTexture(mTarget, mTextureID); | 
|---|
| 695 |             glGenerateMipmapEXT(mTarget); | 
|---|
| 696 |         } | 
|---|
| 697 |     } | 
|---|
| 698 |  | 
|---|
| 699 |     /// Reset source texture to sane state | 
|---|
| 700 |     glBindTexture(src->mTarget, src->mTextureID); | 
|---|
| 701 |     glTexParameteri(src->mTarget, GL_TEXTURE_BASE_LEVEL, 0); | 
|---|
| 702 |      | 
|---|
| 703 |     /// Detach texture from temporary framebuffer | 
|---|
| 704 |     glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, | 
|---|
| 705 |                     GL_RENDERBUFFER_EXT, 0); | 
|---|
| 706 |     /// Restore old framebuffer | 
|---|
| 707 |     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, oldfb); | 
|---|
| 708 |     /// Restore matrix stacks and render state | 
|---|
| 709 |     glMatrixMode(GL_TEXTURE); | 
|---|
| 710 |     glPopMatrix(); | 
|---|
| 711 |     glMatrixMode(GL_PROJECTION); | 
|---|
| 712 |     glPopMatrix(); | 
|---|
| 713 |     glMatrixMode(GL_MODELVIEW); | 
|---|
| 714 |     glPopMatrix(); | 
|---|
| 715 |     glPopAttrib(); | 
|---|
| 716 |     glDeleteTextures(1, &tempTex); | 
|---|
| 717 | } | 
|---|
| 718 | //-----------------------------------------------------------------------------   | 
|---|
| 719 | /// blitFromMemory doing hardware trilinear scaling | 
|---|
| 720 | void GLTextureBuffer::blitFromMemory(const PixelBox &src_orig, const Image::Box &dstBox) | 
|---|
| 721 | { | 
|---|
| 722 |     /// Fall back to normal GLHardwarePixelBuffer::blitFromMemory in case  | 
|---|
| 723 |     /// - FBO is not supported | 
|---|
| 724 |     /// - Either source or target is luminance due doesn't looks like supported by hardware | 
|---|
| 725 |     /// - the source dimensions match the destination ones, in which case no scaling is needed | 
|---|
| 726 |     if(!GLEW_EXT_framebuffer_object || | 
|---|
| 727 |         PixelUtil::isLuminance(src_orig.format) || | 
|---|
| 728 |         PixelUtil::isLuminance(mFormat) || | 
|---|
| 729 |         (src_orig.getWidth() == dstBox.getWidth() && | 
|---|
| 730 |         src_orig.getHeight() == dstBox.getHeight() && | 
|---|
| 731 |         src_orig.getDepth() == dstBox.getDepth())) | 
|---|
| 732 |     { | 
|---|
| 733 |         GLHardwarePixelBuffer::blitFromMemory(src_orig, dstBox); | 
|---|
| 734 |         return; | 
|---|
| 735 |     } | 
|---|
| 736 |     if(!mBuffer.contains(dstBox)) | 
|---|
| 737 |         OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "destination box out of range", | 
|---|
| 738 |                     "GLHardwarePixelBuffer::blitFromMemory"); | 
|---|
| 739 |     /// For scoped deletion of conversion buffer | 
|---|
| 740 |     MemoryDataStreamPtr buf; | 
|---|
| 741 |     PixelBox src; | 
|---|
| 742 |      | 
|---|
| 743 |     /// First, convert the srcbox to a OpenGL compatible pixel format | 
|---|
| 744 |     if(GLPixelUtil::getGLOriginFormat(src_orig.format) == 0) | 
|---|
| 745 |     { | 
|---|
| 746 |         /// Convert to buffer internal format | 
|---|
| 747 |         buf.bind(new MemoryDataStream( | 
|---|
| 748 |                 PixelUtil::getMemorySize(src_orig.getWidth(), src_orig.getHeight(), src_orig.getDepth(), | 
|---|
| 749 |                                          mFormat))); | 
|---|
| 750 |         src = PixelBox(src_orig.getWidth(), src_orig.getHeight(), src_orig.getDepth(), mFormat, buf->getPtr()); | 
|---|
| 751 |         PixelUtil::bulkPixelConversion(src_orig, src); | 
|---|
| 752 |     } | 
|---|
| 753 |     else | 
|---|
| 754 |     { | 
|---|
| 755 |         /// No conversion needed | 
|---|
| 756 |         src = src_orig; | 
|---|
| 757 |     } | 
|---|
| 758 |      | 
|---|
| 759 |     /// Create temporary texture to store source data | 
|---|
| 760 |     GLuint id; | 
|---|
| 761 |     GLenum target = (src.getDepth()!=1)?GL_TEXTURE_3D:GL_TEXTURE_2D; | 
|---|
| 762 |     GLsizei width = GLPixelUtil::optionalPO2(src.getWidth()); | 
|---|
| 763 |     GLsizei height = GLPixelUtil::optionalPO2(src.getHeight()); | 
|---|
| 764 |     GLsizei depth = GLPixelUtil::optionalPO2(src.getDepth()); | 
|---|
| 765 |     GLenum format = GLPixelUtil::getClosestGLInternalFormat(src.format); | 
|---|
| 766 |      | 
|---|
| 767 |     /// Generate texture name | 
|---|
| 768 |     glGenTextures(1, &id); | 
|---|
| 769 |      | 
|---|
| 770 |     /// Set texture type | 
|---|
| 771 |     glBindTexture(target, id); | 
|---|
| 772 |      | 
|---|
| 773 |     /// Set automatic mipmap generation; nice for minimisation | 
|---|
| 774 |     glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 1000 ); | 
|---|
| 775 |     glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE ); | 
|---|
| 776 |      | 
|---|
| 777 |     /// Allocate texture memory | 
|---|
| 778 |     if(target == GL_TEXTURE_3D) | 
|---|
| 779 |         glTexImage3D(target, 0, format, width, height, depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); | 
|---|
| 780 |     else | 
|---|
| 781 |         glTexImage2D(target, 0, format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); | 
|---|
| 782 |  | 
|---|
| 783 |     /// GL texture buffer | 
|---|
| 784 |     GLTextureBuffer tex(StringUtil::BLANK, target, id, 0, 0, (Usage)(TU_AUTOMIPMAP|HBU_STATIC_WRITE_ONLY), false); | 
|---|
| 785 |      | 
|---|
| 786 |     /// Upload data to 0,0,0 in temporary texture | 
|---|
| 787 |     PixelBox tempTarget(src.getWidth(), src.getHeight(), src.getDepth(), src.format, src.data); | 
|---|
| 788 |     tempTarget.rowPitch = src.rowPitch; | 
|---|
| 789 |     tempTarget.slicePitch = src.slicePitch; | 
|---|
| 790 |     tex.upload(tempTarget); | 
|---|
| 791 |      | 
|---|
| 792 |     /// Blit | 
|---|
| 793 |     blitFromTexture(&tex, tempTarget, dstBox); | 
|---|
| 794 |      | 
|---|
| 795 |     /// Delete temp texture | 
|---|
| 796 |     glDeleteTextures(1, &id); | 
|---|
| 797 | } | 
|---|
| 798 | //-----------------------------------------------------------------------------     | 
|---|
| 799 |  | 
|---|
| 800 | RenderTexture *GLTextureBuffer::getRenderTarget(size_t zoffset) | 
|---|
| 801 | { | 
|---|
| 802 |     assert(mUsage & TU_RENDERTARGET); | 
|---|
| 803 |     assert(zoffset < mDepth); | 
|---|
| 804 |     return mSliceTRT[zoffset]; | 
|---|
| 805 | } | 
|---|
| 806 | //********* GLRenderBuffer | 
|---|
| 807 | //-----------------------------------------------------------------------------  | 
|---|
| 808 | GLRenderBuffer::GLRenderBuffer(GLenum format, size_t width, size_t height): | 
|---|
| 809 |     GLHardwarePixelBuffer(width, height, 1, GLPixelUtil::getClosestOGREFormat(format),HBU_WRITE_ONLY) | 
|---|
| 810 | { | 
|---|
| 811 |     mGLInternalFormat = format; | 
|---|
| 812 |     /// Generate renderbuffer | 
|---|
| 813 |     glGenRenderbuffersEXT(1, &mRenderbufferID); | 
|---|
| 814 |     /// Bind it to FBO | 
|---|
| 815 |     glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mRenderbufferID); | 
|---|
| 816 |      | 
|---|
| 817 |     /// Allocate storage for depth buffer | 
|---|
| 818 |     glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, | 
|---|
| 819 |                         width, height); | 
|---|
| 820 | } | 
|---|
| 821 | //-----------------------------------------------------------------------------  | 
|---|
| 822 | GLRenderBuffer::~GLRenderBuffer() | 
|---|
| 823 | { | 
|---|
| 824 |     /// Generate renderbuffer | 
|---|
| 825 |     glDeleteRenderbuffersEXT(1, &mRenderbufferID); | 
|---|
| 826 | } | 
|---|
| 827 | //-----------------------------------------------------------------------------   | 
|---|
| 828 | void GLRenderBuffer::bindToFramebuffer(GLenum attachment, size_t zoffset) | 
|---|
| 829 | { | 
|---|
| 830 |     assert(zoffset < mDepth); | 
|---|
| 831 |     glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, | 
|---|
| 832 |                         GL_RENDERBUFFER_EXT, mRenderbufferID); | 
|---|
| 833 | } | 
|---|
| 834 |  | 
|---|
| 835 | }; | 
|---|