source: OGRE/trunk/ogre_changes/RenderSystems/GL/src/OgreGLTexture.cpp @ 657

Revision 657, 15.2 KB checked in by mattausch, 18 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://ogre.sourceforge.net/
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
26#include "OgreGLTexture.h"
27#include "OgreGLSupport.h"
28#include "OgreGLPixelFormat.h"
29#include "OgreGLHardwarePixelBuffer.h"
30
31#include "OgreTextureManager.h"
32#include "OgreImage.h"
33#include "OgreLogManager.h"
34#include "OgreCamera.h"
35#include "OgreException.h"
36#include "OgreRoot.h"
37#include "OgreCodec.h"
38#include "OgreImageCodec.h"
39#include "OgreStringConverter.h"
40
41#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
42#   include <windows.h>
43#   include <wingdi.h>
44#endif
45
46namespace Ogre {
47
48    unsigned int mostSignificantBitSet(unsigned int value)
49        {
50                unsigned int result = 0;
51                while (value != 0) {
52                        ++result;
53                        value >>= 1;
54                }
55                return result-1;
56        }
57
58    GLTexture::GLTexture(ResourceManager* creator, const String& name,
59        ResourceHandle handle, const String& group, bool isManual,
60        ManualResourceLoader* loader, GLSupport& support)
61        : Texture(creator, name, handle, group, isManual, loader),
62        mTextureID(0), mGLSupport(support)
63    {
64    }
65
66
67    GLTexture::~GLTexture()
68    {
69        // have to call this here reather than in Resource destructor
70        // since calling virtual methods in base destructors causes crash
71                if (mIsLoaded)
72                {
73        unload();
74    }
75                else
76                {
77                        freeInternalResources();
78                }
79    }
80
81    GLenum GLTexture::getGLTextureTarget(void) const
82    {
83        switch(mTextureType)
84        {
85            case TEX_TYPE_1D:
86                return GL_TEXTURE_1D;
87            case TEX_TYPE_2D:
88                return GL_TEXTURE_2D;
89            case TEX_TYPE_3D:
90                return GL_TEXTURE_3D;
91            case TEX_TYPE_CUBE_MAP:
92                return GL_TEXTURE_CUBE_MAP;
93            default:
94                return 0;
95        };
96    }
97
98        //* Creation / loading methods ********************************************
99        void GLTexture::createInternalResourcesImpl(void)
100    {
101                // Adjust requested parameters to capabilities
102
103                // Check power-of-two size if required
104        unsigned int newWidth = (1 << mostSignificantBitSet(mWidth));
105        if (newWidth != mWidth)
106            newWidth <<= 1;
107
108        unsigned int newHeight = (1 << mostSignificantBitSet(mHeight));
109        if (newHeight != mHeight)
110            newHeight <<= 1;
111
112                unsigned int newDepth = (1 << mostSignificantBitSet(mDepth));
113        if (newDepth != mDepth)
114            newDepth <<= 1;
115
116        if(!Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_NON_POWER_OF_2_TEXTURES))
117                {
118                        mHeight = newHeight;
119                        mWidth = newWidth;
120                        mDepth = newDepth;
121                }
122               
123                // Check compressed texture support
124                // if a compressed format not supported, revert to PF_A8R8G8B8
125                if(PixelUtil::isCompressed(mFormat) &&
126                 !Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability( RSC_TEXTURE_COMPRESSION_DXT ))
127                {
128                        mFormat = PF_A8R8G8B8;
129                }
130                // if floating point textures not supported, revert to PF_A8R8G8B8
131                if(PixelUtil::isFloatingPoint(mFormat) &&
132                 !Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability( RSC_TEXTURE_FLOAT ))
133                {
134                        mFormat = PF_A8R8G8B8;
135                }
136               
137                // Check requested number of mipmaps
138                // Zero means create mip levels until 1x1
139                size_t maxMips = GLPixelUtil::getMaxMipmaps(mWidth, mHeight, mDepth, mFormat);
140                mNumMipmaps = mNumRequestedMipmaps;
141                if(mNumMipmaps>maxMips)
142                        mNumMipmaps = maxMips;
143               
144                // Generate texture name
145        glGenTextures( 1, &mTextureID );
146               
147                // Set texture type
148                glBindTexture( getGLTextureTarget(), mTextureID );
149       
150                // This needs to be set otherwise the texture doesn't get rendered
151        glTexParameteri( getGLTextureTarget(), GL_TEXTURE_MAX_LEVEL, mNumMipmaps );
152               
153                // If we can do automip generation and the user desires this, do so
154                mMipmapsHardwareGenerated =
155                        Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_AUTOMIPMAP);
156                if((mUsage & TU_AUTOMIPMAP) &&
157                    mNumRequestedMipmaps && mMipmapsHardwareGenerated)
158        {
159            glTexParameteri( getGLTextureTarget(), GL_GENERATE_MIPMAP, GL_TRUE );
160        }
161               
162                // Allocate internal buffer so that glTexSubImageXD can be used
163                // Internal format
164                GLenum format = GLPixelUtil::getClosestGLInternalFormat(mFormat);
165                size_t width = mWidth;
166                size_t height = mHeight;
167                size_t depth = mDepth;
168                if(PixelUtil::isCompressed(mFormat))
169                {
170                        // Compressed formats
171                        size_t size = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);
172                        // Provide temporary buffer filled with zeroes as glCompressedTexImageXD does not
173                        // accept a 0 pointer like normal glTexImageXD
174                        // Run through this process for every mipmap to pregenerate mipmap piramid
175                        uint8 *tmpdata = new uint8[size];
176                        memset(tmpdata, 0, size);
177                       
178                        for(int mip=0; mip<=mNumMipmaps; mip++)
179                        {
180                        //int mip = 0;
181                                size = PixelUtil::getMemorySize(width, height, depth, mFormat);
182                                switch(mTextureType)
183                                {
184                                        case TEX_TYPE_1D:
185                                                glCompressedTexImage1DARB_ptr(GL_TEXTURE_1D, mip, format,
186                                                        width, 0,
187                                                        size, tmpdata);
188                                                break;
189                                        case TEX_TYPE_2D:
190                                                glCompressedTexImage2DARB_ptr(GL_TEXTURE_2D, mip, format,
191                                                        width, height, 0,
192                                                        size, tmpdata);
193                                                break;
194                                        case TEX_TYPE_3D:
195                                                glCompressedTexImage3DARB_ptr(GL_TEXTURE_3D, mip, format,
196                                                        width, height, depth, 0,
197                                                        size, tmpdata);
198                                                break;
199                                        case TEX_TYPE_CUBE_MAP:
200                                                for(int face=0; face<6; face++) {
201                                                        glCompressedTexImage2DARB_ptr(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, format,
202                                                                width, height, 0,
203                                                                size, tmpdata);
204                                                }
205                                                break;
206                                };
207                                if(width>1)             width = width/2;
208                                if(height>1)    height = height/2;
209                                if(depth>1)             depth = depth/2;
210                        }
211                        delete [] tmpdata;
212                }
213                else
214                {
215                        // Run through this process to pregenerate mipmap piramid
216                        for(int mip=0; mip<=mNumMipmaps; mip++)
217                        {
218                                // Normal formats
219                                switch(mTextureType)
220                                {
221                                        case TEX_TYPE_1D:
222                                                glTexImage1D(GL_TEXTURE_1D, mip, format,
223                                                        width, 0,
224                                                        GL_RGBA, GL_UNSIGNED_BYTE, 0);
225       
226                                                break;
227                                        case TEX_TYPE_2D:
228                                                glTexImage2D(GL_TEXTURE_2D, mip, format,
229                                                        width, height, 0,
230                                                        GL_RGBA, GL_UNSIGNED_BYTE, 0);
231                                                break;
232                                        case TEX_TYPE_3D:
233                                                glTexImage3D(GL_TEXTURE_3D, mip, format,
234                                                        width, height, depth, 0,
235                                                        GL_RGBA, GL_UNSIGNED_BYTE, 0);
236                                                break;
237                                        case TEX_TYPE_CUBE_MAP:
238                                                for(int face=0; face<6; face++) {
239                                                        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, format,
240                                                                width, height, 0,
241                                                                GL_RGBA, GL_UNSIGNED_BYTE, 0);
242                                                }
243                                                break;
244                                };
245                                if(width>1)             width = width/2;
246                                if(height>1)    height = height/2;
247                                if(depth>1)             depth = depth/2;
248                        }
249                }
250                _createSurfaceList();
251                // Get final internal format
252                mFormat = getBuffer(0,0)->getFormat();
253        }
254       
255    void GLTexture::createRenderTexture(void)
256    {
257        if (this->getTextureType() != TEX_TYPE_2D)
258            OGRE_EXCEPT( Exception::UNIMPLEMENTED_FEATURE, "**** Create render texture implemented only for 2D textures!!! ****", "GLTexture::createRenderTexture" );
259
260        // Create the GL texture
261                // This already does everything neccessary
262        createInternalResources();
263    }
264       
265        void GLTexture::loadImage( const Image& img )
266    {
267        std::vector<const Image*> images;
268               
269        images.push_back(&img);
270        _loadImages(images);
271        images.clear();
272    }
273
274    void GLTexture::loadImpl()
275    {
276        if( mUsage & TU_RENDERTARGET )
277        {
278            createRenderTexture();
279            mIsLoaded = true;     
280        }
281        else
282        {
283            if(mTextureType == TEX_TYPE_1D || mTextureType == TEX_TYPE_2D ||
284                mTextureType == TEX_TYPE_3D)
285            {
286                Image img;
287                img.load(mName, mGroup);
288
289                                // If this is a cube map, set the texture type flag accordingly.
290                if (img.hasFlag(IF_CUBEMAP))
291                                        mTextureType = TEX_TYPE_CUBE_MAP;
292                                // If this is a volumetric texture set the texture type flag accordingly.
293                                if(img.getDepth() > 1)
294                                        mTextureType = TEX_TYPE_3D;
295
296                                loadImage( img );
297            }
298            else if (mTextureType == TEX_TYPE_CUBE_MAP)
299            {
300                                if(StringUtil::endsWith(getName(), ".dds"))
301                                {
302                                        // XX HACK there should be a better way to specify wether
303                                        // all faces are in the same file or not
304                                        Image img;
305                        img.load(mName, mGroup);
306                                        loadImage( img );
307                                }
308                                else
309                                {
310                                        String baseName, ext;
311                                        std::vector<Image> images(6);
312                                        std::vector<const Image*> imagePtrs;
313                                        static const String suffixes[6] = {"_rt", "_lf", "_up", "_dn", "_fr", "_bk"};
314       
315                                        for(size_t i = 0; i < 6; i++)
316                                        {
317                                                size_t pos = mName.find_last_of(".");
318                                                baseName = mName.substr(0, pos);
319                                                ext = mName.substr(pos);
320                                                String fullName = baseName + suffixes[i] + ext;
321       
322                                                images[i].load(fullName, mGroup);
323                                                imagePtrs.push_back(&images[i]);
324                                        }
325       
326                                        _loadImages( imagePtrs );
327                                }
328            }
329            else
330                OGRE_EXCEPT( Exception::UNIMPLEMENTED_FEATURE, "**** Unknown texture type ****", "GLTexture::load" );
331        }
332    }
333       
334        //*************************************************************************
335   
336    void GLTexture::freeInternalResourcesImpl()
337    {
338                mSurfaceList.clear();
339        glDeleteTextures( 1, &mTextureID );
340    }
341
342       
343        //---------------------------------------------------------------------------------------------
344        void GLTexture::_createSurfaceList()
345        {
346                mSurfaceList.clear();
347               
348                // For all faces and mipmaps, store surfaces as HardwarePixelBufferSharedPtr
349                bool wantGeneratedMips = (mUsage & TU_AUTOMIPMAP)!=0;
350               
351                // Do mipmapping in software? (uses GLU) For some cards, this is still needed. Of course,
352                // only when mipmap generation is desired.
353                bool doSoftware = wantGeneratedMips && !mMipmapsHardwareGenerated && getNumMipmaps();
354               
355                for(int face=0; face<getNumFaces(); face++)
356                {
357                        for(int mip=0; mip<=getNumMipmaps(); mip++)
358                        {
359                GLHardwarePixelBuffer *buf = new GLHardwarePixelBuffer(getGLTextureTarget(), mTextureID, face, mip,
360                                                static_cast<HardwareBuffer::Usage>(mUsage), doSoftware && mip==0);
361                                mSurfaceList.push_back(HardwarePixelBufferSharedPtr(buf));
362               
363                /// Check for error
364                if(buf->getWidth()==0 || buf->getHeight()==0 || buf->getDepth()==0)
365                {
366                    OGRE_EXCEPT(
367                        Exception::ERR_RENDERINGAPI_ERROR,
368                        "Zero sized texture surface on texture "+getName()+
369                            " face "+StringConverter::toString(face)+
370                            " mipmap "+StringConverter::toString(mip)+
371                            ". Probably, the GL driver refused to create the texture.",
372                            "GLTexture::_createSurfaceList");
373                }
374                        }
375                }
376        }
377       
378        //---------------------------------------------------------------------------------------------
379        HardwarePixelBufferSharedPtr GLTexture::getBuffer(size_t face, size_t mipmap)
380        {
381                if(face >= getNumFaces())
382                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Face index out of range",
383                                        "GLTexture::getBuffer");
384                if(mipmap > mNumMipmaps)
385                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Mipmap index out of range",
386                                        "GLTexture::getBuffer");
387                unsigned int idx = face*(mNumMipmaps+1) + mipmap;
388                assert(idx < mSurfaceList.size());
389                return mSurfaceList[idx];
390        }
391       
392        //---------------------------------------------------------------------------------------------
393    void GLRenderTexture::_copyToTexture(void)
394    {           
395        glBindTexture(GL_TEXTURE_2D, mGLTexture->getGLID());
396                       
397        glCopyTexSubImage2D(GL_TEXTURE_2D, mGLTexture->getNumMipmaps(), 0, 0,
398            0, 0, mWidth, mHeight);
399
400    }
401   
402    void GLRenderTexture::writeContentsToFile( const String & filename )
403    {
404        ImageCodec::ImageData *imgData = new ImageCodec::ImageData();
405       
406        imgData->width = mGLTexture->getWidth();
407        imgData->height = mGLTexture->getHeight();
408                imgData->depth = 1;
409        imgData->format = PF_BYTE_RGB;
410
411        // Allocate buffer
412        uchar* pBuffer = new uchar[imgData->width * imgData->height * 3];
413
414        // Read pixels
415        // I love GL: it does all the locking & colour conversion for us
416        glBindTexture(GL_TEXTURE_2D, mGLTexture->getGLID());
417        glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
418
419        // Wrap buffer in a chunk
420        DataStreamPtr stream(new MemoryDataStream(
421            pBuffer, imgData->width * imgData->height * 3, false));
422
423        // Need to flip the read data over in Y though
424        Image img;
425        img.loadRawData(stream, imgData->width, imgData->height, imgData->format );
426        img.flipAroundX();
427
428        MemoryDataStreamPtr streamFlipped(
429            new MemoryDataStream(img.getData(), stream->size(), false));
430
431        // Get codec
432        size_t pos = filename.find_last_of(".");
433            String extension;
434        if( pos == String::npos )
435            OGRE_EXCEPT(
436                Exception::ERR_INVALIDPARAMS,
437            "Unable to determine image type for '" + filename + "' - invalid extension.",
438                "GLRenderTexture::writeContentsToFile" );
439
440        while( pos != filename.length() - 1 )
441            extension += filename[++pos];
442
443        // Get the codec
444        Codec * pCodec = Codec::getCodec(extension);
445
446        // Write out
447        Codec::CodecDataPtr codecDataPtr(imgData);
448        pCodec->codeToFile(streamFlipped, filename, codecDataPtr);
449
450        delete [] pBuffer;
451    }
452#ifdef GTP_VISIBILITY_MODIFIED_OGRE
453        uchar *GLRenderTexture::getBufferContents(int &dimx, int &dimy)
454        {
455                dimx = mWidth;
456                dimy = mHeight;
457               
458                // Allocate buffer
459                uchar* pBuffer = new uchar[mWidth * mHeight * 3];
460
461                // Read pixels
462                // I love GL: it does all the locking & colour conversion for us
463                glReadPixels(0, 0, mWidth-1, mHeight-1, GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
464
465                return pBuffer;
466        }
467#endif // GTP_VISIBILITY_MODIFIED_OGRE
468}
469
Note: See TracBrowser for help on using the repository browser.