source: OGRE/trunk/ogrenew/RenderSystems/Direct3D9/src/OgreD3D9Texture.cpp @ 692

Revision 692, 37.0 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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 "OgreD3D9Texture.h"
26#include "OgreD3D9HardwarePixelBuffer.h"
27#include "OgreException.h"
28#include "OgreLogManager.h"
29#include "OgreStringConverter.h"
30#include "OgreBitwise.h"
31#include "OgreD3D9Mappings.h"
32
33#include "OgreNoMemoryMacros.h"
34#include <d3dx9.h>
35#include <dxerr9.h>
36#include "OgreMemoryMacros.h"
37
38namespace Ogre
39{
40        /****************************************************************************************/
41    D3D9Texture::D3D9Texture(ResourceManager* creator, const String& name,
42        ResourceHandle handle, const String& group, bool isManual,
43        ManualResourceLoader* loader, IDirect3DDevice9 *pD3DDevice)
44        :Texture(creator, name, handle, group, isManual, loader),
45        mpDev(pD3DDevice),
46        mpD3D(NULL),
47        mpNormTex(NULL),
48        mpCubeTex(NULL),
49                mpVolumeTex(NULL),
50        mpTex(NULL),
51                mDynamicTextures(false)
52        {
53        _initDevice();
54        }
55        /****************************************************************************************/
56        D3D9Texture::~D3D9Texture()
57        {
58        // have to call this here reather than in Resource destructor
59        // since calling virtual methods in base destructors causes crash
60                if (mIsLoaded)
61                {
62                        unload();
63                }
64                else
65                {
66                        freeInternalResources();
67                }
68        }
69        /****************************************************************************************/
70        void D3D9Texture::copyToTexture(TexturePtr& target)
71        {
72        // check if this & target are the same format and type
73                // blitting from or to cube textures is not supported yet
74                if (target->getUsage() != this->getUsage() ||
75                        target->getTextureType() != this->getTextureType())
76                {
77                        OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS,
78                                        "Src. and dest. textures must be of same type and must have the same usage !!!",
79                                        "D3D9Texture::copyToTexture" );
80                }
81
82        HRESULT hr;
83        D3D9Texture *other;
84                // get the target
85                other = reinterpret_cast< D3D9Texture * >( target.get() );
86                // target rectangle (whole surface)
87                RECT dstRC = {0, 0, other->getWidth(), other->getHeight()};
88
89                // do it plain for normal texture
90                if (this->getTextureType() == TEX_TYPE_2D)
91                {
92                        // get our source surface
93                        IDirect3DSurface9 *pSrcSurface = 0;
94                        if( FAILED( hr = mpNormTex->GetSurfaceLevel(0, &pSrcSurface) ) )
95                        {
96                                String msg = DXGetErrorDescription9(hr);
97                                OGRE_EXCEPT( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
98                        }
99
100                        // get our target surface
101                        IDirect3DSurface9 *pDstSurface = 0;
102                        IDirect3DTexture9 *pOthTex = other->getNormTexture();
103                        if( FAILED( hr = pOthTex->GetSurfaceLevel(0, &pDstSurface) ) )
104                        {
105                                String msg = DXGetErrorDescription9(hr);
106                                SAFE_RELEASE(pSrcSurface);
107                                OGRE_EXCEPT( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
108                        }
109
110                        // do the blit, it's called StretchRect in D3D9 :)
111                        if( FAILED( hr = mpDev->StretchRect( pSrcSurface, NULL, pDstSurface, &dstRC, D3DTEXF_NONE) ) )
112                        {
113                                String msg = DXGetErrorDescription9(hr);
114                                SAFE_RELEASE(pSrcSurface);
115                                SAFE_RELEASE(pDstSurface);
116                                OGRE_EXCEPT( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
117                        }
118
119                        // release temp. surfaces
120                        SAFE_RELEASE(pSrcSurface);
121                        SAFE_RELEASE(pDstSurface);
122                }
123                else if (this->getTextureType() == TEX_TYPE_CUBE_MAP)
124                {
125                        // get the target cube texture
126                        IDirect3DCubeTexture9 *pOthTex = other->getCubeTexture();
127                        // blit to 6 cube faces
128                        for (size_t face = 0; face < 6; face++)
129                        {
130                                // get our source surface
131                                IDirect3DSurface9 *pSrcSurface = 0;
132                                if( FAILED( hr = mpCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)face, 0, &pSrcSurface) ) )
133                                {
134                                        String msg = DXGetErrorDescription9(hr);
135                                        OGRE_EXCEPT( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
136                                }
137
138                                // get our target surface
139                                IDirect3DSurface9 *pDstSurface = 0;
140                                if( FAILED( hr = pOthTex->GetCubeMapSurface((D3DCUBEMAP_FACES)face, 0, &pDstSurface) ) )
141                                {
142                                        String msg = DXGetErrorDescription9(hr);
143                                        SAFE_RELEASE(pSrcSurface);
144                                        OGRE_EXCEPT( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
145                                }
146
147                                // do the blit, it's called StretchRect in D3D9 :)
148                                if( FAILED( hr = mpDev->StretchRect( pSrcSurface, NULL, pDstSurface, &dstRC, D3DTEXF_NONE) ) )
149                                {
150                                        String msg = DXGetErrorDescription9(hr);
151                                        SAFE_RELEASE(pSrcSurface);
152                                        SAFE_RELEASE(pDstSurface);
153                                        OGRE_EXCEPT( hr, "Couldn't blit : " + msg, "D3D9Texture::copyToTexture" );
154                                }
155
156                                // release temp. surfaces
157                                SAFE_RELEASE(pSrcSurface);
158                                SAFE_RELEASE(pDstSurface);
159                        }
160                }
161                else
162                {
163                        OGRE_EXCEPT( Exception::UNIMPLEMENTED_FEATURE,
164                                        "Copy to texture is implemented only for 2D and cube textures !!!",
165                                        "D3D9Texture::copyToTexture" );
166                }
167        }
168        /****************************************************************************************/
169        void D3D9Texture::loadImage( const Image &img )
170        {
171                // Use OGRE its own codecs
172                std::vector<const Image*> imagePtrs;
173                imagePtrs.push_back(&img);
174                _loadImages( imagePtrs );
175        }
176        /****************************************************************************************/
177        void D3D9Texture::loadImpl()
178        {
179                if (mUsage & TU_RENDERTARGET)
180                {
181                        createInternalResources();
182                        mIsLoaded = true;
183                        return;
184                }
185
186                // load based on tex.type
187                switch (this->getTextureType())
188                {
189                case TEX_TYPE_1D:
190                case TEX_TYPE_2D:
191                        this->_loadNormTex();
192                        break;
193                case TEX_TYPE_3D:
194            this->_loadVolumeTex();
195            break;
196                case TEX_TYPE_CUBE_MAP:
197                        this->_loadCubeTex();
198                        break;
199                default:
200                        OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Unknown texture type", "D3D9Texture::loadImpl" );
201                }
202
203        }
204        /****************************************************************************************/
205        void D3D9Texture::freeInternalResourcesImpl()
206        {
207                SAFE_RELEASE(mpTex);
208                SAFE_RELEASE(mpNormTex);
209                SAFE_RELEASE(mpCubeTex);
210                SAFE_RELEASE(mpVolumeTex);
211        }
212        /****************************************************************************************/
213        void D3D9Texture::_loadCubeTex()
214        {
215                assert(this->getTextureType() == TEX_TYPE_CUBE_MAP);
216
217        // DDS load?
218                if (StringUtil::endsWith(getName(), ".dds"))
219        {
220            // find & load resource data
221                        DataStreamPtr dstream =
222                                ResourceGroupManager::getSingleton().openResource(
223                                        mName, mGroup, true, this);
224            MemoryDataStream stream( dstream );
225
226            HRESULT hr = D3DXCreateCubeTextureFromFileInMemory(
227                mpDev,
228                stream.getPtr(),
229                stream.size(),
230                &mpCubeTex);
231
232            if (FAILED(hr))
233                    {
234                                this->freeInternalResources();
235                            OGRE_EXCEPT( hr, "Can't create cube texture", "D3D9Texture::_loadCubeTex" );
236                    }
237
238            hr = mpCubeTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&mpTex);
239
240            if (FAILED(hr))
241                    {
242                                this->freeInternalResources();
243                            OGRE_EXCEPT( hr, "Can't get base texture", "D3D9Texture::_loadCubeTex" );
244                    }
245
246            D3DSURFACE_DESC texDesc;
247            mpCubeTex->GetLevelDesc(0, &texDesc);
248            // set src and dest attributes to the same, we can't know
249            _setSrcAttributes(texDesc.Width, texDesc.Height, 1, D3D9Mappings::_getPF(texDesc.Format));
250            _setFinalAttributes(texDesc.Width, texDesc.Height, 1,  D3D9Mappings::_getPF(texDesc.Format));
251                        mIsLoaded = true;
252                        mInternalResourcesCreated = true;
253        }
254        else
255        {
256                        // Load from 6 separate files
257                        // Use OGRE its own codecs
258                        String baseName, ext;
259                        size_t pos = mName.find_last_of(".");
260                        baseName = mName.substr(0, pos);
261                        ext = mName.substr(pos+1);
262                        std::vector<Image> images(6);
263                        std::vector<const Image*> imagePtrs;
264                        static const String suffixes[6] = {"_rt", "_lf", "_up", "_dn", "_fr", "_bk"};
265
266                        for(size_t i = 0; i < 6; i++)
267                        {
268                                String fullName = baseName + suffixes[i] + "." + ext;
269
270                // find & load resource data intro stream to allow resource
271                                // group changes if required
272                                DataStreamPtr dstream =
273                                        ResourceGroupManager::getSingleton().openResource(
274                                                fullName, mGroup, true, this);
275       
276                                images[i].load(dstream, ext);
277
278                                imagePtrs.push_back(&images[i]);
279                        }
280
281            _loadImages( imagePtrs );
282        }
283        }
284        /****************************************************************************************/
285        void D3D9Texture::_loadVolumeTex()
286        {
287                assert(this->getTextureType() == TEX_TYPE_3D);
288                // DDS load?
289                if (StringUtil::endsWith(getName(), ".dds"))
290                {
291                        // find & load resource data
292                        DataStreamPtr dstream =
293                                ResourceGroupManager::getSingleton().openResource(
294                                        mName, mGroup, true, this);
295                        MemoryDataStream stream(dstream);
296       
297                        HRESULT hr = D3DXCreateVolumeTextureFromFileInMemory(
298                                mpDev,
299                                stream.getPtr(),
300                                stream.size(),
301                                &mpVolumeTex);
302       
303                        if (FAILED(hr))
304                        {
305                                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
306                                        "Unable to load volume texture from " + this->getName(),
307                                        "D3D9Texture::_loadVolumeTex");
308                        }
309       
310                        hr = mpVolumeTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&mpTex);
311       
312                        if (FAILED(hr))
313                        {
314                                this->freeInternalResources();
315                                OGRE_EXCEPT( hr, "Can't get base texture", "D3D9Texture::_loadVolumeTex" );
316                        }
317       
318                        D3DVOLUME_DESC texDesc;
319                        hr = mpVolumeTex->GetLevelDesc(0, &texDesc);
320       
321                        // set src and dest attributes to the same, we can't know
322                        _setSrcAttributes(texDesc.Width, texDesc.Height, texDesc.Depth, D3D9Mappings::_getPF(texDesc.Format));
323                        _setFinalAttributes(texDesc.Width, texDesc.Height, texDesc.Depth, D3D9Mappings::_getPF(texDesc.Format));
324                        mIsLoaded = true;
325                        mInternalResourcesCreated = true;
326        }
327                else
328                {
329                        Image img;
330                // find & load resource data intro stream to allow resource
331                        // group changes if required
332                        DataStreamPtr dstream =
333                                ResourceGroupManager::getSingleton().openResource(
334                                        mName, mGroup, true, this);
335                        size_t pos = mName.find_last_of(".");
336                        String ext = mName.substr(pos+1);
337       
338                        img.load(dstream, ext);
339                        loadImage(img);
340                }
341    }
342        /****************************************************************************************/
343        void D3D9Texture::_loadNormTex()
344        {
345                assert(this->getTextureType() == TEX_TYPE_1D || this->getTextureType() == TEX_TYPE_2D);
346                // DDS load?
347                if (StringUtil::endsWith(getName(), ".dds"))
348                {
349                        // Use D3DX
350                        // find & load resource data
351                        DataStreamPtr dstream =
352                                ResourceGroupManager::getSingleton().openResource(
353                                        mName, mGroup, true, this);
354                        MemoryDataStream stream(dstream);
355       
356                        HRESULT hr = D3DXCreateTextureFromFileInMemory(
357                                mpDev,
358                                stream.getPtr(),
359                                stream.size(),
360                                &mpNormTex);
361       
362                        if (FAILED(hr))
363                        {
364                                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
365                                        "Unable to load texture from " + this->getName(),
366                                        "D3D9Texture::_loadNormTex");
367                        }
368       
369                        hr = mpNormTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&mpTex);
370       
371                        if (FAILED(hr))
372                        {
373                                this->freeInternalResources();
374                                OGRE_EXCEPT( hr, "Can't get base texture", "D3D9Texture::_loadNormTex" );
375                        }
376       
377                        D3DSURFACE_DESC texDesc;
378                        mpNormTex->GetLevelDesc(0, &texDesc);
379                        // set src and dest attributes to the same, we can't know
380                        _setSrcAttributes(texDesc.Width, texDesc.Height, 1, D3D9Mappings::_getPF(texDesc.Format));
381                        _setFinalAttributes(texDesc.Width, texDesc.Height, 1, D3D9Mappings::_getPF(texDesc.Format));
382                        mIsLoaded = true;
383                        mInternalResourcesCreated = true;
384        }
385                else
386                {
387                        Image img;
388                // find & load resource data intro stream to allow resource
389                        // group changes if required
390                        DataStreamPtr dstream =
391                                ResourceGroupManager::getSingleton().openResource(
392                                        mName, mGroup, true, this);
393       
394                        size_t pos = mName.find_last_of(".");
395                        String ext = mName.substr(pos+1);
396                       
397                        img.load(dstream, ext);
398                        loadImage(img);
399                }
400        }
401        /****************************************************************************************/
402    void D3D9Texture::createInternalResourcesImpl(void)
403        {
404                // If mSrcWidth and mSrcHeight are zero, the requested extents have probably been set
405                // through setWidth and setHeight, which set mWidth and mHeight. Take those values.
406                if(mSrcWidth == 0 || mSrcHeight == 0) {
407                        mSrcWidth = mWidth;
408                        mSrcHeight = mHeight;
409                }
410               
411                // Determine D3D pool to use
412                // Use managed unless we're a render target or user has asked for
413                // a dynamic texture
414                if ((mUsage & TU_RENDERTARGET) ||
415                        (mUsage & TU_DYNAMIC))
416                {
417                        mD3DPool = D3DPOOL_DEFAULT;
418                }
419                else
420                {
421                        mD3DPool = D3DPOOL_MANAGED;
422                }
423                // load based on tex.type
424                switch (this->getTextureType())
425                {
426                case TEX_TYPE_1D:
427                case TEX_TYPE_2D:
428                        this->_createNormTex();
429                        break;
430                case TEX_TYPE_CUBE_MAP:
431                        this->_createCubeTex();
432                        break;
433                case TEX_TYPE_3D:
434                        this->_createVolumeTex();
435                        break;
436                default:
437                        this->freeInternalResources();
438                        OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Unknown texture type", "D3D9Texture::createInternalResources" );
439                }
440        }
441        /****************************************************************************************/
442        void D3D9Texture::_createNormTex()
443        {
444                // we must have those defined here
445                assert(mSrcWidth > 0 || mSrcHeight > 0);
446
447                // determine wich D3D9 pixel format we'll use
448                HRESULT hr;
449                D3DFORMAT d3dPF = this->_chooseD3DFormat();
450                // let's D3DX check the corrected pixel format
451                hr = D3DXCheckTextureRequirements(mpDev, NULL, NULL, NULL, 0, &d3dPF, mD3DPool);
452
453                // Use D3DX to help us create the texture, this way it can adjust any relevant sizes
454                DWORD usage = (mUsage & TU_RENDERTARGET) ? D3DUSAGE_RENDERTARGET : 0;
455                UINT numMips = mNumRequestedMipmaps + 1;
456                // Check dynamic textures
457                if (mUsage & TU_DYNAMIC)
458                {
459                        if (_canUseDynamicTextures(usage, D3DRTYPE_TEXTURE, d3dPF))
460                        {
461                                usage |= D3DUSAGE_DYNAMIC;
462                                mDynamicTextures = true;
463                        }
464                        else
465                        {
466                                mDynamicTextures = false;
467                        }
468                }
469                // check if mip maps are supported on hardware
470                mMipmapsHardwareGenerated = false;
471                if (mDevCaps.TextureCaps & D3DPTEXTURECAPS_MIPMAP)
472                {
473                        if (mUsage & TU_AUTOMIPMAP && mNumRequestedMipmaps != 0)
474                        {
475                                // use auto.gen. if available, and if desired
476                                mMipmapsHardwareGenerated = this->_canAutoGenMipmaps(usage, D3DRTYPE_TEXTURE, d3dPF);
477                                if (mMipmapsHardwareGenerated)
478                                {
479                                        usage |= D3DUSAGE_AUTOGENMIPMAP;
480                                        numMips = 0;
481                                }
482                        }
483                }
484                else
485                {
486                        // no mip map support for this kind of textures :(
487                        mNumMipmaps = 0;
488                        numMips = 1;
489                }
490
491                // create the texture
492                hr = D3DXCreateTexture(
493                                mpDev,                                                          // device
494                                mSrcWidth,                                                      // width
495                                mSrcHeight,                                                     // height
496                                numMips,                                                        // number of mip map levels
497                                usage,                                                          // usage
498                                d3dPF,                                                          // pixel format
499                                mD3DPool,
500                                &mpNormTex);                                            // data pointer
501                // check result and except if failed
502                if (FAILED(hr))
503                {
504                        this->freeInternalResources();
505                        OGRE_EXCEPT( hr, "Error creating texture", "D3D9Texture::_createNormTex" );
506                }
507               
508                // set the base texture we'll use in the render system
509                hr = mpNormTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&mpTex);
510                if (FAILED(hr))
511                {
512                        this->freeInternalResources();
513                        OGRE_EXCEPT( hr, "Can't get base texture", "D3D9Texture::_createNormTex" );
514                }
515               
516                // set final tex. attributes from tex. description
517                // they may differ from the source image !!!
518                D3DSURFACE_DESC desc;
519                hr = mpNormTex->GetLevelDesc(0, &desc);
520                if (FAILED(hr))
521                {
522                        this->freeInternalResources();
523                        OGRE_EXCEPT( hr, "Can't get texture description", "D3D9Texture::_createNormTex" );
524                }
525                this->_setFinalAttributes(desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));
526               
527                // Set best filter type
528                if(mMipmapsHardwareGenerated)
529                {
530                        hr = mpTex->SetAutoGenFilterType(_getBestFilterMethod());
531                        if(FAILED(hr))
532                        {
533                                OGRE_EXCEPT( hr, "Could not set best autogen filter type", "D3D9Texture::_createNormTex" );
534                        }
535                }
536        }
537        /****************************************************************************************/
538        void D3D9Texture::_createCubeTex()
539        {
540                // we must have those defined here
541                assert(mSrcWidth > 0 || mSrcHeight > 0);
542
543                // determine wich D3D9 pixel format we'll use
544                HRESULT hr;
545                D3DFORMAT d3dPF = this->_chooseD3DFormat();
546                // let's D3DX check the corrected pixel format
547                hr = D3DXCheckCubeTextureRequirements(mpDev, NULL, NULL, 0, &d3dPF, mD3DPool);
548
549                // Use D3DX to help us create the texture, this way it can adjust any relevant sizes
550                DWORD usage = (mUsage & TU_RENDERTARGET) ? D3DUSAGE_RENDERTARGET : 0;
551                UINT numMips = mNumRequestedMipmaps + 1;
552                // Check dynamic textures
553                if (mUsage & TU_DYNAMIC)
554                {
555                        if (_canUseDynamicTextures(usage, D3DRTYPE_CUBETEXTURE, d3dPF))
556                        {
557                                usage |= D3DUSAGE_DYNAMIC;
558                                mDynamicTextures = true;
559                        }
560                        else
561                        {
562                                mDynamicTextures = false;
563                        }
564                }
565                // check if mip map cube textures are supported
566                mMipmapsHardwareGenerated = false;
567                if (mDevCaps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP)
568                {
569                        if (mUsage & TU_AUTOMIPMAP && mNumRequestedMipmaps != 0)
570                        {
571                                // use auto.gen. if available
572                                mMipmapsHardwareGenerated = this->_canAutoGenMipmaps(usage, D3DRTYPE_CUBETEXTURE, d3dPF);
573                                if (mMipmapsHardwareGenerated)
574                                {
575                                        usage |= D3DUSAGE_AUTOGENMIPMAP;
576                                        numMips = 0;
577                                }
578                        }
579                }
580                else
581                {
582                        // no mip map support for this kind of textures :(
583                        mNumMipmaps = 0;
584                        numMips = 1;
585                }
586
587                // create the texture
588                hr = D3DXCreateCubeTexture(     
589                                mpDev,                                                          // device
590                                mSrcWidth,                                                      // dimension
591                                numMips,                                                        // number of mip map levels
592                                usage,                                                          // usage
593                                d3dPF,                                                          // pixel format
594                                mD3DPool,
595                                &mpCubeTex);                                            // data pointer
596                // check result and except if failed
597                if (FAILED(hr))
598                {
599                        this->freeInternalResources();
600                        OGRE_EXCEPT( hr, "Error creating texture", "D3D9Texture::_createCubeTex" );
601                }
602
603                // set the base texture we'll use in the render system
604                hr = mpCubeTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&mpTex);
605                if (FAILED(hr))
606                {
607                        this->freeInternalResources();
608                        OGRE_EXCEPT( hr, "Can't get base texture", "D3D9Texture::_createCubeTex" );
609                }
610               
611                // set final tex. attributes from tex. description
612                // they may differ from the source image !!!
613                D3DSURFACE_DESC desc;
614                hr = mpCubeTex->GetLevelDesc(0, &desc);
615                if (FAILED(hr))
616                {
617                        this->freeInternalResources();
618                        OGRE_EXCEPT( hr, "Can't get texture description", "D3D9Texture::_createCubeTex" );
619                }
620                this->_setFinalAttributes(desc.Width, desc.Height, 1, D3D9Mappings::_getPF(desc.Format));
621
622                // Set best filter type
623                if(mMipmapsHardwareGenerated)
624                {
625                        hr = mpTex->SetAutoGenFilterType(_getBestFilterMethod());
626                        if(FAILED(hr))
627                        {
628                                OGRE_EXCEPT( hr, "Could not set best autogen filter type", "D3D9Texture::_createCubeTex" );
629                        }
630                }
631        }
632        /****************************************************************************************/
633        void D3D9Texture::_createVolumeTex()
634        {
635                // we must have those defined here
636                assert(mWidth > 0 && mHeight > 0 && mDepth>0);
637
638                // determine wich D3D9 pixel format we'll use
639                HRESULT hr;
640                D3DFORMAT d3dPF = this->_chooseD3DFormat();
641                // let's D3DX check the corrected pixel format
642                hr = D3DXCheckVolumeTextureRequirements(mpDev, NULL, NULL, NULL, NULL, 0, &d3dPF, mD3DPool);
643
644                // Use D3DX to help us create the texture, this way it can adjust any relevant sizes
645                DWORD usage = (mUsage & TU_RENDERTARGET) ? D3DUSAGE_RENDERTARGET : 0;
646                UINT numMips = mNumRequestedMipmaps + 1;
647                // Check dynamic textures
648                if (mUsage & TU_DYNAMIC)
649                {
650                        if (_canUseDynamicTextures(usage, D3DRTYPE_VOLUMETEXTURE, d3dPF))
651                        {
652                                usage |= D3DUSAGE_DYNAMIC;
653                                mDynamicTextures = true;
654                        }
655                        else
656                        {
657                                mDynamicTextures = false;
658                        }
659                }
660                // check if mip map volume textures are supported
661                mMipmapsHardwareGenerated = false;
662                if (mDevCaps.TextureCaps & D3DPTEXTURECAPS_MIPVOLUMEMAP)
663                {
664                        if (mUsage & TU_AUTOMIPMAP && mNumRequestedMipmaps != 0)
665                        {
666                                // use auto.gen. if available
667                                mMipmapsHardwareGenerated = this->_canAutoGenMipmaps(usage, D3DRTYPE_VOLUMETEXTURE, d3dPF);
668                                if (mMipmapsHardwareGenerated)
669                                {
670                                        usage |= D3DUSAGE_AUTOGENMIPMAP;
671                                        numMips = 0;
672                                }
673                        }
674                }
675                else
676                {
677                        // no mip map support for this kind of textures :(
678                        mNumMipmaps = 0;
679                        numMips = 1;
680                }
681
682                // create the texture
683                hr = D3DXCreateVolumeTexture(   
684                                mpDev,                                                          // device
685                                mWidth,                                                         // dimension
686                                mHeight,
687                                mDepth,
688                                numMips,                                                        // number of mip map levels
689                                usage,                                                          // usage
690                                d3dPF,                                                          // pixel format
691                                mD3DPool,
692                                &mpVolumeTex);                                          // data pointer
693                // check result and except if failed
694                if (FAILED(hr))
695                {
696                        this->freeInternalResources();
697                        OGRE_EXCEPT( hr, "Error creating texture", "D3D9Texture::_createVolumeTex" );
698                }
699
700                // set the base texture we'll use in the render system
701                hr = mpVolumeTex->QueryInterface(IID_IDirect3DBaseTexture9, (void **)&mpTex);
702                if (FAILED(hr))
703                {
704                        this->freeInternalResources();
705                        OGRE_EXCEPT( hr, "Can't get base texture", "D3D9Texture::_createVolumeTex" );
706                }
707               
708                // set final tex. attributes from tex. description
709                // they may differ from the source image !!!
710                D3DVOLUME_DESC desc;
711                hr = mpVolumeTex->GetLevelDesc(0, &desc);
712                if (FAILED(hr))
713                {
714                        this->freeInternalResources();
715                        OGRE_EXCEPT( hr, "Can't get texture description", "D3D9Texture::_createVolumeTex" );
716                }
717                this->_setFinalAttributes(desc.Width, desc.Height, desc.Depth, D3D9Mappings::_getPF(desc.Format));
718               
719                // Set best filter type
720                if(mMipmapsHardwareGenerated)
721                {
722                        hr = mpTex->SetAutoGenFilterType(_getBestFilterMethod());
723                        if(FAILED(hr))
724                        {
725                                OGRE_EXCEPT( hr, "Could not set best autogen filter type", "D3D9Texture::_createCubeTex" );
726                        }
727                }
728        }
729        /****************************************************************************************/
730        void D3D9Texture::_initDevice(void)
731        {
732                assert(mpDev);
733                HRESULT hr;
734
735                // get device caps
736                hr = mpDev->GetDeviceCaps(&mDevCaps);
737                if (FAILED(hr))
738                        OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't get device description", "D3D9Texture::_setDevice" );
739
740                // get D3D pointer
741                hr = mpDev->GetDirect3D(&mpD3D);
742                // decrement reference count
743                mpD3D->Release();
744                if (FAILED(hr))
745                        OGRE_EXCEPT( hr, "Failed to get D3D9 pointer", "D3D9Texture::_setDevice" );
746
747                // get our device creation parameters
748                hr = mpDev->GetCreationParameters(&mDevCreParams);
749                if (FAILED(hr))
750                        OGRE_EXCEPT( hr, "Failed to get D3D9 device creation parameters", "D3D9Texture::_setDevice" );
751
752                // get our back buffer pixel format
753                IDirect3DSurface9 *pSrf;
754                D3DSURFACE_DESC srfDesc;
755                hr = mpDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pSrf);
756                // decrement reference count
757                pSrf->Release();
758                if (FAILED(hr))
759                        OGRE_EXCEPT( hr, "Failed to get D3D9 device pixel format", "D3D9Texture::_setDevice" );
760
761                hr = pSrf->GetDesc(&srfDesc);
762                if (FAILED(hr))
763                {
764                        OGRE_EXCEPT( hr, "Failed to get D3D9 device pixel format", "D3D9Texture::_setDevice" );
765                }
766
767                mBBPixelFormat = srfDesc.Format;
768        }
769        /****************************************************************************************/
770        void D3D9Texture::_setFinalAttributes(unsigned long width, unsigned long height,
771        unsigned long depth, PixelFormat format)
772        {
773                // set target texture attributes
774                mHeight = height;
775                mWidth = width;
776        mDepth = depth;
777                mFormat = format;
778
779                // Update size (the final size, not including temp space)
780                // this is needed in Resource class
781                unsigned short bytesPerPixel = mFinalBpp >> 3;
782                if( !mHasAlpha && mFinalBpp == 32 )
783                        bytesPerPixel--;
784                mSize = mWidth * mHeight * mDepth * bytesPerPixel
785            * (mTextureType == TEX_TYPE_CUBE_MAP)? 6 : 1;
786
787                // say to the world what we are doing
788                if (mWidth != mSrcWidth ||
789                        mHeight != mSrcHeight)
790                {
791                        LogManager::getSingleton().logMessage("D3D9 : ***** Dimensions altered by the render system");
792                        LogManager::getSingleton().logMessage("D3D9 : ***** Source image dimensions : " + StringConverter::toString(mSrcWidth) + "x" + StringConverter::toString(mSrcHeight));
793                        LogManager::getSingleton().logMessage("D3D9 : ***** Texture dimensions : " + StringConverter::toString(mWidth) + "x" + StringConverter::toString(mHeight));
794                }
795               
796                // Create list of subsurfaces for getBuffer()
797                _createSurfaceList();
798        }
799        /****************************************************************************************/
800        void D3D9Texture::_setSrcAttributes(unsigned long width, unsigned long height,
801        unsigned long depth, PixelFormat format)
802        {
803                // set source image attributes
804                mSrcWidth = width;
805                mSrcHeight = height;
806                mSrcBpp = PixelUtil::getNumElemBits(format);
807        mHasAlpha = PixelUtil::getFlags(format) & PFF_HASALPHA;
808                // say to the world what we are doing
809                switch (this->getTextureType())
810                {
811                case TEX_TYPE_1D:
812                        if (mUsage & TU_RENDERTARGET)
813                                LogManager::getSingleton().logMessage("D3D9 : Creating 1D RenderTarget, name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipmaps) + " mip map levels");
814                        else
815                                LogManager::getSingleton().logMessage("D3D9 : Loading 1D Texture, image name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipmaps) + " mip map levels");
816                        break;
817                case TEX_TYPE_2D:
818                        if (mUsage & TU_RENDERTARGET)
819                                LogManager::getSingleton().logMessage("D3D9 : Creating 2D RenderTarget, name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipmaps) + " mip map levels");
820                        else
821                                LogManager::getSingleton().logMessage("D3D9 : Loading 2D Texture, image name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipmaps) + " mip map levels");
822                        break;
823                case TEX_TYPE_3D:
824                        if (mUsage & TU_RENDERTARGET)
825                                LogManager::getSingleton().logMessage("D3D9 : Creating 3D RenderTarget, name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipmaps) + " mip map levels");
826                        else
827                                LogManager::getSingleton().logMessage("D3D9 : Loading 3D Texture, image name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipmaps) + " mip map levels");
828                        break;
829                case TEX_TYPE_CUBE_MAP:
830                        if (mUsage & TU_RENDERTARGET)
831                                LogManager::getSingleton().logMessage("D3D9 : Creating Cube map RenderTarget, name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipmaps) + " mip map levels");
832                        else
833                                LogManager::getSingleton().logMessage("D3D9 : Loading Cube Texture, base image name : '" + this->getName() + "' with " + StringConverter::toString(mNumMipmaps) + " mip map levels");
834                        break;
835                default:
836                        this->freeInternalResources();
837                        OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Unknown texture type", "D3D9Texture::_setSrcAttributes" );
838                }
839        }
840        /****************************************************************************************/
841        D3DTEXTUREFILTERTYPE D3D9Texture::_getBestFilterMethod()
842        {
843                // those MUST be initialized !!!
844                assert(mpDev);
845                assert(mpD3D);
846                assert(mpTex);
847               
848                DWORD filterCaps = 0;
849                // Minification filter is used for mipmap generation
850                // Pick the best one supported for this tex type
851                switch (this->getTextureType())
852                {
853                case TEX_TYPE_1D:               // Same as 2D
854                case TEX_TYPE_2D:               filterCaps = mDevCaps.TextureFilterCaps;        break;
855                case TEX_TYPE_3D:               filterCaps = mDevCaps.VolumeTextureFilterCaps;  break;
856                case TEX_TYPE_CUBE_MAP: filterCaps = mDevCaps.CubeTextureFilterCaps;    break;
857                }
858                if(filterCaps & D3DPTFILTERCAPS_MINFGAUSSIANQUAD)
859                        return D3DTEXF_GAUSSIANQUAD;
860               
861                if(filterCaps & D3DPTFILTERCAPS_MINFPYRAMIDALQUAD)
862                        return D3DTEXF_PYRAMIDALQUAD;
863               
864                if(filterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC)
865                        return D3DTEXF_ANISOTROPIC;
866               
867                if(filterCaps & D3DPTFILTERCAPS_MINFLINEAR)
868                        return D3DTEXF_LINEAR;
869               
870                if(filterCaps & D3DPTFILTERCAPS_MINFPOINT)
871                        return D3DTEXF_POINT;
872               
873                return D3DTEXF_POINT;
874        }
875        /****************************************************************************************/
876        bool D3D9Texture::_canUseDynamicTextures(DWORD srcUsage, D3DRESOURCETYPE srcType, D3DFORMAT srcFormat)
877        {
878                // those MUST be initialized !!!
879                assert(mpDev);
880                assert(mpD3D);
881
882                // Check for dynamic texture support
883                HRESULT hr;
884                // check for auto gen. mip maps support
885                hr = mpD3D->CheckDeviceFormat(
886                        mDevCreParams.AdapterOrdinal,
887                        mDevCreParams.DeviceType,
888                        mBBPixelFormat,
889                        srcUsage | D3DUSAGE_DYNAMIC,
890                        srcType,
891                        srcFormat);
892                if (hr == D3D_OK)
893                        return true;
894                else
895                        return false;
896        }
897        /****************************************************************************************/
898        bool D3D9Texture::_canAutoGenMipmaps(DWORD srcUsage, D3DRESOURCETYPE srcType, D3DFORMAT srcFormat)
899        {
900                // those MUST be initialized !!!
901                assert(mpDev);
902                assert(mpD3D);
903
904                // Hacky override - many (all?) cards seem to not be able to autogen on
905                // textures which are not a power of two
906                // Can we even mipmap on 3D textures? Well
907                if ((mWidth & mWidth-1) || (mHeight & mHeight-1) || (mDepth & mDepth-1))
908                        return false;
909
910                if (mDevCaps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP)
911                {
912                        HRESULT hr;
913                        // check for auto gen. mip maps support
914                        hr = mpD3D->CheckDeviceFormat(
915                                        mDevCreParams.AdapterOrdinal,
916                                        mDevCreParams.DeviceType,
917                                        mBBPixelFormat,
918                                        srcUsage | D3DUSAGE_AUTOGENMIPMAP,
919                                        srcType,
920                                        srcFormat);
921                        // this HR could a SUCCES
922                        // but mip maps will not be generated
923                        if (hr == D3D_OK)
924                                return true;
925                        else
926                                return false;
927                }
928                else
929                        return false;
930        }
931        /****************************************************************************************/
932        D3DFORMAT D3D9Texture::_chooseD3DFormat()
933        {
934                // Choose frame buffer pixel format in case PF_UNKNOWN was requested
935                if(mFormat == PF_UNKNOWN)
936                        return mBBPixelFormat;
937                // Choose closest supported D3D format as a D3D format
938                return D3D9Mappings::_getPF(D3D9Mappings::_getClosestSupportedPF(mFormat));
939
940        }
941        /****************************************************************************************/
942        // Macro to hide ugly cast
943        #define GETLEVEL(face,mip) \
944                static_cast<D3D9HardwarePixelBuffer*>(mSurfaceList[face*(mNumMipmaps+1)+mip].get())
945        void D3D9Texture::_createSurfaceList(void)
946        {
947                IDirect3DSurface9 *surface;
948                IDirect3DVolume9 *volume;
949                D3D9HardwarePixelBuffer *buffer;
950                size_t mip, face;
951                assert(mpTex);
952                // Make sure number of mips is right
953                mNumMipmaps = mpTex->GetLevelCount() - 1;
954                // Need to know static / dynamic
955                unsigned int bufusage;
956                if ((mUsage & TU_DYNAMIC) && mDynamicTextures)
957                {
958                        bufusage = HardwareBuffer::HBU_DYNAMIC;
959                }
960                else
961                {
962                        bufusage = HardwareBuffer::HBU_STATIC;
963                }
964                if (mUsage & TU_RENDERTARGET)
965                {
966                        bufusage |= TU_RENDERTARGET;
967                }
968               
969                bool updateOldList = mSurfaceList.size() == (getNumFaces() * (mNumMipmaps + 1));
970                if(!updateOldList)
971                {
972                        // Create new list of surfaces
973                        mSurfaceList.clear();
974                        for(size_t face=0; face<getNumFaces(); ++face)
975                        {
976                                for(size_t mip=0; mip<=mNumMipmaps; ++mip)
977                                {
978                                        buffer = new D3D9HardwarePixelBuffer((HardwareBuffer::Usage)bufusage);
979                                        mSurfaceList.push_back(
980                                                HardwarePixelBufferSharedPtr(buffer)
981                                        );
982                                }
983                        }
984                }
985
986                switch(getTextureType()) {
987                case TEX_TYPE_2D:
988                case TEX_TYPE_1D:
989                        assert(mpNormTex);
990                        // For all mipmaps, store surfaces as HardwarePixelBufferSharedPtr
991                        for(mip=0; mip<=mNumMipmaps; ++mip)
992                        {
993                                if(mpNormTex->GetSurfaceLevel(mip, &surface) != D3D_OK)
994                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Get surface level failed",
995                                                "D3D9Texture::_createSurfaceList");
996                                // decrement reference count, the GetSurfaceLevel call increments this
997                                // this is safe because the texture keeps a reference as well
998                                surface->Release();
999
1000                                GETLEVEL(0, mip)->bind(mpDev, surface, updateOldList);
1001                        }
1002                        break;
1003                case TEX_TYPE_CUBE_MAP:
1004                        assert(mpCubeTex);
1005                        // For all faces and mipmaps, store surfaces as HardwarePixelBufferSharedPtr
1006                        for(face=0; face<6; ++face)
1007                        {
1008                                for(mip=0; mip<=mNumMipmaps; ++mip)
1009                                {
1010                                        if(mpCubeTex->GetCubeMapSurface((D3DCUBEMAP_FACES)face, mip, &surface) != D3D_OK)
1011                                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Get cubemap surface failed",
1012                                                "D3D9Texture::getBuffer");
1013                                        // decrement reference count, the GetSurfaceLevel call increments this
1014                                        // this is safe because the texture keeps a reference as well
1015                                        surface->Release();
1016                                       
1017                                        GETLEVEL(face, mip)->bind(mpDev, surface, updateOldList);
1018                                }
1019                        }
1020                        break;
1021                case TEX_TYPE_3D:
1022                        assert(mpVolumeTex);
1023                        // For all mipmaps, store surfaces as HardwarePixelBufferSharedPtr
1024                        for(mip=0; mip<=mNumMipmaps; ++mip)
1025                        {
1026                                if(mpVolumeTex->GetVolumeLevel(mip, &volume) != D3D_OK)
1027                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Get volume level failed",
1028                                                "D3D9Texture::getBuffer");     
1029                                // decrement reference count, the GetSurfaceLevel call increments this
1030                                // this is safe because the texture keeps a reference as well
1031                                volume->Release();
1032                                               
1033                                GETLEVEL(0, mip)->bind(mpDev, volume, updateOldList);
1034                        }
1035                        break;
1036                };
1037               
1038                // Set autogeneration of mipmaps for each face of the texture, if it is enabled
1039                if(mNumRequestedMipmaps != 0 && (mUsage & TU_AUTOMIPMAP))
1040                {
1041                        for(face=0; face<getNumFaces(); ++face)
1042                        {
1043                                GETLEVEL(face, 0)->_setMipmapping(true, mMipmapsHardwareGenerated, mpTex);
1044                        }
1045                }
1046        }
1047        #undef GETLEVEL
1048        /****************************************************************************************/
1049        HardwarePixelBufferSharedPtr D3D9Texture::getBuffer(size_t face, size_t mipmap)
1050        {
1051                if(face >= getNumFaces())
1052                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "A three dimensional cube has six faces",
1053                                        "D3D9Texture::getBuffer");
1054                if(mipmap > mNumMipmaps)
1055                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Mipmap index out of range",
1056                                        "D3D9Texture::getBuffer");
1057                size_t idx = face*(mNumMipmaps+1) + mipmap;
1058                assert(idx < mSurfaceList.size());
1059                return mSurfaceList[idx];
1060        }
1061       
1062       
1063        /****************************************************************************************/
1064        bool D3D9Texture::releaseIfDefaultPool(void)
1065        {
1066                if(mD3DPool == D3DPOOL_DEFAULT)
1067                {
1068                        LogManager::getSingleton().logMessage(
1069                                "Releasing D3D9 default pool texture: " + mName);
1070                        // Just free any internal resources, don't call unload() here
1071                        // because we want the un-touched resource to keep its unloaded status
1072                        // after device reset.
1073                        freeInternalResources();
1074                        LogManager::getSingleton().logMessage(
1075                                "Released D3D9 default pool texture: " + mName);
1076                        return true;
1077                }
1078                return false;
1079        }
1080        /****************************************************************************************/
1081        bool D3D9Texture::recreateIfDefaultPool(LPDIRECT3DDEVICE9 pDev)
1082        {
1083                bool ret = false;
1084                if(mD3DPool == D3DPOOL_DEFAULT)
1085                {
1086                        ret = true;
1087                        LogManager::getSingleton().logMessage(
1088                                "Recreating D3D9 default pool texture: " + mName);
1089                        // We just want to create the texture resources if:
1090                        // 1. This is a render texture, or
1091                        // 2. This is a manual texture with no loader, or
1092                        // 3. This was an unloaded regular texture (preserve unloaded state)
1093                        if ((mIsManual && !mLoader) || (mUsage & TU_RENDERTARGET) || !mIsLoaded)
1094                        {
1095                                // just recreate any internal resources
1096                                createInternalResources();
1097                        }
1098                        // Otherwise, this is a regular loaded texture, or a manual texture with a loader
1099                        else
1100                        {
1101                                // The internal resources already freed, need unload/load here:
1102                                // 1. Make sure resource memory usage statistic correction.
1103                                // 2. Don't call unload() in releaseIfDefaultPool() because we want
1104                                //    the un-touched resource keep unload status after device reset.
1105                                unload();
1106                                // if manual, we need to recreate internal resources since load() won't do that
1107                                if (mIsManual)
1108                                        createInternalResources();
1109                                load();
1110                        }
1111                        LogManager::getSingleton().logMessage(
1112                                "Recreated D3D9 default pool texture: " + mName);
1113                }
1114
1115                return ret;
1116
1117        }
1118
1119
1120        /****************************************************************************************/
1121}
Note: See TracBrowser for help on using the repository browser.