source: trunk/VUT/work/ogre_changes/RenderSystems/GL/src/OgreGLTexture.cpp @ 156

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