Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/RenderSystems/GL/src/OgreGLHardwarePixelBuffer.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 31.1 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus 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
40namespace Ogre {
41//-----------------------------------------------------------------------------
42GLHardwarePixelBuffer::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//----------------------------------------------------------------------------- 
52GLHardwarePixelBuffer::~GLHardwarePixelBuffer()
53{
54        // Force free buffer
55        delete [] (uint8*)mBuffer.data;
56}
57//----------------------------------------------------------------------------- 
58void 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//----------------------------------------------------------------------------- 
67void 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//----------------------------------------------------------------------------- 
77PixelBox 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//----------------------------------------------------------------------------- 
90void 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//----------------------------------------------------------------------------- 
102void 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//----------------------------------------------------------------------------- 
145void 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//-----------------------------------------------------------------------------
184void 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//----------------------------------------------------------------------------- 
191void 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//----------------------------------------------------------------------------- 
197void 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
203GLTextureBuffer::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}
283GLTextureBuffer::~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//-----------------------------------------------------------------------------
296void 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//----------------------------------------------------------------------------- 
420void 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//----------------------------------------------------------------------------- 
459void 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//-----------------------------------------------------------------------------
480void 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//----------------------------------------------------------------------------- 
498void 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
522void 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
720void 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
800RenderTexture *GLTextureBuffer::getRenderTarget(size_t zoffset)
801{
802    assert(mUsage & TU_RENDERTARGET);
803    assert(zoffset < mDepth);
804    return mSliceTRT[zoffset];
805}
806//********* GLRenderBuffer
807//-----------------------------------------------------------------------------
808GLRenderBuffer::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//-----------------------------------------------------------------------------
822GLRenderBuffer::~GLRenderBuffer()
823{
824    /// Generate renderbuffer
825    glDeleteRenderbuffersEXT(1, &mRenderbufferID);
826}
827//----------------------------------------------------------------------------- 
828void 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};
Note: See TracBrowser for help on using the repository browser.