From 1f7cf5520464caa3314926aab779e9724e57c052 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 16 Sep 2018 18:19:04 -0500 Subject: [PATCH] Add cubemap arrays, as well as control for generation of MIPs on texture targets. --- Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp | 153 +++++++++++++++--- Engine/source/gfx/D3D11/gfxD3D11Cubemap.h | 31 +++- Engine/source/gfx/D3D11/gfxD3D11Device.cpp | 32 +++- Engine/source/gfx/D3D11/gfxD3D11Device.h | 7 +- .../gfx/D3D11/gfxD3D11EnumTranslate.cpp | 1 + Engine/source/gfx/D3D11/gfxD3D11Shader.cpp | 3 +- Engine/source/gfx/D3D11/gfxD3D11Target.cpp | 28 +++- Engine/source/gfx/D3D11/gfxD3D11Target.h | 2 +- Engine/source/gfx/Null/gfxNullDevice.cpp | 22 ++- Engine/source/gfx/Null/gfxNullDevice.h | 4 +- Engine/source/gfx/gfxCubemap.cpp | 7 + Engine/source/gfx/gfxCubemap.h | 46 +++++- Engine/source/gfx/gfxDevice.cpp | 62 ++++++- Engine/source/gfx/gfxDevice.h | 12 +- Engine/source/gfx/gfxEnums.h | 5 +- Engine/source/gfx/gfxTarget.h | 6 + Engine/source/gfx/gl/gfxGLCubemap.cpp | 2 +- Engine/source/gfx/gl/gfxGLCubemap.h | 2 +- Engine/source/gfx/gl/gfxGLDevice.cpp | 10 +- Engine/source/gfx/gl/gfxGLDevice.h | 4 +- Engine/source/gfx/gl/gfxGLEnumTranslate.cpp | 3 + Engine/source/gfx/gl/gfxGLTextureTarget.cpp | 8 +- Engine/source/gfx/gl/gfxGLTextureTarget.h | 2 +- Engine/source/gfx/sim/cubemapData.cpp | 15 +- Engine/source/gfx/sim/cubemapData.h | 5 + 25 files changed, 412 insertions(+), 60 deletions(-) diff --git a/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp b/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp index 145a64385..e1f667926 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp @@ -34,7 +34,8 @@ GFXD3D11Cubemap::GFXD3D11Cubemap() : mTexture(NULL), mSRView(NULL), mDSView(NULL for (U32 i = 0; i < CubeFaces; i++) { - mRTView[i] = NULL; + for(U32 j=0; j < MaxMipMaps; j++) + mRTView[i][j] = NULL; } } @@ -50,7 +51,8 @@ void GFXD3D11Cubemap::releaseSurfaces() for (U32 i = 0; i < CubeFaces; i++) { - SAFE_RELEASE(mRTView[i]); + for (U32 j = 0; j < MaxMipMaps; j++) + SAFE_RELEASE(mRTView[i][j]); } SAFE_RELEASE(mDSView); @@ -93,7 +95,7 @@ void GFXD3D11Cubemap::initStatic(GFXTexHandle *faces) desc.Width = mTexSize; desc.Height = mTexSize; desc.MipLevels = mAutoGenMips ? 0 : mMipMapLevels; - desc.ArraySize = 6; + desc.ArraySize = CubeFaces; desc.Format = GFXD3D11TextureFormat[mFaceFormat]; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; @@ -209,16 +211,20 @@ void GFXD3D11Cubemap::initStatic(DDSFile *dds) } } -void GFXD3D11Cubemap::initDynamic(U32 texSize, GFXFormat faceFormat) +void GFXD3D11Cubemap::initDynamic(U32 texSize, GFXFormat faceFormat, U32 mipLevels) { if(!mDynamic) GFXTextureManager::addEventDelegate(this, &GFXD3D11Cubemap::_onTextureEvent); mDynamic = true; - mAutoGenMips = true; mTexSize = texSize; mFaceFormat = faceFormat; - mMipMapLevels = 0; + if (!mipLevels) + mAutoGenMips = true; + + mMipMapLevels = mipLevels; + + bool compressed = ImageUtil::isCompressedFormat(mFaceFormat); UINT bindFlags = D3D11_BIND_SHADER_RESOURCE; @@ -233,7 +239,7 @@ void GFXD3D11Cubemap::initDynamic(U32 texSize, GFXFormat faceFormat) desc.Width = mTexSize; desc.Height = mTexSize; - desc.MipLevels = 0; + desc.MipLevels = mMipMapLevels; desc.ArraySize = 6; desc.Format = GFXD3D11TextureFormat[mFaceFormat]; desc.SampleDesc.Count = 1; @@ -249,7 +255,7 @@ void GFXD3D11Cubemap::initDynamic(U32 texSize, GFXFormat faceFormat) D3D11_SHADER_RESOURCE_VIEW_DESC SMViewDesc; SMViewDesc.Format = GFXD3D11TextureFormat[mFaceFormat]; SMViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - SMViewDesc.TextureCube.MipLevels = -1; + SMViewDesc.TextureCube.MipLevels = mAutoGenMips ? -1 : mMipMapLevels; SMViewDesc.TextureCube.MostDetailedMip = 0; hr = D3D11DEVICE->CreateShaderResourceView(mTexture, &SMViewDesc, &mSRView); @@ -274,18 +280,21 @@ void GFXD3D11Cubemap::initDynamic(U32 texSize, GFXFormat faceFormat) viewDesc.Format = desc.Format; viewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; viewDesc.Texture2DArray.ArraySize = 1; - viewDesc.Texture2DArray.MipSlice = 0; for (U32 i = 0; i < CubeFaces; i++) - { - viewDesc.Texture2DArray.FirstArraySlice = i; - hr = D3D11DEVICE->CreateRenderTargetView(mTexture, &viewDesc, &mRTView[i]); + { + viewDesc.Texture2DArray.FirstArraySlice = i; + for (U32 j = 0; j < mMipMapLevels; j++) + { + viewDesc.Texture2DArray.MipSlice = j; + hr = D3D11DEVICE->CreateRenderTargetView(mTexture, &viewDesc, &mRTView[i][j]); - if(FAILED(hr)) - { - AssertFatal(false, "GFXD3D11Cubemap::initDynamic - CreateRenderTargetView call failure"); - } - } + if (FAILED(hr)) + { + AssertFatal(false, "GFXD3D11Cubemap::initDynamic - CreateRenderTargetView call failure"); + } + } + } D3D11_TEXTURE2D_DESC depthTexDesc; depthTexDesc.Width = mTexSize; @@ -352,16 +361,11 @@ ID3D11ShaderResourceView* GFXD3D11Cubemap::getSRView() return mSRView; } -ID3D11RenderTargetView* GFXD3D11Cubemap::getRTView(U32 faceIdx) +ID3D11RenderTargetView* GFXD3D11Cubemap::getRTView(U32 faceIdx, U32 mipIndex) { AssertFatal(faceIdx < CubeFaces, "GFXD3D11Cubemap::getRTView - face index out of bounds"); - return mRTView[faceIdx]; -} - -ID3D11RenderTargetView** GFXD3D11Cubemap::getRTViewArray() -{ - return mRTView; + return mRTView[faceIdx][mipIndex]; } ID3D11DepthStencilView* GFXD3D11Cubemap::getDSView() @@ -372,4 +376,105 @@ ID3D11DepthStencilView* GFXD3D11Cubemap::getDSView() ID3D11Texture2D* GFXD3D11Cubemap::get2DTex() { return mTexture; +} + +//----------------------------------------------------------------------------- +// Cubemap Array +//----------------------------------------------------------------------------- + +GFXD3D11CubemapArray::GFXD3D11CubemapArray() : mTexture(NULL), mSRView(NULL) +{ +} + +GFXD3D11CubemapArray::~GFXD3D11CubemapArray() +{ + SAFE_RELEASE(mSRView); + SAFE_RELEASE(mTexture); +} + +void GFXD3D11CubemapArray::initStatic(GFXCubemapHandle *cubemaps, const U32 cubemapCount) +{ + AssertFatal(cubemaps, "GFXD3D11CubemapArray - Got null GFXCubemapHandle!"); + AssertFatal(*cubemaps, "GFXD3D11CubemapArray - Got empty cubemap!"); + + //all cubemaps must be the same size,format and number of mipmaps. Grab the details from the first cubemap + mSize = cubemaps[0]->getSize(); + mFormat = cubemaps[0]->getFormat(); + mMipMapLevels = cubemaps[0]->getMipMapLevels(); + mNumCubemaps = cubemapCount; + + //create texture object + UINT bindFlags = D3D11_BIND_SHADER_RESOURCE; + UINT miscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + D3D11_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC)); + desc.Width = mSize; + desc.Height = mSize; + desc.MipLevels = mMipMapLevels; + desc.ArraySize = CubeFaces * cubemapCount; + desc.Format = GFXD3D11TextureFormat[mFormat]; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = bindFlags; + desc.MiscFlags = miscFlags; + desc.CPUAccessFlags = 0; + + HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, NULL, &mTexture); + + if (FAILED(hr)) + AssertFatal(false, "GFXD3D11CubemapArray:initStatic(GFXCubemap *cubemaps,const U32 cubemapCount) - CreateTexture2D failure"); + + for (U32 i = 0; i < cubemapCount; i++) + { + GFXD3D11Cubemap *cubeObj = static_cast((GFXCubemap*)cubemaps[i]); + //yes checking the first one(cubemap at index 0) is pointless but saves a further if statement + if (cubemaps[i]->getSize() != mSize || cubemaps[i]->getFormat() != mFormat || cubemaps[i]->getMipMapLevels() != mMipMapLevels) + { + Con::printf("Trying to add an invalid Cubemap to a CubemapArray"); + //destroy array here first + AssertFatal(false, "GFXD3D11CubemapArray:initStatic(GFXCubemap *cubemaps,const U32 cubemapCount) - invalid cubemap"); + } + + for (U32 face = 0; face < CubeFaces; face++) + { + const U32 arraySlice = face + CubeFaces * i; + for (U32 currentMip = 0; currentMip < mMipMapLevels; currentMip++) + { + const U32 srcSubResource = D3D11CalcSubresource(currentMip, face, mMipMapLevels); + const U32 dstSubResource = D3D11CalcSubresource(currentMip, arraySlice, mMipMapLevels); + D3D11DEVICECONTEXT->CopySubresourceRegion(mTexture, dstSubResource, 0, 0, 0, cubeObj->get2DTex(), srcSubResource, NULL); + } + } + } + + //create shader resource view + D3D11_SHADER_RESOURCE_VIEW_DESC SMViewDesc; + SMViewDesc.Format = GFXD3D11TextureFormat[mFormat]; + SMViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY; + SMViewDesc.TextureCubeArray.MipLevels = mMipMapLevels; + SMViewDesc.TextureCubeArray.MostDetailedMip = 0; + SMViewDesc.TextureCubeArray.NumCubes = mNumCubemaps; + SMViewDesc.TextureCubeArray.First2DArrayFace = 0; + + hr = D3D11DEVICE->CreateShaderResourceView(mTexture, &SMViewDesc, &mSRView); + if (FAILED(hr)) + AssertFatal(false, "GFXD3D11CubemapArray:initStatic(GFXCubemap *cubemaps,const U32 cubemapCount) - shader resource view creation failure"); + +} + +void GFXD3D11CubemapArray::setToTexUnit(U32 tuNum) +{ + D3D11DEVICECONTEXT->PSSetShaderResources(tuNum, 1, &mSRView); +} + +void GFXD3D11CubemapArray::zombify() +{ + // Static cubemaps are handled by D3D +} + +void GFXD3D11CubemapArray::resurrect() +{ + // Static cubemaps are handled by D3D } \ No newline at end of file diff --git a/Engine/source/gfx/D3D11/gfxD3D11Cubemap.h b/Engine/source/gfx/D3D11/gfxD3D11Cubemap.h index fa1fd538c..6f2524622 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Cubemap.h +++ b/Engine/source/gfx/D3D11/gfxD3D11Cubemap.h @@ -29,13 +29,14 @@ #include "gfx/gfxTarget.h" const U32 CubeFaces = 6; +const U32 MaxMipMaps = 13; //todo this needs a proper static value somewhere to sync up with other classes like GBitmap class GFXD3D11Cubemap : public GFXCubemap { public: virtual void initStatic( GFXTexHandle *faces ); virtual void initStatic( DDSFile *dds ); - virtual void initDynamic( U32 texSize, GFXFormat faceFormat = GFXFormatR8G8B8A8 ); + virtual void initDynamic( U32 texSize, GFXFormat faceFormat = GFXFormatR8G8B8A8, U32 mipLevels = 0); virtual void setToTexUnit( U32 tuNum ); virtual U32 getSize() const { return mTexSize; } virtual GFXFormat getFormat() const { return mFaceFormat; } @@ -49,8 +50,7 @@ public: // Get functions ID3D11ShaderResourceView* getSRView(); - ID3D11RenderTargetView* getRTView(U32 faceIdx); - ID3D11RenderTargetView** getRTViewArray(); + ID3D11RenderTargetView* getRTView(U32 faceIdx, U32 mipIndex=0); ID3D11DepthStencilView* getDSView(); ID3D11Texture2D* get2DTex(); @@ -61,7 +61,7 @@ private: ID3D11Texture2D* mTexture; ID3D11ShaderResourceView* mSRView; // for shader resource input - ID3D11RenderTargetView* mRTView[CubeFaces]; // for render targets, 6 faces of the cubemap + ID3D11RenderTargetView* mRTView[CubeFaces][MaxMipMaps]; // for render targets, 6 faces of the cubemap ID3D11DepthStencilView* mDSView; //render target view for depth stencil bool mAutoGenMips; @@ -76,4 +76,27 @@ private: void _onTextureEvent(GFXTexCallbackCode code); }; +class GFXD3D11CubemapArray : public GFXCubemapArray +{ +public: + GFXD3D11CubemapArray(); + virtual ~GFXD3D11CubemapArray(); + virtual void initStatic(GFXCubemapHandle *cubemaps, const U32 cubemapCount); + virtual void setToTexUnit(U32 tuNum); + + ID3D11ShaderResourceView* getSRView() { return mSRView; } + ID3D11Texture2D* get2DTex() { return mTexture; } + + // GFXResource interface + virtual void zombify(); + virtual void resurrect(); + +private: + friend class GFXD3D11TextureTarget; + friend class GFXD3D11Device; + + ID3D11Texture2D *mTexture; + ID3D11ShaderResourceView* mSRView; // for shader resource input +}; + #endif diff --git a/Engine/source/gfx/D3D11/gfxD3D11Device.cpp b/Engine/source/gfx/D3D11/gfxD3D11Device.cpp index 2be8d2a15..5ecde9fb7 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Device.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11Device.cpp @@ -449,7 +449,7 @@ void GFXD3D11Device::init(const GFXVideoMode &mode, PlatformWindow *window) DXGI_SWAP_CHAIN_DESC d3dpp = setupPresentParams(mode, winHwnd); // TODO support at least feature level 10 to match GL - D3D_FEATURE_LEVEL pFeatureLevels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0 }; + D3D_FEATURE_LEVEL pFeatureLevels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1 }; U32 nFeatureCount = ARRAYSIZE(pFeatureLevels); D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_HARDWARE;// use D3D_DRIVER_TYPE_REFERENCE for reference device // create a device, device context and swap chain using the information in the d3dpp struct @@ -689,9 +689,9 @@ GFXWindowTarget * GFXD3D11Device::allocWindowTarget(PlatformWindow *window) return gdwt; } -GFXTextureTarget* GFXD3D11Device::allocRenderToTextureTarget() +GFXTextureTarget* GFXD3D11Device::allocRenderToTextureTarget(bool genMips) { - GFXD3D11TextureTarget *targ = new GFXD3D11TextureTarget(); + GFXD3D11TextureTarget *targ = new GFXD3D11TextureTarget(genMips); targ->registerResourceWithDevice(this); return targ; @@ -963,6 +963,25 @@ void GFXD3D11Device::clear(U32 flags, const LinearColorF& color, F32 z, U32 sten SAFE_RELEASE(dsView); } +void GFXD3D11Device::clearColorAttachment(const U32 attachment, const LinearColorF& color) +{ + GFXD3D11TextureTarget *pTarget = static_cast(mCurrentRT.getPointer()); + ID3D11RenderTargetView* rtView = NULL; + + if (!pTarget) + { + rtView = mDeviceBackBufferView;// we are using the default backbuffer + } + else + { + //attachment + 1 to skip past DepthStencil which is first in the list + rtView = static_cast(pTarget->mTargetViews[attachment + 1]); + } + + const FLOAT clearColor[4] = { color.red, color.green, color.blue, color.alpha }; + mD3DDeviceContext->ClearRenderTargetView(rtView, clearColor); +} + void GFXD3D11Device::endSceneInternal() { mCanCurrentlyRender = false; @@ -1837,6 +1856,13 @@ GFXCubemap * GFXD3D11Device::createCubemap() return cube; } +GFXCubemapArray * GFXD3D11Device::createCubemapArray() +{ + GFXD3D11CubemapArray* cubeArray = new GFXD3D11CubemapArray(); + cubeArray->registerResourceWithDevice(this); + return cubeArray; +} + // Debug events //------------------------------------------------------------------------------ void GFXD3D11Device::enterDebugEvent(ColorI color, const char *name) diff --git a/Engine/source/gfx/D3D11/gfxD3D11Device.h b/Engine/source/gfx/D3D11/gfxD3D11Device.h index 9aabb74ee..381589c0f 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Device.h +++ b/Engine/source/gfx/D3D11/gfxD3D11Device.h @@ -71,7 +71,7 @@ private: virtual void enumerateVideoModes(); virtual GFXWindowTarget *allocWindowTarget(PlatformWindow *window); - virtual GFXTextureTarget *allocRenderToTextureTarget(); + virtual GFXTextureTarget *allocRenderToTextureTarget(bool genMips = true); virtual void enterDebugEvent(ColorI color, const char *name); virtual void leaveDebugEvent(); @@ -237,6 +237,7 @@ public: U32 getAdaterIndex() const { return mAdapterIndex; } virtual GFXCubemap *createCubemap(); + virtual GFXCubemapArray *createCubemapArray(); virtual F32 getPixelShaderVersion() const { return mPixVersion; } virtual void setPixelShaderVersion( F32 version ){ mPixVersion = version;} @@ -249,6 +250,8 @@ public: // Misc rendering control // { virtual void clear( U32 flags, const LinearColorF& color, F32 z, U32 stencil ); + virtual void clearColorAttachment(const U32 attachment, const LinearColorF& color); + virtual bool beginSceneInternal(); virtual void endSceneInternal(); @@ -325,7 +328,7 @@ public: // grab the sampler map const SamplerMap &getSamplersMap() const { return mSamplersMap; } - SamplerMap &getSamplersMap() { return mSamplersMap; } + SamplerMap &getSamplersMap(){ return mSamplersMap; } }; #endif diff --git a/Engine/source/gfx/D3D11/gfxD3D11EnumTranslate.cpp b/Engine/source/gfx/D3D11/gfxD3D11EnumTranslate.cpp index 92e30fdc2..3114cb689 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11EnumTranslate.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11EnumTranslate.cpp @@ -67,6 +67,7 @@ void GFXD3D11EnumTranslate::init() GFXD3D11TextureFormat[GFXFormatR16F] = DXGI_FORMAT_R16_FLOAT; GFXD3D11TextureFormat[GFXFormatR16G16F] = DXGI_FORMAT_R16G16_FLOAT; GFXD3D11TextureFormat[GFXFormatR10G10B10A2] = DXGI_FORMAT_R10G10B10A2_UNORM; + GFXD3D11TextureFormat[GFXFormatR11G11B10] = DXGI_FORMAT_R11G11B10_FLOAT; GFXD3D11TextureFormat[GFXFormatD32] = DXGI_FORMAT_UNKNOWN; GFXD3D11TextureFormat[GFXFormatD24X8] = DXGI_FORMAT_UNKNOWN; GFXD3D11TextureFormat[GFXFormatD24S8] = DXGI_FORMAT_D24_UNORM_S8_UINT; diff --git a/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp b/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp index 897cbacaa..8a53170e7 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp @@ -1384,7 +1384,8 @@ void GFXD3D11Shader::_buildSamplerShaderConstantHandles( Vectorget2DTex(); mTargets[slot]->AddRef(); - mTargetViews[slot] = cube->getRTView(face); + mTargetViews[slot] = cube->getRTView(face, mipLevel); mTargetViews[slot]->AddRef(); mTargetSRViews[slot] = cube->getSRView(); mTargetSRViews[slot]->AddRef(); @@ -262,6 +264,9 @@ void GFXD3D11TextureTarget::activate() void GFXD3D11TextureTarget::deactivate() { + if (!mGenMips) + return; + //re-gen mip maps for (U32 i = 0; i < 6; i++) { @@ -347,7 +352,23 @@ GFXFormat GFXD3D11WindowTarget::getFormat() bool GFXD3D11WindowTarget::present() { - return (D3D11->getSwapChain()->Present(!D3D11->smDisableVSync, 0) == S_OK); + HRESULT hr = D3D11->getSwapChain()->Present(!D3D11->smDisableVSync, 0); + if (hr == DXGI_ERROR_DEVICE_REMOVED) + { + HRESULT result = D3D11->getDevice()->GetDeviceRemovedReason(); + if (result == DXGI_ERROR_DEVICE_HUNG) + AssertFatal(false,"DXGI_ERROR_DEVICE_HUNG"); + else if (result == DXGI_ERROR_DEVICE_REMOVED) + AssertFatal(false, "DXGI_ERROR_DEVICE_REMOVED"); + else if (result == DXGI_ERROR_DEVICE_RESET) + AssertFatal(false, "DXGI_ERROR_DEVICE_RESET"); + else if (result == DXGI_ERROR_DRIVER_INTERNAL_ERROR) + AssertFatal(false, "DXGI_ERROR_DRIVER_INTERNAL_ERROR"); + else if (result == DXGI_ERROR_INVALID_CALL) + AssertFatal(false, "DXGI_ERROR_INVALID_CALL"); + } + + return (hr == S_OK); } void GFXD3D11WindowTarget::setImplicitSwapChain() @@ -370,7 +391,6 @@ void GFXD3D11WindowTarget::resetMode() mSize = Point2I(mPresentationParams.BufferDesc.Width, mPresentationParams.BufferDesc.Height); mWindow->setSuppressReset(false); - GFX->beginReset(); } void GFXD3D11WindowTarget::zombify() diff --git a/Engine/source/gfx/D3D11/gfxD3D11Target.h b/Engine/source/gfx/D3D11/gfxD3D11Target.h index 055f11ccf..dbe1baf68 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Target.h +++ b/Engine/source/gfx/D3D11/gfxD3D11Target.h @@ -51,7 +51,7 @@ class GFXD3D11TextureTarget : public GFXTextureTarget public: - GFXD3D11TextureTarget(); + GFXD3D11TextureTarget(bool genMips); ~GFXD3D11TextureTarget(); // Public interface. diff --git a/Engine/source/gfx/Null/gfxNullDevice.cpp b/Engine/source/gfx/Null/gfxNullDevice.cpp index 6b2b0b659..fbf854d2b 100644 --- a/Engine/source/gfx/Null/gfxNullDevice.cpp +++ b/Engine/source/gfx/Null/gfxNullDevice.cpp @@ -151,7 +151,7 @@ private: public: virtual void initStatic( GFXTexHandle *faces ) { }; virtual void initStatic( DDSFile *dds ) { }; - virtual void initDynamic( U32 texSize, GFXFormat faceFormat = GFXFormatR8G8B8A8 ) { }; + virtual void initDynamic( U32 texSize, GFXFormat faceFormat = GFXFormatR8G8B8A8, U32 mipLevels = 0) { }; virtual U32 getSize() const { return 0; } virtual GFXFormat getFormat() const { return GFXFormatR8G8B8A8; } @@ -161,6 +161,21 @@ public: virtual void resurrect() {} }; +class GFXNullCubemapArray : public GFXCubemapArray +{ + friend class GFXDevice; +private: + // should only be called by GFXDevice + virtual void setToTexUnit(U32 tuNum) { }; + +public: + virtual void initStatic(GFXCubemapHandle *cubemaps, const U32 cubemapCount) { }; + + virtual ~GFXNullCubemapArray() {}; + virtual void zombify() {} + virtual void resurrect() {} +}; + class GFXNullVertexBuffer : public GFXVertexBuffer { unsigned char* tempBuf; @@ -295,6 +310,11 @@ GFXCubemap* GFXNullDevice::createCubemap() return new GFXNullCubemap(); }; +GFXCubemapArray* GFXNullDevice::createCubemapArray() +{ + return new GFXNullCubemapArray(); +}; + void GFXNullDevice::enumerateAdapters( Vector &adapterList ) { // Add the NULL renderer diff --git a/Engine/source/gfx/Null/gfxNullDevice.h b/Engine/source/gfx/Null/gfxNullDevice.h index 8fa5477fa..672e86bbd 100644 --- a/Engine/source/gfx/Null/gfxNullDevice.h +++ b/Engine/source/gfx/Null/gfxNullDevice.h @@ -129,12 +129,13 @@ protected: public: virtual GFXCubemap * createCubemap(); + virtual GFXCubemapArray *createCubemapArray(); virtual F32 getFillConventionOffset() const { return 0.0f; }; ///@} - virtual GFXTextureTarget *allocRenderToTextureTarget(){return NULL;}; + virtual GFXTextureTarget *allocRenderToTextureTarget(bool genMips=true){return NULL;}; virtual GFXWindowTarget *allocWindowTarget(PlatformWindow *window) { return new GFXNullWindowTarget(); @@ -151,6 +152,7 @@ public: virtual void clear( U32 flags, const LinearColorF& color, F32 z, U32 stencil ) { }; + virtual void clearColorAttachment(const U32 attachment, const LinearColorF& color) { }; virtual bool beginSceneInternal() { return true; }; virtual void endSceneInternal() { }; diff --git a/Engine/source/gfx/gfxCubemap.cpp b/Engine/source/gfx/gfxCubemap.cpp index 3cce8bda8..9a556663f 100644 --- a/Engine/source/gfx/gfxCubemap.cpp +++ b/Engine/source/gfx/gfxCubemap.cpp @@ -124,3 +124,10 @@ bool GFXCubemapHandle::set( const String &cubemapDDS ) return isValid(); } + +const String GFXCubemapArray::describeSelf() const +{ + // We've got nothing + return String(); +} + diff --git a/Engine/source/gfx/gfxCubemap.h b/Engine/source/gfx/gfxCubemap.h index f056ee65b..ed175e73e 100644 --- a/Engine/source/gfx/gfxCubemap.h +++ b/Engine/source/gfx/gfxCubemap.h @@ -59,8 +59,8 @@ public: /// Create a static cubemap from a DDS cubemap file. virtual void initStatic( DDSFile *dds ) = 0; - /// - virtual void initDynamic( U32 texSize, GFXFormat faceFormat = GFXFormatR8G8B8A8 ) = 0; + ///create dynamic cubemap. mipLevels 0 is auto create mips, otherwise the value is how many mip levels you wish the cubemap to have + virtual void initDynamic( U32 texSize, GFXFormat faceFormat = GFXFormatR8G8B8A8, U32 mipLevels = 0 ) = 0; void initNormalize(U32 size); @@ -99,5 +99,47 @@ public: void free() { StrongObjectRef::set( NULL ); } }; +/// Cubemap array +class GFXCubemapArray : public StrongRefBase, public GFXResource +{ + friend class GFXDevice; + friend class GFXTextureManager; + +protected: + // should only be called by GFXDevice + virtual void setToTexUnit( U32 tuNum ) = 0; + /// number of cubemaps in the array + U32 mNumCubemaps; + U32 mSize; + U32 mMipMapLevels; + GFXFormat mFormat; + +public: + + virtual ~GFXCubemapArray() {}; + + virtual void initStatic(GFXCubemapHandle *cubemaps, const U32 cubemapCount) = 0; + /// Return number of textures in the array + const U32 getNumCubemaps() const { return mNumCubemaps; } + /// Get the number of mip maps + const U32 getMipMapLevels() const { return mMipMapLevels; } + /// Returns the size of the faces. + const U32 getSize() const { return mSize; } + + virtual const String describeSelf() const; +}; + +/// A reference counted handle to a cubemap array resource. +class GFXCubemapArrayHandle : public StrongRefPtr +{ +public: + GFXCubemapArrayHandle() {} + GFXCubemapArrayHandle(GFXCubemapArray *cubemapArray) { StrongRefPtr::set(cubemapArray); } + + /// Releases the texture handle. + void free() { StrongObjectRef::set(NULL); } +}; + + #endif // GFXCUBEMAP diff --git a/Engine/source/gfx/gfxDevice.cpp b/Engine/source/gfx/gfxDevice.cpp index 28add7718..64bf96cc9 100644 --- a/Engine/source/gfx/gfxDevice.cpp +++ b/Engine/source/gfx/gfxDevice.cpp @@ -131,6 +131,8 @@ GFXDevice::GFXDevice() mNewTexture[i] = NULL; mCurrentCubemap[i] = NULL; mNewCubemap[i] = NULL; + mCurrentCubemapArray[i] = NULL; + mNewCubemapArray[i] = NULL; mTexType[i] = GFXTDT_Normal; mTextureMatrix[i].identity(); @@ -262,6 +264,8 @@ GFXDevice::~GFXDevice() mNewTexture[i] = NULL; mCurrentCubemap[i] = NULL; mNewCubemap[i] = NULL; + mCurrentCubemapArray[i] = NULL; + mNewCubemapArray[i] = NULL; } mCurrentRT = NULL; @@ -398,6 +402,15 @@ void GFXDevice::updateStates(bool forceSetAll /*=false*/) setTextureInternal(i, NULL); } break; + case GFXTDT_CubeArray: + { + mCurrentCubemapArray[i] = mNewCubemapArray[i]; + if (mCurrentCubemapArray[i]) + mCurrentCubemapArray[i]->setToTexUnit(i); + else + setTextureInternal(i, NULL); + } + break; default: AssertFatal(false, "Unknown texture type!"); break; @@ -537,6 +550,15 @@ void GFXDevice::updateStates(bool forceSetAll /*=false*/) setTextureInternal(i, NULL); } break; + case GFXTDT_CubeArray: + { + mCurrentCubemapArray[i] = mNewCubemapArray[i]; + if (mCurrentCubemapArray[i]) + mCurrentCubemapArray[i]->setToTexUnit(i); + else + setTextureInternal(i, NULL); + } + break; default: AssertFatal(false, "Unknown texture type!"); break; @@ -777,30 +799,60 @@ void GFXDevice::setTexture( U32 stage, GFXTextureObject *texture ) // Clear out the cubemaps mNewCubemap[stage] = NULL; mCurrentCubemap[stage] = NULL; + mNewCubemapArray[stage] = NULL; + mCurrentCubemapArray[stage] = NULL; } //----------------------------------------------------------------------------- // Set cube texture //----------------------------------------------------------------------------- -void GFXDevice::setCubeTexture( U32 stage, GFXCubemap *texture ) +void GFXDevice::setCubeTexture( U32 stage, GFXCubemap *cubemap ) { AssertFatal(stage < getNumSamplers(), "GFXDevice::setTexture - out of range stage!"); if ( mTexType[stage] == GFXTDT_Cube && - ( ( mTextureDirty[stage] && mNewCubemap[stage].getPointer() == texture ) || - ( !mTextureDirty[stage] && mCurrentCubemap[stage].getPointer() == texture ) ) ) + ( ( mTextureDirty[stage] && mNewCubemap[stage].getPointer() == cubemap) || + ( !mTextureDirty[stage] && mCurrentCubemap[stage].getPointer() == cubemap) ) ) return; mStateDirty = true; mTexturesDirty = true; mTextureDirty[stage] = true; - mNewCubemap[stage] = texture; + mNewCubemap[stage] = cubemap; mTexType[stage] = GFXTDT_Cube; - // Clear out the normal textures + // Clear out textures mNewTexture[stage] = NULL; mCurrentTexture[stage] = NULL; + mNewCubemapArray[stage] = NULL; + mCurrentCubemapArray[stage] = NULL; +} + +//----------------------------------------------------------------------------- +// Set cube texture array +//----------------------------------------------------------------------------- +void GFXDevice::setCubeArrayTexture(U32 stage, GFXCubemapArray *cubemapArray) +{ + AssertFatal(stage < getNumSamplers(), "GFXDevice::setTexture - out of range stage!"); + + if (mTexType[stage] == GFXTDT_CubeArray && + ((mTextureDirty[stage] && mNewCubemapArray[stage].getPointer() == cubemapArray) || + (!mTextureDirty[stage] && mCurrentCubemapArray[stage].getPointer() == cubemapArray))) + return; + + mStateDirty = true; + mTexturesDirty = true; + mTextureDirty[stage] = true; + + mNewCubemapArray[stage] = cubemapArray; + mTexType[stage] = GFXTDT_CubeArray; + + // Clear out textures + mNewTexture[stage] = NULL; + mCurrentTexture[stage] = NULL; + mNewCubemap[stage] = NULL; + mCurrentCubemap[stage] = NULL; } //------------------------------------------------------------------------------ diff --git a/Engine/source/gfx/gfxDevice.h b/Engine/source/gfx/gfxDevice.h index acfa06843..c893287d0 100644 --- a/Engine/source/gfx/gfxDevice.h +++ b/Engine/source/gfx/gfxDevice.h @@ -497,13 +497,16 @@ protected: enum TexDirtyType { GFXTDT_Normal, - GFXTDT_Cube + GFXTDT_Cube, + GFXTDT_CubeArray }; GFXTexHandle mCurrentTexture[TEXTURE_STAGE_COUNT]; GFXTexHandle mNewTexture[TEXTURE_STAGE_COUNT]; GFXCubemapHandle mCurrentCubemap[TEXTURE_STAGE_COUNT]; GFXCubemapHandle mNewCubemap[TEXTURE_STAGE_COUNT]; + GFXCubemapArrayHandle mCurrentCubemapArray[TEXTURE_STAGE_COUNT]; + GFXCubemapArrayHandle mNewCubemapArray[TEXTURE_STAGE_COUNT]; TexDirtyType mTexType[TEXTURE_STAGE_COUNT]; bool mTextureDirty[TEXTURE_STAGE_COUNT]; @@ -753,6 +756,7 @@ protected: public: virtual GFXCubemap * createCubemap() = 0; + virtual GFXCubemapArray *createCubemapArray() = 0; inline GFXTextureManager *getTextureManager() { @@ -778,7 +782,7 @@ public: /// Allocate a target for doing render to texture operations, with no /// depth/stencil buffer. - virtual GFXTextureTarget *allocRenderToTextureTarget()=0; + virtual GFXTextureTarget *allocRenderToTextureTarget(bool genMips = true) = 0; /// Allocate a target for a given window. virtual GFXWindowTarget *allocWindowTarget(PlatformWindow *window)=0; @@ -827,6 +831,7 @@ public: /// virtual void clear( U32 flags, const LinearColorF& color, F32 z, U32 stencil ) = 0; + virtual void clearColorAttachment(const U32 attachment, const LinearColorF& color) = 0; virtual bool beginScene(); virtual void endScene(); virtual void beginField(); @@ -937,8 +942,9 @@ public: /// @{ /// - void setTexture(U32 stage, GFXTextureObject*texture); + void setTexture(U32 stage, GFXTextureObject *texture); void setCubeTexture( U32 stage, GFXCubemap *cubemap ); + void setCubeArrayTexture( U32 stage, GFXCubemapArray *cubemapArray); inline GFXTextureObject* getCurrentTexture( U32 stage ) { return mCurrentTexture[stage]; } /// @} diff --git a/Engine/source/gfx/gfxEnums.h b/Engine/source/gfx/gfxEnums.h index 85b224b02..12a7337b8 100644 --- a/Engine/source/gfx/gfxEnums.h +++ b/Engine/source/gfx/gfxEnums.h @@ -188,6 +188,7 @@ enum GFXFormat GFXFormatR16G16, GFXFormatR16G16F, GFXFormatR10G10B10A2, + GFXFormatR11G11B10, GFXFormatD32, GFXFormatD24X8, GFXFormatD24S8, @@ -495,6 +496,7 @@ enum GFXTextureTransformFlags // CodeReview: This number is used for the declaration of variables, but it // should *not* be used for any run-time purposes [7/2/2007 Pat] +#define TEXTURE_STAGE_COUNT 32 #define TEXTURE_STAGE_COUNT 16 enum GFXSamplerState @@ -597,7 +599,8 @@ enum GFXShaderConstType GFXSCT_Int4, // Samplers GFXSCT_Sampler, - GFXSCT_SamplerCube + GFXSCT_SamplerCube, + GFXSCT_SamplerCubeArray }; diff --git a/Engine/source/gfx/gfxTarget.h b/Engine/source/gfx/gfxTarget.h index ae1cc0097..9d774d5f8 100644 --- a/Engine/source/gfx/gfxTarget.h +++ b/Engine/source/gfx/gfxTarget.h @@ -196,6 +196,12 @@ public: /// /// By default, this method will resolve all color targets. virtual void resolve()=0; + + /// Returns true if the automatic generation of mip maps is enabled + inline bool isGenMipsEnabled() const { return mGenMips; } + +protected: + bool mGenMips; }; typedef StrongRefPtr GFXTargetRef; diff --git a/Engine/source/gfx/gl/gfxGLCubemap.cpp b/Engine/source/gfx/gl/gfxGLCubemap.cpp index 91e951abc..c74d44025 100644 --- a/Engine/source/gfx/gl/gfxGLCubemap.cpp +++ b/Engine/source/gfx/gl/gfxGLCubemap.cpp @@ -181,7 +181,7 @@ void GFXGLCubemap::initStatic( DDSFile *dds ) } } -void GFXGLCubemap::initDynamic(U32 texSize, GFXFormat faceFormat) +void GFXGLCubemap::initDynamic(U32 texSize, GFXFormat faceFormat, U32 mipLevels) { mDynamicTexSize = texSize; mFaceFormat = faceFormat; diff --git a/Engine/source/gfx/gl/gfxGLCubemap.h b/Engine/source/gfx/gl/gfxGLCubemap.h index 7477d4a32..47bd72b62 100644 --- a/Engine/source/gfx/gl/gfxGLCubemap.h +++ b/Engine/source/gfx/gl/gfxGLCubemap.h @@ -39,7 +39,7 @@ public: virtual void initStatic( GFXTexHandle *faces ); virtual void initStatic( DDSFile *dds ); - virtual void initDynamic( U32 texSize, GFXFormat faceFormat = GFXFormatR8G8B8A8 ); + virtual void initDynamic( U32 texSize, GFXFormat faceFormat = GFXFormatR8G8B8A8, U32 mipLevels = 0); virtual U32 getSize() const { return mWidth; } virtual GFXFormat getFormat() const { return mFaceFormat; } diff --git a/Engine/source/gfx/gl/gfxGLDevice.cpp b/Engine/source/gfx/gl/gfxGLDevice.cpp index d2a1853ee..d135ee06a 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.cpp +++ b/Engine/source/gfx/gl/gfxGLDevice.cpp @@ -495,6 +495,12 @@ void GFXGLDevice::clear(U32 flags, const LinearColorF& color, F32 z, U32 stencil glStencilMask(desc->stencilWriteMask); } +void GFXGLDevice::clearColorAttachment(const U32 attachment, const LinearColorF& color) +{ + const GLfloat clearColor[4] = { color.red, color.green, color.blue, color.alpha }; + glClearBufferfv(GL_COLOR, attachment, clearColor); +} + // Given a primitive type and a number of primitives, return the number of indexes/vertexes used. inline GLsizei GFXGLDevice::primCountToIndexCount(GFXPrimitiveType primType, U32 primitiveCount) { @@ -749,9 +755,9 @@ void GFXGLDevice::setStateBlockInternal(GFXStateBlock* block, bool force) //------------------------------------------------------------------------------ -GFXTextureTarget * GFXGLDevice::allocRenderToTextureTarget() +GFXTextureTarget * GFXGLDevice::allocRenderToTextureTarget(bool genMips) { - GFXGLTextureTarget *targ = new GFXGLTextureTarget(); + GFXGLTextureTarget *targ = new GFXGLTextureTarget(genMips); targ->registerResourceWithDevice(this); return targ; } diff --git a/Engine/source/gfx/gl/gfxGLDevice.h b/Engine/source/gfx/gl/gfxGLDevice.h index a271f9e2b..5fdb63c41 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.h +++ b/Engine/source/gfx/gl/gfxGLDevice.h @@ -81,6 +81,7 @@ public: virtual U32 getTotalVideoMemory(); virtual GFXCubemap * createCubemap(); + virtual GFXCubemapArray *createCubemapArray() { return NULL; } //TODO: implement virtual F32 getFillConventionOffset() const { return 0.0f; } @@ -91,7 +92,7 @@ public: /// @{ /// - virtual GFXTextureTarget *allocRenderToTextureTarget(); + virtual GFXTextureTarget *allocRenderToTextureTarget(bool genMips = true); virtual GFXWindowTarget *allocWindowTarget(PlatformWindow *window); virtual void _updateRenderTargets(); @@ -117,6 +118,7 @@ public: virtual GFXShader* createShader(); virtual void clear( U32 flags, const LinearColorF& color, F32 z, U32 stencil ); + virtual void clearColorAttachment(const U32 attachment, const LinearColorF& color); virtual bool beginSceneInternal(); virtual void endSceneInternal(); diff --git a/Engine/source/gfx/gl/gfxGLEnumTranslate.cpp b/Engine/source/gfx/gl/gfxGLEnumTranslate.cpp index bfed4f047..0ab380db5 100644 --- a/Engine/source/gfx/gl/gfxGLEnumTranslate.cpp +++ b/Engine/source/gfx/gl/gfxGLEnumTranslate.cpp @@ -138,6 +138,7 @@ void GFXGLEnumTranslate::init() GFXGLTextureInternalFormat[GFXFormatR8G8B8X8] = GL_RGBA8; GFXGLTextureInternalFormat[GFXFormatB8G8R8A8] = GL_RGBA8; GFXGLTextureInternalFormat[GFXFormatR10G10B10A2] = GL_RGB10_A2; + GFXGLTextureInternalFormat[GFXFormatR11G11B10] = GL_R11F_G11F_B10F; GFXGLTextureInternalFormat[GFXFormatD32] = GL_DEPTH_COMPONENT32; GFXGLTextureInternalFormat[GFXFormatD24X8] = GL_DEPTH24_STENCIL8; GFXGLTextureInternalFormat[GFXFormatD24S8] = GL_DEPTH24_STENCIL8; @@ -165,6 +166,7 @@ void GFXGLEnumTranslate::init() GFXGLTextureFormat[GFXFormatR8G8B8X8] = GL_RGBA; GFXGLTextureFormat[GFXFormatB8G8R8A8] = GL_BGRA; GFXGLTextureFormat[GFXFormatR10G10B10A2] = GL_RGBA; + GFXGLTextureFormat[GFXFormatR11G11B10] = GL_RGB; GFXGLTextureFormat[GFXFormatD32] = GL_DEPTH_COMPONENT; GFXGLTextureFormat[GFXFormatD24X8] = GL_DEPTH_STENCIL; GFXGLTextureFormat[GFXFormatD24S8] = GL_DEPTH_STENCIL; @@ -192,6 +194,7 @@ void GFXGLEnumTranslate::init() GFXGLTextureType[GFXFormatR8G8B8X8] = GL_UNSIGNED_BYTE; GFXGLTextureType[GFXFormatB8G8R8A8] = GL_UNSIGNED_BYTE;; GFXGLTextureType[GFXFormatR10G10B10A2] = GL_UNSIGNED_INT_10_10_10_2; + GFXGLTextureType[GFXFormatR11G11B10] = GL_UNSIGNED_INT_10F_11F_11F_REV; GFXGLTextureType[GFXFormatD32] = GL_UNSIGNED_INT; GFXGLTextureType[GFXFormatD24X8] = GL_UNSIGNED_INT_24_8; GFXGLTextureType[GFXFormatD24S8] = GL_UNSIGNED_INT_24_8; diff --git a/Engine/source/gfx/gl/gfxGLTextureTarget.cpp b/Engine/source/gfx/gl/gfxGLTextureTarget.cpp index 35011c357..4cfc47854 100644 --- a/Engine/source/gfx/gl/gfxGLTextureTarget.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureTarget.cpp @@ -136,6 +136,7 @@ class _GFXGLTextureTargetFBOImpl : public _GFXGLTextureTargetImpl { public: GLuint mFramebuffer; + bool mGenMips; _GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target); virtual ~_GFXGLTextureTargetFBOImpl(); @@ -147,6 +148,7 @@ public: _GFXGLTextureTargetFBOImpl::_GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target) { + mGenMips = target->isGenMipsEnabled(); mTarget = target; glGenFramebuffers(1, &mFramebuffer); } @@ -245,6 +247,9 @@ void _GFXGLTextureTargetFBOImpl::finish() glBindFramebuffer(GL_FRAMEBUFFER, 0); GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, 0); + if (!mGenMips) + return; + for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i) { _GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast(GFXTextureTarget::Color0+i ) ); @@ -263,8 +268,9 @@ void _GFXGLTextureTargetFBOImpl::finish() } // Actual GFXGLTextureTarget interface -GFXGLTextureTarget::GFXGLTextureTarget() : mCopyFboSrc(0), mCopyFboDst(0) +GFXGLTextureTarget::GFXGLTextureTarget(bool genMips) : mCopyFboSrc(0), mCopyFboDst(0) { + mGenMips = genMips; for(U32 i=0; i= 6) @@ -172,6 +177,14 @@ void CubemapData::setCubeFaceFile(U32 index, FileName newFaceFile) mCubeFaceFile[index] = newFaceFile; } +void CubemapData::setCubeFaceTexture(U32 index, GFXTexHandle newFaceTexture) +{ + if (index >= 6) + return; + + mCubeFace[index] = newFaceTexture; +} + DefineEngineMethod( CubemapData, updateFaces, void, (),, "Update the assigned cubemaps faces." ) { diff --git a/Engine/source/gfx/sim/cubemapData.h b/Engine/source/gfx/sim/cubemapData.h index 981b78539..ba2edbcf9 100644 --- a/Engine/source/gfx/sim/cubemapData.h +++ b/Engine/source/gfx/sim/cubemapData.h @@ -63,7 +63,12 @@ public: // Update a static cubemap @ pos void updateFaces(); + void setCubemapFile(FileName newCubemapFile); + void setCubeFaceFile(U32 index, FileName newFaceFile); + + void setCubeFaceTexture(U32 index, GFXTexHandle newFaceTexture); + GFXTexHandle* getCubeMapFace(U32 faceIdx) { return &mCubeFace[faceIdx]; } protected: