source: OGRE/trunk/ogrenew/RenderSystems/GL/src/OgreGLHardwarePixelBuffer.cpp @ 657

Revision 657, 13.8 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

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-2005 The OGRE Team
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-----------------------------------------------------------------------------
24*/
25#include "OgreGLHardwarePixelBuffer.h"
26#include "OgreGLTexture.h"
27#include "OgreGLSupport.h"
28#include "OgreGLPixelFormat.h"
29#include "OgreException.h"
30#include "OgreLogManager.h"
31#include "OgreStringConverter.h"
32#include "OgreBitwise.h"
33
34namespace Ogre {
35//-----------------------------------------------------------------------------
36GLHardwarePixelBuffer::GLHardwarePixelBuffer(GLenum target, GLuint id, GLint face, GLint level, Usage usage, bool crappyCard):
37        HardwarePixelBuffer(0, 0, 0, PF_UNKNOWN, usage, false, false),
38        mType(TYPE_TEXTURE),
39        mTarget(target), mTextureID(id), mFace(face), mLevel(level), mSoftwareMipmap(crappyCard)
40{
41        // devise mWidth, mHeight and mDepth and mFormat
42        GLint value;
43       
44        glBindTexture( mTarget, mTextureID );
45       
46        // Get face identifier
47        mFaceTarget = mTarget;
48        if(mTarget == GL_TEXTURE_CUBE_MAP)
49                mFaceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
50       
51        // Get width
52        glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_WIDTH, &value);
53        mWidth = value;
54       
55        // Get height
56        if(target == GL_TEXTURE_1D)
57                value = 1;      // Height always 1 for 1D textures
58        else
59                glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_HEIGHT, &value);
60        mHeight = value;
61       
62        // Get depth
63        if(target != GL_TEXTURE_3D)
64                value = 1; // Depth always 1 for non-3D textures
65        else
66                glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_DEPTH, &value);
67        mDepth = value;
68
69        // Get format
70        glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_INTERNAL_FORMAT, &value);
71        int mGLInternalFormat = value;
72        mFormat = GLPixelUtil::getClosestOGREFormat(value);
73       
74        // Default
75        mRowPitch = mWidth;
76        mSlicePitch = mHeight*mWidth;
77        mSizeInBytes = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);
78       
79        // Log a message
80        /*
81        std::stringstream str;
82        str << "GLHardwarePixelBuffer constructed for texture " << mTextureID
83                << " face " << mFace << " level " << mLevel << ": "
84                << "width=" << mWidth << " height="<< mHeight << " depth=" << mDepth
85                << "format=" << PixelUtil::getFormatName(mFormat) << "(internal 0x"
86                << std::hex << value << ")";
87        LogManager::getSingleton().logMessage(
88                LML_NORMAL, str.str());
89        */
90        // Set up pixel box
91        mBuffer = PixelBox(mWidth, mHeight, mDepth, mFormat);
92       
93    if(mWidth==0 || mHeight==0 || mDepth==0)
94        /// We are invalid, do not allocate a buffer
95        return;
96        // Allocate buffer
97        if(mUsage & HBU_STATIC)
98                allocateBuffer();
99}
100
101//----------------------------------------------------------------------------- 
102GLHardwarePixelBuffer::~GLHardwarePixelBuffer()
103{
104        // Force free buffer
105        delete [] (uint8*)mBuffer.data;
106}
107//----------------------------------------------------------------------------- 
108void GLHardwarePixelBuffer::allocateBuffer()
109{
110        if(mBuffer.data)
111                // Already allocated
112                return;
113        mBuffer.data = new uint8[mSizeInBytes];
114        // TODO: use PBO if we're HBU_DYNAMIC
115}
116//----------------------------------------------------------------------------- 
117void GLHardwarePixelBuffer::freeBuffer()
118{
119        // Free buffer if we're STATIC to save memory
120        if(mUsage & HBU_STATIC)
121        {
122                delete [] (uint8*)mBuffer.data;
123                mBuffer.data = 0;
124        }
125}
126//----------------------------------------------------------------------------- 
127PixelBox GLHardwarePixelBuffer::lockImpl(const Image::Box lockBox,  LockOptions options)
128{
129        allocateBuffer();
130        //if(!(mUsage & HBU_WRITEONLY) && options!=HBU_DISCARD)
131        if(options == HBL_READ_ONLY)
132                // Download the old contents of the texture
133                download(mBuffer);
134        return mBuffer.getSubVolume(lockBox);
135}
136//----------------------------------------------------------------------------- 
137void GLHardwarePixelBuffer::unlockImpl(void)
138{
139        // From buffer to card
140        upload(mCurrentLock);
141       
142        freeBuffer();
143}
144//-----------------------------------------------------------------------------
145void GLHardwarePixelBuffer::upload(const PixelBox &data)
146{
147        glBindTexture( mTarget, mTextureID );
148        if(PixelUtil::isCompressed(data.format))
149        {
150                if(data.format != mFormat || !data.isConsecutive())
151                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
152                        "Compressed images must be consecutive, in the source format",
153                        "GLHardwarePixelBuffer::upload");
154                GLenum format = GLPixelUtil::getClosestGLInternalFormat(mFormat);
155                // Data must be consecutive and at beginning of buffer as PixelStorei not allowed
156                // for compressed formats
157                switch(mTarget) {
158                        case GL_TEXTURE_1D:
159                                glCompressedTexSubImage1DARB_ptr(GL_TEXTURE_1D, mLevel,
160                                        data.left,
161                                        data.getWidth(),
162                                        format, data.getConsecutiveSize(),
163                                        data.data);
164                                break;
165                        case GL_TEXTURE_2D:
166                        case GL_TEXTURE_CUBE_MAP:
167                                glCompressedTexSubImage2DARB_ptr(mFaceTarget, mLevel,
168                                        data.left, data.top,
169                                        data.getWidth(), data.getHeight(),
170                                        format, data.getConsecutiveSize(),
171                                        data.data);
172                                break;
173                        case GL_TEXTURE_3D:
174                                glCompressedTexSubImage3DARB_ptr(GL_TEXTURE_3D, mLevel,
175                                        data.left, data.top, data.front,
176                                        data.getWidth(), data.getHeight(), data.getDepth(),
177                                        format, data.getConsecutiveSize(),
178                                        data.data);
179                                break;
180                }
181               
182        }
183        else if(mSoftwareMipmap)
184        {
185                GLint internalFormat;
186                glGetTexLevelParameteriv(mTarget, mLevel, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat);
187                if(data.getWidth() != data.rowPitch)
188                        glPixelStorei(GL_UNPACK_ROW_LENGTH, data.rowPitch);
189                if(data.getHeight()*data.getWidth() != data.slicePitch)
190                        glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth()));
191                glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
192               
193                switch(mTarget)
194                {
195                case GL_TEXTURE_1D:
196                        gluBuild1DMipmaps(
197                                GL_TEXTURE_1D, internalFormat,
198                                data.getWidth(),
199                                GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format),
200                                data.data);
201                        break;
202                case GL_TEXTURE_2D:
203                case GL_TEXTURE_CUBE_MAP:
204                        gluBuild2DMipmaps(
205                                mFaceTarget,
206                                internalFormat, data.getWidth(), data.getHeight(),
207                                GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format),
208                                data.data);
209                        break;         
210                case GL_TEXTURE_3D:
211                        /* Requires GLU 1.3 which is harder to come by than cards doing hardware mipmapping
212                                Most 3D textures don't need mipmaps?
213                        gluBuild3DMipmaps(
214                                GL_TEXTURE_3D, internalFormat,
215                                data.getWidth(), data.getHeight(), data.getDepth(),
216                                GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format),
217                                data.data);
218                        */
219                        glTexImage3D(
220                                GL_TEXTURE_3D, 0, internalFormat,
221                                data.getWidth(), data.getHeight(), data.getDepth(), 0,
222                                GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format),
223                                data.data );
224                        break;
225                }
226        }
227        else
228        {
229                if(data.getWidth() != data.rowPitch)
230                        glPixelStorei(GL_UNPACK_ROW_LENGTH, data.rowPitch);
231                if(data.getHeight()*data.getWidth() != data.slicePitch)
232                        glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth()));
233                if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) {
234                        // Standard alignment of 4 is not right
235                        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
236                }
237                switch(mTarget) {
238                        case GL_TEXTURE_1D:
239                                glTexSubImage1D(GL_TEXTURE_1D, mLevel,
240                                        data.left,
241                                        data.getWidth(),
242                                        GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format),
243                                        data.data);
244                                break;
245                        case GL_TEXTURE_2D:
246                        case GL_TEXTURE_CUBE_MAP:
247                                glTexSubImage2D(mFaceTarget, mLevel,
248                                        data.left, data.top,
249                                        data.getWidth(), data.getHeight(),
250                                        GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format),
251                                        data.data);
252                                break;
253                        case GL_TEXTURE_3D:
254#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
255                                // GLX doesn't define it
256                                glTexSubImage3DEXT(
257#else
258                                glTexSubImage3D(
259#endif
260                                        GL_TEXTURE_3D, mLevel,
261                                        data.left, data.top, data.front,
262                                        data.getWidth(), data.getHeight(), data.getDepth(),
263                                        GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format),
264                                        data.data);
265                                break;
266                }       
267        }
268        // Restore defaults
269        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
270        glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
271        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
272}
273//----------------------------------------------------------------------------- 
274void GLHardwarePixelBuffer::download(const PixelBox &data)
275{
276        if(data.getWidth() != getWidth() ||
277                data.getHeight() != getHeight() ||
278                data.getDepth() != getDepth())
279                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "only download of entire buffer is supported by GL",
280                        "GLHardwarePixelBuffer::download");
281        glBindTexture( mTarget, mTextureID );
282        if(PixelUtil::isCompressed(data.format))
283        {
284                if(data.format != mFormat || !data.isConsecutive())
285                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
286                        "Compressed images must be consecutive, in the source format",
287                        "GLHardwarePixelBuffer::upload");
288                // Data must be consecutive and at beginning of buffer as PixelStorei not allowed
289                // for compressed formate
290                glGetCompressedTexImageARB_ptr(mFaceTarget, mLevel, data.data);
291        }
292        else
293        {
294                if(data.getWidth() != data.rowPitch)
295                        glPixelStorei(GL_PACK_ROW_LENGTH, data.rowPitch);
296                if(data.getHeight()*data.getWidth() != data.slicePitch)
297                        glPixelStorei(GL_PACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth()));
298                if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) {
299                        // Standard alignment of 4 is not right
300                        glPixelStorei(GL_PACK_ALIGNMENT, 1);
301                }
302                // We can only get the entire texture
303                glGetTexImage(mFaceTarget, mLevel,
304                        GLPixelUtil::getGLOriginFormat(data.format), GLPixelUtil::getGLOriginDataType(data.format),
305                        data.data);
306                // Restore defaults
307                glPixelStorei(GL_PACK_ROW_LENGTH, 0);
308                glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
309                glPixelStorei(GL_PACK_ALIGNMENT, 4);
310        }
311}
312//----------------------------------------------------------------------------- 
313void GLHardwarePixelBuffer::blit(HardwarePixelBuffer *src, const Image::Box &srcBox, const Image::Box &dstBox)
314{
315        // this can be sped up with some copy pixels primitive, sometimes, maybe
316        HardwarePixelBuffer::blit(src, srcBox, dstBox);
317}
318//----------------------------------------------------------------------------- 
319void GLHardwarePixelBuffer::blitFromMemory(const PixelBox &src, const Image::Box &dstBox)
320{
321        if(!mBuffer.contains(dstBox))
322                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "destination box out of range",
323                 "GLHardwarePixelBuffer::blitFromMemory");
324        PixelBox scaled;
325       
326        if(src.getWidth() != dstBox.getWidth() ||
327                src.getHeight() != dstBox.getHeight() ||
328                src.getDepth() != dstBox.getDepth())
329        {
330                // Scale to destination size. Use DevIL and not iluScale because ILU screws up for
331                // floating point textures and cannot cope with 3D images.
332                // This also does pixel format conversion if needed
333                allocateBuffer();
334                scaled = mBuffer.getSubVolume(dstBox);
335                Image::scale(src, scaled, Image::FILTER_BILINEAR);
336        }
337        else if(GLPixelUtil::getGLOriginFormat(src.format) == 0)
338        {
339                // Extents match, but format is not accepted as valid source format for GL
340                // do conversion in temporary buffer
341                allocateBuffer();
342                scaled = mBuffer.getSubVolume(dstBox);
343                PixelUtil::bulkPixelConversion(src, scaled);
344        }
345        else
346        {
347                // No scaling or conversion needed
348                scaled = src;
349                // Set extents for upload
350                scaled.left = dstBox.left;
351                scaled.right = dstBox.right;
352                scaled.top = dstBox.top;
353                scaled.bottom = dstBox.bottom;
354                scaled.front = dstBox.front;
355                scaled.back = dstBox.back;
356        }
357       
358        upload(scaled);
359        freeBuffer();
360}
361//----------------------------------------------------------------------------- 
362void GLHardwarePixelBuffer::blitToMemory(const Image::Box &srcBox, const PixelBox &dst)
363{
364        if(!mBuffer.contains(srcBox))
365                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "source box out of range",
366                 "GLHardwarePixelBuffer::blitToMemory");
367        if(srcBox.left == 0 && srcBox.right == getWidth() &&
368           srcBox.top == 0 && srcBox.bottom == getHeight() &&
369           srcBox.front == 0 && srcBox.back == getDepth() &&
370           dst.getWidth() == getWidth() &&
371           dst.getHeight() == getHeight() &&
372           dst.getDepth() == getDepth() &&
373           GLPixelUtil::getGLOriginFormat(dst.format) != 0)
374        {
375                // The direct case: the user wants the entire texture in a format supported by GL
376                // so we don't need an intermediate buffer
377                download(dst);
378        }
379        else
380        {
381                // Use buffer for intermediate copy
382                allocateBuffer();
383                // Download entire buffer
384                download(mBuffer);
385                if(srcBox.getWidth() != dst.getWidth() ||
386                        srcBox.getHeight() != dst.getHeight() ||
387                        srcBox.getDepth() != dst.getDepth())
388                {
389                        // We need scaling
390                        Image::scale(mBuffer.getSubVolume(srcBox), dst, Image::FILTER_BILINEAR);
391                }
392                else
393                {
394                        // Just copy the bit that we need
395                        PixelUtil::bulkPixelConversion(mBuffer.getSubVolume(srcBox), dst);
396                }
397                freeBuffer();
398        }
399}
400
401
402};
Note: See TracBrowser for help on using the repository browser.