From 87dd7ffc4a87dc05dd35f1979f566aee8d3640b4 Mon Sep 17 00:00:00 2001 From: Lukas Aldershaab Date: Fri, 1 Jan 2021 21:05:21 +0100 Subject: [PATCH] Implement Singlepass Terrain Render --- Engine/source/gfx/D3D11/gfxD3D11Device.cpp | 11 + Engine/source/gfx/D3D11/gfxD3D11Device.h | 1 + Engine/source/gfx/D3D11/gfxD3D11Shader.cpp | 3 +- .../source/gfx/D3D11/gfxD3D11TextureArray.cpp | 266 ++++++ .../source/gfx/D3D11/gfxD3D11TextureArray.h | 51 ++ .../gfx/D3D11/gfxD3D11TextureObject.cpp | 5 +- Engine/source/gfx/Null/gfxNullDevice.cpp | 15 + Engine/source/gfx/Null/gfxNullDevice.h | 1 + Engine/source/gfx/bitmap/gBitmap.cpp | 16 +- Engine/source/gfx/bitmap/gBitmap.h | 2 +- Engine/source/gfx/gfxDevice.cpp | 72 +- Engine/source/gfx/gfxDevice.h | 8 +- Engine/source/gfx/gfxEnums.h | 3 +- Engine/source/gfx/gfxTextureArray.cpp | 7 + Engine/source/gfx/gfxTextureArray.h | 72 ++ Engine/source/gfx/gfxTextureManager.cpp | 36 + Engine/source/gfx/gfxTextureManager.h | 2 + Engine/source/gfx/gl/gfxGLDevice.cpp | 25 + Engine/source/gfx/gl/gfxGLDevice.h | 4 + Engine/source/gfx/gl/gfxGLShader.cpp | 16 +- Engine/source/gfx/gl/gfxGLStateCache.h | 14 +- Engine/source/gfx/gl/gfxGLTextureArray.cpp | 215 +++++ Engine/source/gfx/gl/gfxGLTextureArray.h | 34 + Engine/source/gfx/gl/gfxGLUtils.h | 3 + Engine/source/shaderGen/shaderOp.cpp | 23 + Engine/source/shaderGen/shaderOp.h | 15 + .../source/terrain/glsl/terrFeatureGLSL.cpp | 292 +++---- Engine/source/terrain/glsl/terrFeatureGLSL.h | 17 +- .../source/terrain/hlsl/terrFeatureHLSL.cpp | 409 +++++----- Engine/source/terrain/hlsl/terrFeatureHLSL.h | 17 +- Engine/source/terrain/terrCellMaterial.cpp | 757 ++++++++---------- Engine/source/terrain/terrCellMaterial.h | 116 +-- Engine/source/terrain/terrData.cpp | 12 +- Engine/source/terrain/terrData.h | 10 + Engine/source/terrain/terrRender.cpp | 59 +- 35 files changed, 1658 insertions(+), 951 deletions(-) create mode 100644 Engine/source/gfx/D3D11/gfxD3D11TextureArray.cpp create mode 100644 Engine/source/gfx/D3D11/gfxD3D11TextureArray.h create mode 100644 Engine/source/gfx/gfxTextureArray.cpp create mode 100644 Engine/source/gfx/gfxTextureArray.h create mode 100644 Engine/source/gfx/gl/gfxGLTextureArray.cpp create mode 100644 Engine/source/gfx/gl/gfxGLTextureArray.h diff --git a/Engine/source/gfx/D3D11/gfxD3D11Device.cpp b/Engine/source/gfx/D3D11/gfxD3D11Device.cpp index 1bbd68e6d..01fd8056f 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Device.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11Device.cpp @@ -40,6 +40,8 @@ #include "shaderGen/shaderGen.h" #include //d3dperf +#include "gfxD3D11TextureArray.h" + #ifdef TORQUE_DEBUG #include "d3d11sdklayers.h" #endif @@ -48,6 +50,8 @@ #pragma comment(lib, "d3d9.lib") //d3dperf #pragma comment(lib, "d3d11.lib") +class GFXD3D11TextureArray; + class GFXPCD3D11RegisterDevice { public: @@ -1736,6 +1740,13 @@ GFXCubemapArray * GFXD3D11Device::createCubemapArray() return cubeArray; } +GFXTextureArray * GFXD3D11Device::createTextureArray() +{ + GFXD3D11TextureArray* textureArray = new GFXD3D11TextureArray(); + textureArray->registerResourceWithDevice(this); + return textureArray; +} + // 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 75525ce95..b60e5d2a6 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Device.h +++ b/Engine/source/gfx/D3D11/gfxD3D11Device.h @@ -231,6 +231,7 @@ public: virtual GFXCubemap *createCubemap(); virtual GFXCubemapArray *createCubemapArray(); + virtual GFXTextureArray* createTextureArray(); virtual F32 getPixelShaderVersion() const { return mPixVersion; } virtual void setPixelShaderVersion( F32 version ){ mPixVersion = version;} diff --git a/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp b/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp index 1dcf8ca10..17827349d 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp @@ -1385,7 +1385,8 @@ void GFXD3D11Shader::_buildSamplerShaderConstantHandles( Vector + +#include "gfxD3D11Device.h" +#include "gfxD3D11EnumTranslate.h" +#include "core/util/tVector.h" +#include "gfx/gfxDebugEvent.h" +#include "gfx/bitmap/imageUtils.h" +#include "gfx/util/screenspace.h" +#include "shaderGen/shaderFeature.h" + + +bool GFXD3D11TextureArray::fromTextureArray(const Vector &textureArray) +{ + bool success = true; + Vector texture2Ds; + texture2Ds.setSize(textureArray.size()); + Vector tmpHandles; + + mArraySize = textureArray.size(); + + //--------------------------------------------------------------------------------------- + // Create the texture array. Each element in the texture + // array has the same format/dimensions. + //--------------------------------------------------------------------------------------- + D3D11_TEXTURE2D_DESC texElementDesc; + GFXFormat format; + bool found = false; + for (U32 idx = 0; idx < mArraySize; ++idx) + { + GFXTexHandle texObj = textureArray[idx]; + if (texObj.isValid()) + { + if (!found) + { + dynamic_cast(texObj.getPointer())->get2DTex()->GetDesc(&texElementDesc); + found = true; + format = texObj.getFormat(); + } + + if (format != texObj.getFormat() || texElementDesc.Width != texObj.getWidth() || texElementDesc.Height != texObj.getHeight()) + { + AssertWarn(true, "GFXGLTextureArray::fromTextureArray there was a mismatch in texture formats, defaulting to uncompressed format"); + Con::warnf("GFXGLTextureArray::fromTextureArray there was a mismatch in texture formats, defaulting to uncompressed format"); + success = false; + format = GFXFormatR8G8B8A8; + } + } + } + + // One might think this should return false in this case, but the return value is mostly to highlight internal errors not input errors. + if (!found) return true; + + for (U32 idx = 0; idx < mArraySize; ++idx) + { + texture2Ds[idx] = NULL; + + if(textureArray[idx].isValid()) + { + GFXTexHandle handle = textureArray[idx]; + if (textureArray[idx]->getPath().isNotEmpty()) + { + D3D11_TEXTURE2D_DESC desc; + ID3D11Texture2D* tex = dynamic_cast(textureArray[idx].getPointer())->get2DTex(); + tex->GetDesc(&desc); + if (desc.Height != texElementDesc.Height || desc.Width != texElementDesc.Width || textureArray[idx].getFormat() != format) + { + if (desc.Height != texElementDesc.Height || desc.Width != texElementDesc.Width) + { + AssertWarn(true, "GFXD3D11TextureArray::fromTextureArray all textures should be the same size"); + Con::warnf("GFXD3D11TextureArray::fromTextureArray all textures should be the same size"); + } + else + { + AssertWarn(true, "GFXD3D11TextureArray::fromTextureArray all textures should have the same format"); + Con::warnf("GFXD3D11TextureArray::fromTextureArray all textures should have the same format"); + } + + GBitmap* inBitmap = TEXMGR->loadUncompressedTexture(textureArray[idx]->getPath(), &GFXTexturePersistentProfile, texElementDesc.Width, texElementDesc.Height); + if (!inBitmap->setFormat(format)) + { + AssertWarn(true, "GFXD3D11TextureArray::fromTextureArray all textures must be convertible to GFXFormatR8G8B8A8"); + Con::errorf("GFXD3D11TextureArray::fromTextureArray all textures must be convertible to GFXFormatR8G8B8A8"); + success = false; + handle = NULL; + delete inBitmap; + } + else + { + handle = TEXMGR->createTexture(inBitmap, "", &GFXStaticTextureProfile, true); + tmpHandles.push_back(handle); + } + } + } + if (handle.isValid()) + { + D3D11_TEXTURE2D_DESC desc; + ID3D11Texture2D* tex = dynamic_cast(handle.getPointer())->get2DTex(); + tex->GetDesc(&desc); + if (desc.Height != texElementDesc.Height || desc.Width != texElementDesc.Width || handle.getFormat() != format) + { + AssertWarn(true, "GFXD3D11TextureArray::fromTextureArray all textures must have the same size and format"); + Con::errorf("GFXD3D11TextureArray::fromTextureArray all textures must have the same size and format"); + success = false; + } + texture2Ds[idx] = dynamic_cast(handle.getPointer())->get2DTex(); + } + } + } + + D3D11_TEXTURE2D_DESC texArrayDesc; + texArrayDesc.Width = texElementDesc.Width; + texArrayDesc.Height = texElementDesc.Height; + texArrayDesc.MipLevels = texElementDesc.MipLevels; + texArrayDesc.ArraySize = mArraySize; + texArrayDesc.Format = GFXD3D11TextureFormat[format]; + texArrayDesc.SampleDesc.Count = 1; + texArrayDesc.SampleDesc.Quality = 0; + texArrayDesc.Usage = D3D11_USAGE_DEFAULT; + texArrayDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + texArrayDesc.CPUAccessFlags = 0; + texArrayDesc.MiscFlags = 0; + + HRESULT hr = D3D11DEVICE->CreateTexture2D(&texArrayDesc, NULL, &mTextureArray); + AssertFatal(SUCCEEDED(hr), "GFXD3D11TextureArray::_createTextureArray failed to create texture array!"); + //--------------------------------------------------------------------------------------- + + + //--------------------------------------------------------------------------------------- + // Copy individual texture elements into texture array. + //--------------------------------------------------------------------------------------- + // for each texture element... + for (UINT i = 0; i < mArraySize; ++i) + { + if (texture2Ds[i] == NULL) + { + continue; + } + D3D11_TEXTURE2D_DESC desc; + texture2Ds[i]->GetDesc(&desc); + // for each mipmap level... + for (UINT j = 0; j < desc.MipLevels; ++j) + { + const U32 srcSubResource = D3D11CalcSubresource(j, 0, desc.MipLevels); + const U32 dstSubResource = D3D11CalcSubresource(j, i, texArrayDesc.MipLevels); + D3D11DEVICECONTEXT->CopySubresourceRegion(mTextureArray, dstSubResource, 0, 0, 0, texture2Ds[i], srcSubResource, NULL); + } + } + + // Clean temporary textures + for (GFXTexHandle handle : tmpHandles) + { + handle.free(); + } + //--------------------------------------------------------------------------------------- + + + //--------------------------------------------------------------------------------------- + // Create a resource view to the texture array. + //--------------------------------------------------------------------------------------- + createResourceView(texArrayDesc.Format, texArrayDesc.MipLevels, texArrayDesc.BindFlags); + //--------------------------------------------------------------------------------------- + + return success; +} + +void GFXD3D11TextureArray::setToTexUnit(U32 tuNum) +{ + D3D11DEVICECONTEXT->PSSetShaderResources(tuNum, 1, &mSRView); +} + + +void GFXD3D11TextureArray::createResourceView(DXGI_FORMAT format, U32 numMipLevels, U32 usageFlags) +{ + HRESULT hr; + if (usageFlags & D3D11_BIND_SHADER_RESOURCE) + { + D3D11_SHADER_RESOURCE_VIEW_DESC desc; + + if (usageFlags & D3D11_BIND_DEPTH_STENCIL) + desc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; // reads the depth + else + desc.Format = format; + + desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + desc.Texture2DArray.MostDetailedMip = 0; + desc.Texture2DArray.MipLevels = numMipLevels; + desc.Texture2DArray.FirstArraySlice = 0; + desc.Texture2DArray.ArraySize = mArraySize; + + hr = D3D11DEVICE->CreateShaderResourceView(mTextureArray, &desc, &mSRView); + AssertFatal(SUCCEEDED(hr), "GFXD3D11TextureArray::CreateShaderResourceView failed to create view!"); + } + + if (usageFlags & D3D11_BIND_RENDER_TARGET) + { + D3D11_RENDER_TARGET_VIEW_DESC desc; + desc.Format = format; + desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + desc.Texture2DArray.MipSlice = 0; + desc.Texture2DArray.FirstArraySlice = 0; + desc.Texture2DArray.ArraySize = mArraySize; + hr = D3D11DEVICE->CreateRenderTargetView(mTextureArray, &desc, &mRTView); + AssertFatal(SUCCEEDED(hr), "GFXD3D11TextureArray::CreateRenderTargetView failed to create view!"); + } + + if (usageFlags & D3D11_BIND_DEPTH_STENCIL) + { + D3D11_DEPTH_STENCIL_VIEW_DESC desc; + desc.Format = format; + desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + desc.Texture2DArray.MipSlice = 0; + desc.Texture2DArray.FirstArraySlice = 0; + desc.Texture2DArray.ArraySize = mArraySize; + desc.Flags = 0; + hr = D3D11DEVICE->CreateDepthStencilView(mTextureArray, &desc, &mDSView); + AssertFatal(SUCCEEDED(hr), "GFXD3D11TextureArray::CreateDepthStencilView failed to create view!"); + } +} + + +void GFXD3D11TextureArray::Release() +{ + SAFE_RELEASE(mSRView) + SAFE_RELEASE(mRTView) + SAFE_RELEASE(mDSView) + SAFE_RELEASE(mTextureArray) +} + +ID3D11ShaderResourceView* GFXD3D11TextureArray::getSRView() +{ + return mSRView; +} +ID3D11RenderTargetView* GFXD3D11TextureArray::getRTView() +{ + return mRTView; +} +ID3D11DepthStencilView* GFXD3D11TextureArray::getDSView() +{ + return mDSView; +} + +ID3D11ShaderResourceView** GFXD3D11TextureArray::getSRViewPtr() +{ + return &mSRView; +} +ID3D11RenderTargetView** GFXD3D11TextureArray::getRTViewPtr() +{ + return &mRTView; +} + +ID3D11DepthStencilView** GFXD3D11TextureArray::getDSViewPtr() +{ + return &mDSView; +} + +void GFXD3D11TextureArray::zombify() +{ + // Unsupported +} + +void GFXD3D11TextureArray::resurrect() +{ + // Unsupported +} diff --git a/Engine/source/gfx/D3D11/gfxD3D11TextureArray.h b/Engine/source/gfx/D3D11/gfxD3D11TextureArray.h new file mode 100644 index 000000000..abeac3b59 --- /dev/null +++ b/Engine/source/gfx/D3D11/gfxD3D11TextureArray.h @@ -0,0 +1,51 @@ +#ifndef _GFXD3D11TEXTUREARRAY_H_ +#define _GFXD3D11TEXTUREARRAY_H_ + +#include + + +#include "gfx/gfxTextureArray.h" +#include "gfx/gfxTextureManager.h" +#include "core/util/safeRelease.h" +#include "gfxD3D11TextureManager.h" + +class GFXD3D11TextureArray : public GFXTextureArray +{ +public: + GFXD3D11TextureArray() + : mSRView( NULL ), + mRTView( NULL ), + mDSView( NULL ), + mTextureArray( NULL ) + { + } + + bool fromTextureArray(const Vector &textureArray) override; + void setToTexUnit(U32 tuNum) override; + + void createResourceView(DXGI_FORMAT format, U32 numMipLevels, U32 usageFlags); + + // GFXResource interface + void zombify() override; + void resurrect() override; + void Release() override; + + + ID3D11ShaderResourceView* getSRView(); + ID3D11RenderTargetView* getRTView(); + ID3D11DepthStencilView* getDSView(); + + ID3D11ShaderResourceView** getSRViewPtr(); + ID3D11RenderTargetView** getRTViewPtr(); + ID3D11DepthStencilView** getDSViewPtr(); + +private: + ID3D11ShaderResourceView* mSRView; // for shader resource input + ID3D11RenderTargetView* mRTView; // for render targets + ID3D11DepthStencilView* mDSView; //render target view for depth stencil + + ID3D11Texture2D* mTextureArray; +}; + + +#endif diff --git a/Engine/source/gfx/D3D11/gfxD3D11TextureObject.cpp b/Engine/source/gfx/D3D11/gfxD3D11TextureObject.cpp index ea26e0042..1a06fac5e 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11TextureObject.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11TextureObject.cpp @@ -210,8 +210,8 @@ bool GFXD3D11TextureObject::copyToBmp(GBitmap* bmp) // check format limitations // at the moment we only support RGBA for the source (other 4 byte formats should // be easy to add though) - AssertFatal(mFormat == GFXFormatR16G16B16A16F || mFormat == GFXFormatR8G8B8A8 || mFormat == GFXFormatR8G8B8A8_LINEAR_FORCE || mFormat == GFXFormatR8G8B8A8_SRGB, "copyToBmp: invalid format"); - if (mFormat != GFXFormatR16G16B16A16F && mFormat != GFXFormatR8G8B8A8 && mFormat != GFXFormatR8G8B8A8_LINEAR_FORCE && mFormat != GFXFormatR8G8B8A8_SRGB) + AssertFatal(mFormat == GFXFormatR16G16B16A16F || mFormat == GFXFormatR8G8B8A8 || mFormat == GFXFormatR8G8B8A8_LINEAR_FORCE || mFormat == GFXFormatR8G8B8A8_SRGB || mFormat == GFXFormatR8G8B8, "copyToBmp: invalid format"); + if (mFormat != GFXFormatR16G16B16A16F && mFormat != GFXFormatR8G8B8A8 && mFormat != GFXFormatR8G8B8A8_LINEAR_FORCE && mFormat != GFXFormatR8G8B8A8_SRGB && mFormat != GFXFormatR8G8B8) return false; PROFILE_START(GFXD3D11TextureObject_copyToBmp); @@ -248,6 +248,7 @@ bool GFXD3D11TextureObject::copyToBmp(GBitmap* bmp) desc.BindFlags = 0; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; desc.Usage = D3D11_USAGE_STAGING; + desc.MiscFlags = 0; ID3D11Texture2D* pStagingTexture = NULL; HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, NULL, &pStagingTexture); diff --git a/Engine/source/gfx/Null/gfxNullDevice.cpp b/Engine/source/gfx/Null/gfxNullDevice.cpp index 8767d4eee..98c61ecae 100644 --- a/Engine/source/gfx/Null/gfxNullDevice.cpp +++ b/Engine/source/gfx/Null/gfxNullDevice.cpp @@ -178,6 +178,16 @@ public: virtual void resurrect() {} }; +class GFXNullTextureArray : public GFXTextureArray +{ +public: + void zombify() override {} + void resurrect() override {} + void Release() override {} + bool fromTextureArray(const Vector &textureArray) override { return true; } + virtual void setToTexUnit(U32 tuNum) { } +}; + class GFXNullVertexBuffer : public GFXVertexBuffer { unsigned char* tempBuf; @@ -317,6 +327,11 @@ GFXCubemapArray* GFXNullDevice::createCubemapArray() return new GFXNullCubemapArray(); }; +GFXTextureArray* GFXNullDevice::createTextureArray() +{ + return new GFXNullTextureArray(); +}; + 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 a2ebe6c23..e50c3583b 100644 --- a/Engine/source/gfx/Null/gfxNullDevice.h +++ b/Engine/source/gfx/Null/gfxNullDevice.h @@ -130,6 +130,7 @@ protected: public: virtual GFXCubemap * createCubemap(); virtual GFXCubemapArray *createCubemapArray(); + virtual GFXTextureArray *createTextureArray(); virtual F32 getFillConventionOffset() const { return 0.0f; }; diff --git a/Engine/source/gfx/bitmap/gBitmap.cpp b/Engine/source/gfx/bitmap/gBitmap.cpp index 380070346..d9a0d162c 100644 --- a/Engine/source/gfx/bitmap/gBitmap.cpp +++ b/Engine/source/gfx/bitmap/gBitmap.cpp @@ -727,7 +727,7 @@ bool GBitmap::checkForTransparency() } //------------------------------------------------------------------------------ -LinearColorF GBitmap::sampleTexel(F32 u, F32 v) const +LinearColorF GBitmap::sampleTexel(F32 u, F32 v, bool retAlpha) const { LinearColorF col(0.5f, 0.5f, 0.5f); // normally sampling wraps all the way around at 1.0, @@ -751,6 +751,13 @@ LinearColorF GBitmap::sampleTexel(F32 u, F32 v) const col.red = F32(buffer[lexelindex + 0]) / 255.0f; col.green = F32(buffer[lexelindex + 1]) / 255.0f; col.blue = F32(buffer[lexelindex + 2]) / 255.0f; + if (retAlpha) + { + if (getHasTransparency()) + col.alpha = F32(buffer[lexelindex + 3]) / 255.0f; + else + col.alpha = 1.0f; + } } return col; @@ -1352,7 +1359,7 @@ U32 GBitmap::getSurfaceSize(const U32 mipLevel) const } DefineEngineFunction( getBitmapInfo, String, ( const char *filename ),, - "Returns image info in the following format: width TAB height TAB bytesPerPixel. " + "Returns image info in the following format: width TAB height TAB bytesPerPixel TAB format. " "It will return an empty string if the file is not found.\n" "@ingroup Rendering\n" ) { @@ -1360,7 +1367,8 @@ DefineEngineFunction( getBitmapInfo, String, ( const char *filename ),, if ( !image ) return String::EmptyString; - return String::ToString( "%d\t%d\t%d", image->getWidth(), + return String::ToString( "%d\t%d\t%d\t%d", image->getWidth(), image->getHeight(), - image->getBytesPerPixel() ); + image->getBytesPerPixel(), + image->getFormat()); } diff --git a/Engine/source/gfx/bitmap/gBitmap.h b/Engine/source/gfx/bitmap/gBitmap.h index 16cb24985..00960c047 100644 --- a/Engine/source/gfx/bitmap/gBitmap.h +++ b/Engine/source/gfx/bitmap/gBitmap.h @@ -205,7 +205,7 @@ public: /// the bitmap bits and to check for alpha values less than 255 bool checkForTransparency(); - LinearColorF sampleTexel(F32 u, F32 v) const; + LinearColorF sampleTexel(F32 u, F32 v, bool retAlpha = false) const; bool getColor(const U32 x, const U32 y, ColorI& rColor) const; bool setColor(const U32 x, const U32 y, const ColorI& rColor); U8 getChanelValueAt(U32 x, U32 y, U32 chan); diff --git a/Engine/source/gfx/gfxDevice.cpp b/Engine/source/gfx/gfxDevice.cpp index 19f3efb0a..5dfc4dab2 100644 --- a/Engine/source/gfx/gfxDevice.cpp +++ b/Engine/source/gfx/gfxDevice.cpp @@ -132,6 +132,8 @@ GFXDevice::GFXDevice() mCurrentCubemap[i] = NULL; mNewCubemap[i] = NULL; mCurrentCubemapArray[i] = NULL; + mNewTextureArray[i] = NULL; + mCurrentTextureArray[i] = NULL; mNewCubemapArray[i] = NULL; mTexType[i] = GFXTDT_Normal; @@ -266,6 +268,8 @@ GFXDevice::~GFXDevice() mNewCubemap[i] = NULL; mCurrentCubemapArray[i] = NULL; mNewCubemapArray[i] = NULL; + mCurrentTextureArray[i] = NULL; + mNewTextureArray[i] = NULL; } mCurrentRT = NULL; @@ -403,14 +407,23 @@ void GFXDevice::updateStates(bool forceSetAll /*=false*/) } break; case GFXTDT_CubeArray: - { - mCurrentCubemapArray[i] = mNewCubemapArray[i]; - if (mCurrentCubemapArray[i]) - mCurrentCubemapArray[i]->setToTexUnit(i); - else - setTextureInternal(i, NULL); - } - break; + { + mCurrentCubemapArray[i] = mNewCubemapArray[i]; + if (mCurrentCubemapArray[i]) + mCurrentCubemapArray[i]->setToTexUnit(i); + else + setTextureInternal(i, NULL); + } + break; + case GFXTDT_TextureArray: + { + mCurrentTextureArray[i] = mNewTextureArray[i]; + if (mCurrentTextureArray[i]) + mCurrentTextureArray[i]->setToTexUnit(i); + else + setTextureInternal(i, NULL); + } + break; default: AssertFatal(false, "Unknown texture type!"); break; @@ -557,6 +570,15 @@ void GFXDevice::updateStates(bool forceSetAll /*=false*/) mCurrentCubemapArray[i]->setToTexUnit(i); else setTextureInternal(i, NULL); + } + break; + case GFXTDT_TextureArray: + { + mCurrentTextureArray[i] = mNewTextureArray[i]; + if (mCurrentTextureArray[i]) + mCurrentTextureArray[i]->setToTexUnit(i); + else + setTextureInternal(i, NULL); } break; default: @@ -801,6 +823,8 @@ void GFXDevice::setTexture( U32 stage, GFXTextureObject *texture ) mCurrentCubemap[stage] = NULL; mNewCubemapArray[stage] = NULL; mCurrentCubemapArray[stage] = NULL; + mNewTextureArray[stage] = NULL; + mCurrentTextureArray[stage] = NULL; } //----------------------------------------------------------------------------- @@ -827,6 +851,8 @@ void GFXDevice::setCubeTexture( U32 stage, GFXCubemap *cubemap ) mCurrentTexture[stage] = NULL; mNewCubemapArray[stage] = NULL; mCurrentCubemapArray[stage] = NULL; + mNewTextureArray[stage] = NULL; + mCurrentTextureArray[stage] = NULL; } //----------------------------------------------------------------------------- @@ -853,6 +879,36 @@ void GFXDevice::setCubeArrayTexture(U32 stage, GFXCubemapArray *cubemapArray) mCurrentTexture[stage] = NULL; mNewCubemap[stage] = NULL; mCurrentCubemap[stage] = NULL; + mNewTextureArray[stage] = NULL; + mCurrentTextureArray[stage] = NULL; +} + +//----------------------------------------------------------------------------- +// Set texture array +//----------------------------------------------------------------------------- +void GFXDevice::setTextureArray(U32 stage, GFXTextureArray *textureArray) +{ + AssertFatal(stage < getNumSamplers(), avar("GFXDevice::setTextureArray - out of range stage! %i>%i", stage, getNumSamplers())); + + if (mTexType[stage] == GFXTDT_TextureArray && + ((mTextureDirty[stage] && mNewTextureArray[stage].getPointer() == textureArray) || + (!mTextureDirty[stage] && mCurrentTextureArray[stage].getPointer() == textureArray))) + return; + + mStateDirty = true; + mTexturesDirty = true; + mTextureDirty[stage] = true; + + mNewTextureArray[stage] = textureArray; + mTexType[stage] = GFXTDT_TextureArray; + + // Clear out textures + mNewTexture[stage] = NULL; + mCurrentTexture[stage] = NULL; + mNewCubemap[stage] = NULL; + mCurrentCubemap[stage] = NULL; + mNewCubemapArray[stage] = NULL; + mCurrentCubemapArray[stage] = NULL; } //------------------------------------------------------------------------------ diff --git a/Engine/source/gfx/gfxDevice.h b/Engine/source/gfx/gfxDevice.h index 7b80aef3d..4caecd55b 100644 --- a/Engine/source/gfx/gfxDevice.h +++ b/Engine/source/gfx/gfxDevice.h @@ -57,6 +57,7 @@ #ifndef _PLATFORM_PLATFORMTIMER_H_ #include "platform/platformTimer.h" #endif +#include "gfxTextureArray.h" class FontRenderBatcher; class GFont; @@ -498,7 +499,8 @@ protected: { GFXTDT_Normal, GFXTDT_Cube, - GFXTDT_CubeArray + GFXTDT_CubeArray, + GFXTDT_TextureArray }; GFXTexHandle mCurrentTexture[TEXTURE_STAGE_COUNT]; @@ -507,6 +509,8 @@ protected: GFXCubemapHandle mNewCubemap[TEXTURE_STAGE_COUNT]; GFXCubemapArrayHandle mCurrentCubemapArray[TEXTURE_STAGE_COUNT]; GFXCubemapArrayHandle mNewCubemapArray[TEXTURE_STAGE_COUNT]; + GFXTextureArrayHandle mCurrentTextureArray[TEXTURE_STAGE_COUNT]; + GFXTextureArrayHandle mNewTextureArray[TEXTURE_STAGE_COUNT]; TexDirtyType mTexType[TEXTURE_STAGE_COUNT]; bool mTextureDirty[TEXTURE_STAGE_COUNT]; @@ -757,6 +761,7 @@ protected: public: virtual GFXCubemap * createCubemap() = 0; virtual GFXCubemapArray *createCubemapArray() = 0; + virtual GFXTextureArray *createTextureArray() = 0; inline GFXTextureManager *getTextureManager() { @@ -952,6 +957,7 @@ public: void setTexture(U32 stage, GFXTextureObject *texture); void setCubeTexture( U32 stage, GFXCubemap *cubemap ); void setCubeArrayTexture( U32 stage, GFXCubemapArray *cubemapArray); + void setTextureArray( U32 stage, GFXTextureArray *textureArray); inline GFXTextureObject* getCurrentTexture( U32 stage ) { return mCurrentTexture[stage]; } /// @} diff --git a/Engine/source/gfx/gfxEnums.h b/Engine/source/gfx/gfxEnums.h index f5c233990..748afacd4 100644 --- a/Engine/source/gfx/gfxEnums.h +++ b/Engine/source/gfx/gfxEnums.h @@ -599,7 +599,8 @@ enum GFXShaderConstType // Samplers GFXSCT_Sampler, GFXSCT_SamplerCube, - GFXSCT_SamplerCubeArray + GFXSCT_SamplerCubeArray, + GFXSCT_SamplerTextureArray }; diff --git a/Engine/source/gfx/gfxTextureArray.cpp b/Engine/source/gfx/gfxTextureArray.cpp new file mode 100644 index 000000000..e1458e908 --- /dev/null +++ b/Engine/source/gfx/gfxTextureArray.cpp @@ -0,0 +1,7 @@ +#include "gfxTextureArray.h" + +const String GFXTextureArray::describeSelf() const +{ + // We've got nothing + return String(); +} diff --git a/Engine/source/gfx/gfxTextureArray.h b/Engine/source/gfx/gfxTextureArray.h new file mode 100644 index 000000000..72c95995b --- /dev/null +++ b/Engine/source/gfx/gfxTextureArray.h @@ -0,0 +1,72 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _GFXTEXTUREARRAY_H_ +#define _GFXTEXTUREARRAY_H_ + +#ifndef _REFBASE_H_ +#include "core/util/refBase.h" +#endif +#ifndef _GFXRESOURCE_H_ +#include "gfx/gfxResource.h" +#endif +#ifndef _GFXENUMS_H_ +#include "gfxEnums.h" +#endif +#ifndef _GFXTEXTUREHANDLE_H_ +#include "gfxTextureHandle.h" +#endif + + +class GFXTextureProfile; +class GFXTextureObject; + +class GFXTextureArray : public StrongRefBase, public GFXResource +{ +public: + virtual bool fromTextureArray(const Vector &textureArray) = 0; + virtual void setToTexUnit(U32 tuNum) = 0; + + + // GFXResource interface + virtual void zombify() = 0; + virtual void resurrect() = 0; + virtual void Release() = 0; + + virtual const String describeSelf() const; + + U32 mArraySize; +}; + + +/// A reference counted handle to a texture array resource. +class GFXTextureArrayHandle : public StrongRefPtr +{ +public: + GFXTextureArrayHandle() {} + GFXTextureArrayHandle(GFXTextureArray* textureArray) { StrongRefPtr::set(textureArray); } + + /// Releases the texture handle. + void free() { StrongObjectRef::set(NULL); } +}; + +#endif // _GFXTEXTUREARRAY_H_ diff --git a/Engine/source/gfx/gfxTextureManager.cpp b/Engine/source/gfx/gfxTextureManager.cpp index 6bd027028..53c252d07 100644 --- a/Engine/source/gfx/gfxTextureManager.cpp +++ b/Engine/source/gfx/gfxTextureManager.cpp @@ -894,6 +894,42 @@ Torque::Path GFXTextureManager::validatePath(const Torque::Path &path) return correctPath; } +GBitmap *GFXTextureManager::loadUncompressedTexture(const Torque::Path &path, GFXTextureProfile *profile, U32 width, U32 height) +{ + GBitmap* inBitmap = loadUncompressedTexture(path, &GFXTexturePersistentProfile); + + if (inBitmap == NULL) + { + Con::warnf("GFXTextureManager::loadUncompressedTexture unable to load texture: %s", path.getFullPath()); + return NULL; + } + + // Set the format so we don't have to handle which channels are where. + if (!inBitmap->setFormat(GFXFormatR8G8B8A8)) + { + Con::warnf("GFXTextureManager::loadUncompressedTexture unable to handle texture format: %s", path.getFullPath()); + return NULL; + } + + GBitmap* outBmp = new GBitmap(width, height, true, GFXFormatR8G8B8A8); + + U8* oBits = (U8*)outBmp->getWritableBits(); + for (S32 y = 0; y < width; y++) + { + for (S32 x = 0; x < height; x++) + { + ColorI texelColor = inBitmap->sampleTexel(x / F32(width), y / F32(height), true).toColorI(true); + + oBits[(y * width + x) * 4] = texelColor.red; + oBits[(y * width + x) * 4 + 1] = texelColor.green; + oBits[(y * width + x) * 4 + 2] = texelColor.blue; + oBits[(y * width + x) * 4 + 3] = texelColor.alpha; + } + } + + return outBmp; +} + GBitmap *GFXTextureManager::loadUncompressedTexture(const Torque::Path &path, GFXTextureProfile *profile) { PROFILE_SCOPE(GFXTextureManager_loadUncompressedTexture); diff --git a/Engine/source/gfx/gfxTextureManager.h b/Engine/source/gfx/gfxTextureManager.h index be1640351..b6eb658f2 100644 --- a/Engine/source/gfx/gfxTextureManager.h +++ b/Engine/source/gfx/gfxTextureManager.h @@ -41,6 +41,7 @@ #ifndef _TSIGNAL_H_ #include "core/util/tSignal.h" #endif +#include "gfxTextureHandle.h" namespace Torque @@ -131,6 +132,7 @@ public: S32 antialiasLevel); Torque::Path validatePath(const Torque::Path &path); + GBitmap *loadUncompressedTexture(const Torque::Path& path, GFXTextureProfile* profile, U32 width, U32 height); GBitmap *loadUncompressedTexture(const Torque::Path &path, GFXTextureProfile *profile); virtual GFXTextureObject *createCompositeTexture(const Torque::Path &pathR, const Torque::Path &pathG, const Torque::Path &pathB, const Torque::Path &pathA, U32 inputKey[4], GFXTextureProfile *profile); diff --git a/Engine/source/gfx/gl/gfxGLDevice.cpp b/Engine/source/gfx/gl/gfxGLDevice.cpp index c90080b3f..d0e9db09f 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.cpp +++ b/Engine/source/gfx/gl/gfxGLDevice.cpp @@ -22,6 +22,8 @@ #include "platform/platform.h" #include "gfx/gl/gfxGLDevice.h" + +#include "gfxGLTextureArray.h" #include "platform/platformGL.h" #include "gfx/gfxCubemap.h" @@ -457,6 +459,13 @@ GFXCubemapArray *GFXGLDevice::createCubemapArray() return cubeArray; } +GFXTextureArray* GFXGLDevice::createTextureArray() +{ + GFXGLTextureArray* textureArray = new GFXGLTextureArray(); + textureArray->registerResourceWithDevice(this); + return textureArray; +} + void GFXGLDevice::endSceneInternal() { // nothing to do for opengl @@ -766,6 +775,22 @@ void GFXGLDevice::setCubemapArrayInternal(U32 textureUnit, const GFXGLCubemapArr } } +void GFXGLDevice::setTextureArrayInternal(U32 textureUnit, const GFXGLTextureArray* texture) +{ + if (texture) + { + mActiveTextureType[textureUnit] = GL_TEXTURE_2D_ARRAY; + texture->bind(textureUnit); + } + else if (mActiveTextureType[textureUnit] != GL_ZERO) + { + glActiveTexture(GL_TEXTURE0 + textureUnit); + glBindTexture(mActiveTextureType[textureUnit], 0); + getOpenglCache()->setCacheBindedTex(textureUnit, mActiveTextureType[textureUnit], 0); + mActiveTextureType[textureUnit] = GL_ZERO; + } +} + void GFXGLDevice::setMatrix( GFXMatrixType mtype, const MatrixF &mat ) { // ONLY NEEDED ON FFP diff --git a/Engine/source/gfx/gl/gfxGLDevice.h b/Engine/source/gfx/gl/gfxGLDevice.h index 3e127367e..0282a103f 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.h +++ b/Engine/source/gfx/gl/gfxGLDevice.h @@ -35,6 +35,7 @@ #include "gfx/gfxResource.h" #include "gfx/gl/gfxGLStateBlock.h" +class GFXGLTextureArray; class GFXGLVertexBuffer; class GFXGLPrimitiveBuffer; class GFXGLTextureTarget; @@ -83,6 +84,7 @@ public: virtual GFXCubemap * createCubemap(); virtual GFXCubemapArray *createCubemapArray(); + virtual GFXTextureArray *createTextureArray(); virtual F32 getFillConventionOffset() const { return 0.0f; } @@ -173,6 +175,7 @@ protected: virtual void setTextureInternal(U32 textureUnit, const GFXTextureObject*texture); virtual void setCubemapInternal(U32 textureUnit, const GFXGLCubemap* texture); virtual void setCubemapArrayInternal(U32 textureUnit, const GFXGLCubemapArray* texture); + virtual void setTextureArrayInternal(U32 textureUnit, const GFXGLTextureArray* texture); virtual void setLightInternal(U32 lightStage, const GFXLightInfo light, bool lightEnable); virtual void setLightMaterialInternal(const GFXLightMaterial mat); @@ -210,6 +213,7 @@ private: friend class GFXGLTextureObject; friend class GFXGLCubemap; friend class GFXGLCubemapArray; + friend class GFXGLTextureArray; friend class GFXGLWindowTarget; friend class GFXGLPrimitiveBuffer; friend class GFXGLVertexBuffer; diff --git a/Engine/source/gfx/gl/gfxGLShader.cpp b/Engine/source/gfx/gl/gfxGLShader.cpp index 5d9d4d380..a92d4bc54 100644 --- a/Engine/source/gfx/gl/gfxGLShader.cpp +++ b/Engine/source/gfx/gl/gfxGLShader.cpp @@ -82,6 +82,7 @@ static U32 shaderConstTypeSize(GFXShaderConstType type) case GFXSCT_Sampler: case GFXSCT_SamplerCube: case GFXSCT_SamplerCubeArray: + case GFXSCT_SamplerTextureArray: return 4; case GFXSCT_Float2: case GFXSCT_Int2: @@ -630,6 +631,9 @@ void GFXGLShader::initConstantDescs() case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: desc.constType = GFXSCT_SamplerCubeArray; break; + case GL_SAMPLER_2D_ARRAY: + desc.constType = GFXSCT_SamplerTextureArray; + break; default: AssertFatal(false, "GFXGLShader::initConstantDescs - unrecognized uniform type"); // If we don't recognize the constant don't add its description. @@ -661,7 +665,10 @@ void GFXGLShader::initHandles() HandleMap::Iterator handle = mHandles.find(desc.name); S32 sampler = -1; - if(desc.constType == GFXSCT_Sampler || desc.constType == GFXSCT_SamplerCube || desc.constType == GFXSCT_SamplerCubeArray) + if(desc.constType == GFXSCT_Sampler || + desc.constType == GFXSCT_SamplerCube || + desc.constType == GFXSCT_SamplerCubeArray || + desc.constType == GFXSCT_SamplerTextureArray) { S32 idx = mSamplerNamesOrdered.find_next(desc.name); AssertFatal(idx != -1, ""); @@ -704,7 +711,11 @@ void GFXGLShader::initHandles() for (HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter) { GFXGLShaderConstHandle* handle = iter->value; - if(handle->isValid() && (handle->getType() == GFXSCT_Sampler || handle->getType() == GFXSCT_SamplerCube || handle->getType() == GFXSCT_SamplerCubeArray)) + if(handle->isValid() && + (handle->getType() == GFXSCT_Sampler || + handle->getType() == GFXSCT_SamplerCube || + handle->getType() == GFXSCT_SamplerCubeArray || + handle->getType() == GFXSCT_SamplerTextureArray)) { // Set sampler number on our program. glUniform1i(handle->mLocation, handle->mSamplerNum); @@ -837,6 +848,7 @@ void GFXGLShader::setConstantsFromBuffer(GFXGLShaderConstBuffer* buffer) case GFXSCT_Sampler: case GFXSCT_SamplerCube: case GFXSCT_SamplerCubeArray: + case GFXSCT_SamplerTextureArray: glUniform1iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); break; case GFXSCT_Int2: diff --git a/Engine/source/gfx/gl/gfxGLStateCache.h b/Engine/source/gfx/gl/gfxGLStateCache.h index 24b3179e4..c35a2423f 100644 --- a/Engine/source/gfx/gl/gfxGLStateCache.h +++ b/Engine/source/gfx/gl/gfxGLStateCache.h @@ -20,11 +20,11 @@ public: class TextureUnit { public: - TextureUnit() : mTexture1D(0), mTexture2D(0), mTexture3D(0), mTextureCube(0), mTextureCubeArray(0) + TextureUnit() : mTexture1D(0), mTexture2D(0), mTexture3D(0), mTextureCube(0), mTextureCubeArray(0), mTextureArray(0) { } - GLuint mTexture1D, mTexture2D, mTexture3D, mTextureCube, mTextureCubeArray; + GLuint mTexture1D, mTexture2D, mTexture3D, mTextureCube, mTextureCubeArray, mTextureArray; }; /// after glBindTexture @@ -48,6 +48,9 @@ public: case GL_TEXTURE_CUBE_MAP_ARRAY: mTextureUnits[mActiveTexture].mTextureCubeArray = handle; break; + case GL_TEXTURE_2D_ARRAY: + mTextureUnits[mActiveTexture].mTextureArray = handle; + break; default: AssertFatal(0, avar("GFXGLStateCache::setCacheBindedTex - binding (%x) not supported.", biding) ); return; @@ -74,6 +77,9 @@ public: case GL_TEXTURE_CUBE_MAP_ARRAY: mTextureUnits[mActiveTexture].mTextureCubeArray = handle; break; + case GL_TEXTURE_2D_ARRAY: + mTextureUnits[mActiveTexture].mTextureArray = handle; + break; case GL_FRAMEBUFFER: mBindedFBO_W = mBindedFBO_R = handle; break; @@ -109,6 +115,8 @@ public: return mTextureUnits[mActiveTexture].mTextureCube; case GL_TEXTURE_CUBE_MAP_ARRAY: return mTextureUnits[mActiveTexture].mTextureCubeArray; + case GL_TEXTURE_2D_ARRAY: + return mTextureUnits[mActiveTexture].mTextureArray; case GL_DRAW_FRAMEBUFFER: return mBindedFBO_W; case GL_READ_FRAMEBUFFER: @@ -138,4 +146,4 @@ protected: }; -#endif \ No newline at end of file +#endif diff --git a/Engine/source/gfx/gl/gfxGLTextureArray.cpp b/Engine/source/gfx/gl/gfxGLTextureArray.cpp new file mode 100644 index 000000000..72d9a6875 --- /dev/null +++ b/Engine/source/gfx/gl/gfxGLTextureArray.cpp @@ -0,0 +1,215 @@ +#include "gfxGLTextureArray.h" + +#include "gfxGLTextureObject.h" +#include "gfxGLUtils.h" +#include "core/util/tVector.h" +#include "gfx/bitmap/imageUtils.h" + + +GFXGLTextureArray::GFXGLTextureArray() +{ + mTextureArray = NULL; +} + +GFXGLTextureArray::~GFXGLTextureArray() +{ + glDeleteTextures(1, &mTextureArray); +} + +bool GFXGLTextureArray::fromTextureArray(const Vector &textureArray) +{ + bool success = true; + + if (textureArray.empty()) + { + return true; + } + + bool found = false; + U32 baseWidth = 0, baseHeight = 0; + bool isCompressed = false; + mArraySize = textureArray.size(); + + for (GFXTexHandle texObj : textureArray) + { + if (texObj.isValid()) + { + if (!found) + { + baseWidth = texObj.getWidth(); + baseHeight = texObj.getHeight(); + mMipMapLevels = getMax((U32)1, texObj->mMipLevels); + found = true; + mFormat = texObj.getFormat(); + isCompressed = ImageUtil::isCompressedFormat(mFormat); + } + + if (mFormat != texObj.getFormat() || baseWidth != texObj.getWidth() || baseHeight != texObj.getHeight()) + { + AssertWarn(true, "GFXGLTextureArray::fromTextureArray there was a mismatch in texture format, defaulting to uncompressed format"); + Con::warnf("GFXGLTextureArray::fromTextureArray there was a mismatch in texture format, defaulting to uncompressed format"); + success = false; + mFormat = GFXFormatR8G8B8A8; + isCompressed = false; + } + } + } + + // One might think this should return false in this case, but the return value is mostly to highlight internal errors not input errors. + if (!found) return true; + + Vector texture2Ds; + texture2Ds.setSize(textureArray.size()); + Vector tmpHandles; + + for (U32 idx = 0; idx < mArraySize; ++idx) + { + texture2Ds[idx] = NULL; + GFXTexHandle texObj = textureArray[idx]; + + if (texObj.isValid()) + { + GFXTexHandle handle = textureArray[idx]; + if (texObj->getPath().isNotEmpty()) + { + if (texObj.getHeight() != baseHeight|| texObj.getWidth() != baseWidth || texObj.getFormat() != mFormat) + { + if (texObj.getHeight() != baseHeight || texObj.getWidth() != baseWidth) + { + AssertWarn(true, "GFXGLTextureArray::fromTextureArray all textures should be the same size"); + Con::warnf("GFXGLTextureArray::fromTextureArray all textures should be the same size"); + } + else + { + AssertWarn(true, "GFXGLTextureArray::fromTextureArray all textures should have the same format"); + Con::warnf("GFXGLTextureArray::fromTextureArray all textures should have the same format"); + } + + GBitmap* inBitmap = TEXMGR->loadUncompressedTexture(textureArray[idx]->getPath(), &GFXTexturePersistentProfile, baseWidth, baseHeight); + if (!inBitmap->setFormat(mFormat)) + { + AssertWarn(true, "GFXGLTextureArray::fromTextureArray all textures must be convertible to GFXFormatR8G8B8A8"); + Con::errorf("GFXGLTextureArray::fromTextureArray all textures must be convertible to GFXFormatR8G8B8A8"); + success = false; + handle = NULL; + delete inBitmap; + } + else + { + handle = TEXMGR->createTexture(inBitmap, "", &GFXStaticTextureProfile, true); + tmpHandles.push_back(handle); + } + } + } + if (handle.isValid()) + { + if (handle.getHeight() != baseHeight || handle.getWidth()!= baseWidth || handle.getFormat() != mFormat) + { + AssertWarn(true, "GFXGLTextureArray::fromTextureArray all textures must have the same size and format"); + Con::errorf("GFXGLTextureArray::fromTextureArray all textures must have the same size and format"); + success = false; + } + texture2Ds[idx] = dynamic_cast(handle.getPointer()); + tmpHandles.push_back(handle); + } + } + } + + glGenTextures(1, &mTextureArray); + PRESERVE_2D_TEXTURE_ARRAY(); + glBindTexture(GL_TEXTURE_2D_ARRAY, mTextureArray); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, mMin(mMipMapLevels - 1, 1)); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glTexStorage3D(GL_TEXTURE_2D_ARRAY, mMipMapLevels, GL_RGBA8, baseWidth, baseHeight, textureArray.size()); + + for (U32 idx = 0; idx < texture2Ds.size(); ++idx) + { + if (texture2Ds[idx] == NULL) + { + continue; + } + GFXGLTextureObject* texObj = texture2Ds[idx]; + for (U32 mip = 0; mip < mMipMapLevels; ++mip) + { + U8* buf = texObj->getTextureData(mip); + const U32 mipWidth = getMax(U32(1), baseWidth >> mip); + const U32 mipHeight = getMax(U32(1), baseHeight >> mip); + glBindTexture(GL_TEXTURE_2D_ARRAY, mTextureArray); + if (isCompressed) + { + glCompressedTexSubImage3D( + GL_TEXTURE_2D_ARRAY, + mip, 0, 0, + idx, mipWidth, mipHeight, 1, + GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buf + ); + } + else + { + glTexSubImage3D( + GL_TEXTURE_2D_ARRAY, + mip, 0, 0, + idx, mipWidth, mipHeight, 1, + GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buf + ); + } + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); + delete[] buf; + } + } + + if (!isCompressed) + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); + + // Clean temporary textures + for (GFXTexHandle handle : tmpHandles) + { + handle.free(); + } + + return success; +} + +void GFXGLTextureArray::setToTexUnit(U32 tuNum) +{ + dynamic_cast(getOwningDevice())->setTextureArrayInternal(tuNum, this); +} + + +void GFXGLTextureArray::Release() +{ + glDeleteTextures(1, &mTextureArray); + mTextureArray = 0; +} + + +void GFXGLTextureArray::bind(U32 textureUnit) const +{ + glActiveTexture(GL_TEXTURE0 + textureUnit); + glBindTexture(GL_TEXTURE_2D_ARRAY, mTextureArray); + dynamic_cast(getOwningDevice())->getOpenglCache()->setCacheBindedTex(textureUnit, GL_TEXTURE_2D_ARRAY, mTextureArray); + + GFXGLStateBlockRef sb = static_cast(GFX)->getCurrentStateBlock(); + AssertFatal(sb, "GFXGLTextureArray::bind - No active stateblock!"); + if (!sb) + return; + + const GFXSamplerStateDesc& ssd = sb->getDesc().samplers[textureUnit]; + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, minificationFilter(ssd.minFilter, ssd.mipFilter, 0)); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GFXGLTextureFilter[ssd.magFilter]); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, mMin(mMipMapLevels - 1, 1)); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GFXGLTextureAddress[ssd.addressModeU]); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GFXGLTextureAddress[ssd.addressModeV]); +} + +void GFXGLTextureArray::zombify() +{ +} + +void GFXGLTextureArray::resurrect() +{ +} diff --git a/Engine/source/gfx/gl/gfxGLTextureArray.h b/Engine/source/gfx/gl/gfxGLTextureArray.h new file mode 100644 index 000000000..7730f1257 --- /dev/null +++ b/Engine/source/gfx/gl/gfxGLTextureArray.h @@ -0,0 +1,34 @@ +#ifndef _GFXGLTEXTUREARRAY_H_ +#define _GFXGLTEXTUREARRAY_H_ + +#include + +#include "gfx/gfxTextureArray.h" +#include "gfx/gfxTextureManager.h" + +class GFXGLTextureArray : public GFXTextureArray +{ +public: + GFXGLTextureArray(); + + ~GFXGLTextureArray(); + + bool fromTextureArray(const Vector& textureArray) override; + void setToTexUnit(U32 tuNum) override; + + void bind(U32 textureUnit) const; + + // GFXResource interface + void zombify() override; + void resurrect() override; + void Release() override; + +private: + GLuint mTextureArray; + + U32 mMipMapLevels; + GFXFormat mFormat; +}; + + +#endif diff --git a/Engine/source/gfx/gl/gfxGLUtils.h b/Engine/source/gfx/gl/gfxGLUtils.h index 34eabcbd8..e8ab45be8 100644 --- a/Engine/source/gfx/gl/gfxGLUtils.h +++ b/Engine/source/gfx/gl/gfxGLUtils.h @@ -194,6 +194,9 @@ GFXGLPreserveTexture TORQUE_CONCAT(preserve_, __LINE__) (GL_TEXTURE_CUBE_MAP, GL #define PRESERVE_CUBEMAP_ARRAY_TEXTURE() \ GFXGLPreserveTexture TORQUE_CONCAT(preserve_, __LINE__) (GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_BINDING_CUBE_MAP_ARRAY, (GFXGLPreserveInteger::BindFn)glBindTexture) +#define PRESERVE_2D_TEXTURE_ARRAY() \ +GFXGLPreserveTexture TORQUE_CONCAT(preserve_, __LINE__) (GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BINDING_2D_ARRAY, (GFXGLPreserveInteger::BindFn)glBindTexture) + #define _GET_TEXTURE_BINDING(binding) \ binding == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : (binding == GL_TEXTURE_3D ? GL_TEXTURE_BINDING_3D : GL_TEXTURE_BINDING_1D ) diff --git a/Engine/source/shaderGen/shaderOp.cpp b/Engine/source/shaderGen/shaderOp.cpp index 7df224ed9..c6597b94a 100644 --- a/Engine/source/shaderGen/shaderOp.cpp +++ b/Engine/source/shaderGen/shaderOp.cpp @@ -80,6 +80,29 @@ void EchoOp::print( Stream &stream ) WRITESTR( mStatement ); } +//************************************************************************** +// Index operation +//************************************************************************** +IndexOp::IndexOp( Var* var, U32 index ) : Parent( NULL, NULL ) +{ + mInput[0] = var; + mIndex = index; +} + +//-------------------------------------------------------------------------- +// Print +//-------------------------------------------------------------------------- +void IndexOp::print( Stream &stream ) +{ + Var* var = dynamic_cast(mInput[0]); + + mInput[0]->print(stream); + if (var->arraySize > 1) + { + WRITESTR(String::ToString("[%d]", mIndex)); + } +} + //************************************************************************** // General operation diff --git a/Engine/source/shaderGen/shaderOp.h b/Engine/source/shaderGen/shaderOp.h index 6e8170d9a..2f2cbc4bf 100644 --- a/Engine/source/shaderGen/shaderOp.h +++ b/Engine/source/shaderGen/shaderOp.h @@ -110,6 +110,21 @@ public: virtual void print( Stream &stream ); }; +//---------------------------------------------------------------------------- +/*! + Accesses the given index on the variable +*/ +//---------------------------------------------------------------------------- +class IndexOp : public ShaderOp +{ + typedef ShaderOp Parent; + U32 mIndex; + +public: + IndexOp( Var* var, U32 index ); + virtual void print( Stream &stream ); +}; + //---------------------------------------------------------------------------- /*! diff --git a/Engine/source/terrain/glsl/terrFeatureGLSL.cpp b/Engine/source/terrain/glsl/terrFeatureGLSL.cpp index 1bd06c01c..412f1810d 100644 --- a/Engine/source/terrain/glsl/terrFeatureGLSL.cpp +++ b/Engine/source/terrain/glsl/terrFeatureGLSL.cpp @@ -48,7 +48,6 @@ namespace FEATUREMGR->registerFeature( MFT_TerrainMacroMap, new NamedFeatureGLSL("TerrainMacroMap Deprecated")); // new TerrainMacroMapFeatGLSL); FEATUREMGR->registerFeature( MFT_TerrainLightMap, new TerrainLightMapFeatGLSL ); FEATUREMGR->registerFeature( MFT_TerrainSideProject, new NamedFeatureGLSL( "Terrain Side Projection" ) ); - FEATUREMGR->registerFeature( MFT_TerrainAdditive, new TerrainAdditiveFeatGLSL ); FEATUREMGR->registerFeature( MFT_TerrainORMMap, new TerrainORMMapFeatGLSL ); FEATUREMGR->registerFeature( MFT_DeferredTerrainBlankInfoMap, new TerrainBlankInfoMapFeatGLSL ); } @@ -124,69 +123,90 @@ Var* TerrainFeatGLSL::_getInMacroCoord( Vector &componentList return inDet; } -Var* TerrainFeatGLSL::_getNormalMapTex() +Var* TerrainFeatGLSL::_getDetailMapSampler() { - String name( String::ToString( "normalMap%d", getProcessIndex() ) ); - Var *normalMap = (Var*)LangElement::find( name ); - - if ( !normalMap ) + String name("detailMapSampler"); + Var* detailMapSampler = (Var*)LangElement::find(name); + + if (!detailMapSampler) { - normalMap = new Var; - normalMap->setType( "sampler2D" ); - normalMap->setName( name ); - normalMap->uniform = true; - normalMap->sampler = true; - normalMap->constNum = Var::getTexUnitNum(); + detailMapSampler = new Var; + detailMapSampler->setName(name); + detailMapSampler->setType("sampler2DArray"); + detailMapSampler->uniform = true; + detailMapSampler->sampler = true; + detailMapSampler->constNum = Var::getTexUnitNum(); } - - return normalMap; + + return detailMapSampler; } -Var* TerrainFeatGLSL::_getORMConfigMapTex() +Var* TerrainFeatGLSL::_getNormalMapSampler() { - String name(String::ToString("ormConfigMap%d", getProcessIndex())); - Var *ormConfigMap = (Var*)LangElement::find(name); + String name("normalMapSampler"); + Var* normalMapSampler = (Var*)LangElement::find(name); - if (!ormConfigMap) - { - ormConfigMap = new Var; - ormConfigMap->setType("sampler2D"); - ormConfigMap->setName(name); - ormConfigMap->uniform = true; - ormConfigMap->sampler = true; - ormConfigMap->constNum = Var::getTexUnitNum(); - } + if (!normalMapSampler) + { + normalMapSampler = new Var; + normalMapSampler->setName(name); + normalMapSampler->setType("sampler2DArray"); + normalMapSampler->uniform = true; + normalMapSampler->sampler = true; + normalMapSampler->constNum = Var::getTexUnitNum(); + } - return ormConfigMap; + return normalMapSampler; +} + +Var* TerrainFeatGLSL::_getOrmMapSampler() +{ + String name("ormMapSampler"); + Var* ormMapSampler = (Var*)LangElement::find(name); + + if (!ormMapSampler) + { + ormMapSampler = new Var; + ormMapSampler->setName(name); + ormMapSampler->setType("sampler2DArray"); + ormMapSampler->uniform = true; + ormMapSampler->sampler = true; + ormMapSampler->constNum = Var::getTexUnitNum(); + } + + return ormMapSampler; } Var* TerrainFeatGLSL::_getDetailIdStrengthParallax() { - String name( String::ToString( "detailIdStrengthParallax%d", getProcessIndex() ) ); - - Var *detailInfo = (Var*)LangElement::find( name ); - if ( !detailInfo ) + String name(String::ToString("detailIdStrengthParallax", getProcessIndex())); + + Var* detailInfo = (Var*)LangElement::find(name); + if (!detailInfo) { detailInfo = new Var; - detailInfo->setType( "vec3" ); - detailInfo->setName( name ); + detailInfo->setType("vec4"); + detailInfo->setName(name); detailInfo->uniform = true; detailInfo->constSortPos = cspPotentialPrimitive; + detailInfo->arraySize = getProcessIndex(); } - + + detailInfo->arraySize = mMax(detailInfo->arraySize, getProcessIndex() + 1); + return detailInfo; } Var* TerrainFeatGLSL::_getMacroIdStrengthParallax() { - String name( String::ToString( "macroIdStrengthParallax%d", getProcessIndex() ) ); + String name(String::ToString("macroIdStrengthParallax%d", getProcessIndex())); - Var *detailInfo = (Var*)LangElement::find( name ); - if ( !detailInfo ) + Var* detailInfo = (Var*)LangElement::find(name); + if (!detailInfo) { detailInfo = new Var; - detailInfo->setType( "vec3" ); - detailInfo->setName( name ); + detailInfo->setType("vec3"); + detailInfo->setName(name); detailInfo->uniform = true; detailInfo->constSortPos = cspPotentialPrimitive; } @@ -377,11 +397,17 @@ void TerrainDetailMapFeatGLSL::processVert( Vector &component outTex->setType( "vec4" ); // Get the detail scale and fade info. - Var *detScaleAndFade = new Var; - detScaleAndFade->setType( "vec4" ); - detScaleAndFade->setName( String::ToString( "detailScaleAndFade%d", detailIndex ) ); - detScaleAndFade->uniform = true; - detScaleAndFade->constSortPos = cspPotentialPrimitive; + Var *detScaleAndFade = (Var*)LangElement::find("detailScaleAndFade"); + if (!detScaleAndFade) + { + detScaleAndFade = new Var; + detScaleAndFade->setType("vec4"); + detScaleAndFade->setName("detailScaleAndFade"); + detScaleAndFade->uniform = true; + detScaleAndFade->constSortPos = cspPotentialPrimitive; + } + + detScaleAndFade->arraySize = mMax(detScaleAndFade->arraySize, detailIndex + 1); // Setup the detail coord. // @@ -392,11 +418,11 @@ void TerrainDetailMapFeatGLSL::processVert( Vector &component // // See TerrainBaseMapFeatGLSL::processVert(). // - meta->addStatement( new GenOp( " @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade ) ); + meta->addStatement( new GenOp( " @.xyz = @ * @.xyx;\r\n", outTex, inTex, new IndexOp(detScaleAndFade, detailIndex) ) ); // And sneak the detail fade thru the w detailCoord. meta->addStatement( new GenOp( " @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n", - outTex, detScaleAndFade, dist, detScaleAndFade ) ); + outTex, new IndexOp(detScaleAndFade, detailIndex), dist, new IndexOp(detScaleAndFade, detailIndex)) ); output = meta; } @@ -473,7 +499,7 @@ void TerrainDetailMapFeatGLSL::processPix( Vector &component // Calculate the blend for this detail texture. meta->addStatement( new GenOp( " @ = calcBlend( @.x, @.xy, @, @ );\r\n", - new DecOp( detailBlend ), detailInfo, inTex, layerSize, layerSample ) ); + new DecOp( detailBlend ), new IndexOp(detailInfo, detailIndex), inTex, layerSize, layerSample ) ); // New terrain @@ -525,15 +551,10 @@ void TerrainDetailMapFeatGLSL::processPix( Vector &component } // Get the detail texture. - Var *detailMap = new Var; - detailMap->setType("sampler2D"); - detailMap->setName(String::ToString("detailMap%d", detailIndex)); - detailMap->uniform = true; - detailMap->sampler = true; - detailMap->constNum = Var::getTexUnitNum(); // used as texture unit num here + Var *detailMap = _getDetailMapSampler(); // Get the normal map texture. - Var *normalMap = _getNormalMapTex(); + Var *normalMap = _getNormalMapSampler(); // Issue happens somewhere here ----- @@ -541,8 +562,7 @@ void TerrainDetailMapFeatGLSL::processPix( Vector &component // // We take two normal samples and lerp between them for // side projection layers... else a single sample. - LangElement *texOp; - + // // Note that we're doing the standard greyscale detail // map technique here which can darken and lighten the // diffuse texture. @@ -552,35 +572,17 @@ void TerrainDetailMapFeatGLSL::processPix( Vector &component // if (fd.features.hasFeature(MFT_TerrainSideProject, detailIndex)) { - meta->addStatement(new GenOp(" @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n", - detailColor, detailMap, inDet, detailMap, inDet, inTex)); - - texOp = new GenOp("lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z )", - normalMap, inDet, normalMap, inDet, inTex); + meta->addStatement(new GenOp(" @ = ( lerp( tex2D( @, vec3(@.yz, @.x) ), tex2D( @, vec3(@.xz, @.x) ), @.z ) * 2.0 ) - 1.0;\r\n", + detailColor, detailMap, inDet, new IndexOp(detailInfo, detailIndex), detailMap, inDet, new IndexOp(detailInfo, detailIndex), inTex)); } else { - meta->addStatement(new GenOp(" @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n", - detailColor, detailMap, inDet)); - - texOp = new GenOp("tex2D(@, @.xy)", normalMap, inDet); + meta->addStatement(new GenOp(" @ = ( tex2D( @, vec3(@.xy, @.x) ) * 2.0 ) - 1.0;\r\n", + detailColor, detailMap, inDet, new IndexOp(detailInfo, detailIndex))); } // New terrain - // Get a var and accumulate the blend amount. - Var *blendTotal = (Var*)LangElement::find( "blendTotal" ); - if ( !blendTotal ) - { - blendTotal = new Var; - blendTotal->setName( "blendTotal" ); - blendTotal->setType( "float" ); - meta->addStatement( new GenOp( " @ = 0;\r\n", new DecOp( blendTotal ) ) ); - } - - // Add to the blend total. - meta->addStatement(new GenOp(" @ = max( @, @ );\r\n", blendTotal, blendTotal, detailBlend)); - // If we had a parallax feature... then factor in the parallax // amount so that it fades out with the layer blending. if ( fd.features.hasFeature( MFT_TerrainParallaxMap, detailIndex ) ) @@ -588,13 +590,13 @@ void TerrainDetailMapFeatGLSL::processPix( Vector &component // Call the library function to do the rest. if (fd.features.hasFeature(MFT_IsBC3nm, detailIndex)) { - meta->addStatement(new GenOp(" @.xy += parallaxOffsetDxtnm( @, @.xy, @, @.z * @ );\r\n", - inDet, normalMap, inDet, negViewTS, detailInfo, detailBlend)); + meta->addStatement(new GenOp(" @.xy += parallaxOffsetDxtnm( @, vec3(@.xy, @.x), @, @.z * @ );\r\n", + inDet, normalMap, inDet, new IndexOp(detailInfo, detailIndex), negViewTS, new IndexOp(detailInfo, detailIndex), detailBlend)); } else { - meta->addStatement(new GenOp(" @.xy += parallaxOffset( @, @.xy, @, @.z * @ );\r\n", - inDet, normalMap, inDet, negViewTS, detailInfo, detailBlend)); + meta->addStatement(new GenOp(" @.xy += parallaxOffset( @, vec3(@.xy, @.x), @, @.z * @ );\r\n", + inDet, normalMap, inDet, new IndexOp(detailInfo, detailIndex), negViewTS, new IndexOp(detailInfo, detailIndex), detailBlend)); } } @@ -632,17 +634,17 @@ void TerrainDetailMapFeatGLSL::processPix( Vector &component // if ( fd.features.hasFeature( MFT_TerrainSideProject, detailIndex ) ) { - meta->addStatement( new GenOp( " @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n", - detailColor, detailMap, inDet, detailMap, inDet, inTex ) ); + meta->addStatement( new GenOp( " @ = ( lerp( tex2D( @, vec3(@.yz, @.x) ), tex2D( @, vec3(@.xz, @.x) ), @.z ) * 2.0 ) - 1.0;\r\n", + detailColor, detailMap, inDet, new IndexOp(detailInfo, detailIndex), detailMap, inDet, new IndexOp(detailInfo, detailIndex), inTex ) ); } else { - meta->addStatement( new GenOp( " @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n", - detailColor, detailMap, inDet ) ); + meta->addStatement( new GenOp( " @ = ( tex2D( @, vec3(@.xy, @.x) ) * 2.0 ) - 1.0;\r\n", + detailColor, detailMap, inDet, new IndexOp(detailInfo, detailIndex)) ); } meta->addStatement( new GenOp( " @ *= @.y * @.w;\r\n", - detailColor, detailInfo, inDet ) ); + detailColor, new IndexOp(detailInfo, detailIndex), inDet ) ); meta->addStatement(new GenOp(" @.rgb = toGamma(@.rgb);\r\n", outColor, outColor)); @@ -666,26 +668,13 @@ ShaderFeature::Resources TerrainDetailMapFeatGLSL::getResources( const MaterialF // If this is the first detail pass then we // samples from the layer tex. res.numTex += 1; + res.numTexReg += 1; - // If this material also does parallax then it - // will generate the negative view vector and the - // worldToTanget transform. - if ( fd.features.hasFeature( MFT_TerrainParallaxMap ) ) - res.numTexReg += 4; + // Texture Array + res.numTex += 1; + res.numTexReg += 1; } - // sample from the detail texture for diffuse coloring. - res.numTex += 1; - - // If we have parallax for this layer then we'll also - // be sampling the normal map for the parallax heightmap. - if ( fd.features.hasFeature( MFT_TerrainParallaxMap, getProcessIndex() ) ) - res.numTex += 1; - - // Finally we always send the detail texture - // coord to the pixel shader. - res.numTexReg += 1; - return res; } @@ -836,20 +825,6 @@ void TerrainMacroMapFeatGLSL::processPix( Vector &componentL meta->addStatement( new GenOp( " @ = calcBlend( @.x, @.xy, @, @ );\r\n", new DecOp( detailBlend ), detailInfo, inTex, layerSize, layerSample ) ); - // Get a var and accumulate the blend amount. - Var *blendTotal = (Var*)LangElement::find( "blendTotal" ); - if ( !blendTotal ) - { - blendTotal = new Var; - //blendTotal->setName( "blendTotal" ); - blendTotal->setName( "blendTotal" ); - blendTotal->setType( "float" ); - meta->addStatement( new GenOp( " @ = 0;\r\n", new DecOp( blendTotal ) ) ); - } - - // Add to the blend total. - meta->addStatement(new GenOp(" @ = max( @, @ );\r\n", blendTotal, blendTotal, detailBlend)); - Var *detailColor = (Var*)LangElement::find( "macroColor" ); if ( !detailColor ) { @@ -992,11 +967,12 @@ void TerrainNormalMapFeatGLSL::processPix( Vector &component meta->addStatement( new GenOp( " {\r\n" ) ); // Get the normal map texture. - Var *normalMap = _getNormalMapTex(); + Var *normalMap = _getNormalMapSampler(); /// Get the texture coord. Var *inDet = _getInDetailCoord( componentList ); Var *inTex = getVertTexCoord( "texCoord" ); + Var* detailInfo = _getDetailIdStrengthParallax(); // Sample the normal map. // @@ -1005,11 +981,11 @@ void TerrainNormalMapFeatGLSL::processPix( Vector &component LangElement *texOp; if ( fd.features.hasFeature( MFT_TerrainSideProject, normalIndex ) ) { - texOp = new GenOp( "lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z )", - normalMap, inDet, normalMap, inDet, inTex ); + texOp = new GenOp( "lerp( tex2D( @, vec3(@.yz, @.x) ), tex2D( @, vec3(@.xz, @.x) ), @.z )", + normalMap, inDet, new IndexOp(detailInfo, normalIndex), normalMap, inDet, inTex, new IndexOp(detailInfo, normalIndex)); } else - texOp = new GenOp( "tex2D(@, @.xy)", normalMap, inDet ); + texOp = new GenOp( String::ToString("tex2D(@, vec3(@.xy, @.x))", normalIndex), normalMap, inDet, new IndexOp(detailInfo, normalIndex)); // create bump normal Var *bumpNorm = new Var; @@ -1019,26 +995,11 @@ void TerrainNormalMapFeatGLSL::processPix( Vector &component LangElement *bumpNormDecl = new DecOp( bumpNorm ); meta->addStatement( expandNormalMap( texOp, bumpNormDecl, bumpNorm, fd ) ); - // If this is the last normal map then we - // can test to see the total blend value - // to see if we should clip the result. - Var* blendTotal = (Var*)LangElement::find("blendTotal"); - if (blendTotal) - { - if (fd.features.getNextFeatureIndex(MFT_TerrainNormalMap, normalIndex) == -1) - meta->addStatement(new GenOp(" if ( @ > 0.0001f ){\r\n\r\n", blendTotal)); - } // Normalize is done later... // Note: The reverse mul order is intentional. Affine matrix. meta->addStatement(new GenOp(" @ = lerp( @, tMul( @.xyz, @ ), min( @, @.w ) );\r\n", gbNormal, gbNormal, bumpNorm, viewToTangent, detailBlend, inDet)); - if (blendTotal) - { - if (fd.features.getNextFeatureIndex(MFT_TerrainNormalMap, normalIndex) == -1) - meta->addStatement(new GenOp(" }\r\n")); - } - // End the conditional block. meta->addStatement( new GenOp( " }\r\n" ) ); @@ -1049,6 +1010,13 @@ ShaderFeature::Resources TerrainNormalMapFeatGLSL::getResources( const MaterialF { Resources res; + if (getProcessIndex() == 0) + { + // Texture Array + res.numTex += 1; + res.numTexReg += 1; + } + // We only need to process normals during the deferred. if ( fd.features.hasFeature( MFT_DeferredConditioner ) ) { @@ -1107,35 +1075,6 @@ ShaderFeature::Resources TerrainLightMapFeatGLSL::getResources( const MaterialFe return res; } - -void TerrainAdditiveFeatGLSL::processPix( Vector &componentList, - const MaterialFeatureData &fd ) -{ - Var *color = NULL; - Var* norm = NULL; - if (fd.features[MFT_isDeferred]) - { - color = (Var*)LangElement::find(getOutputTargetVarName(ShaderFeature::RenderTarget1)); - norm = (Var*)LangElement::find(getOutputTargetVarName(ShaderFeature::DefaultTarget)); - } - color = (Var*)LangElement::find(getOutputTargetVarName(ShaderFeature::DefaultTarget)); - - Var *blendTotal = (Var*)LangElement::find( "blendTotal" ); - if ( !color || !blendTotal ) - return; - - MultiLine *meta = new MultiLine; - - meta->addStatement( new GenOp( " clip( @ - 0.0001 );\r\n", blendTotal ) ); - meta->addStatement( new GenOp( " @.a = @;\r\n", color, blendTotal ) ); - if (fd.features[MFT_isDeferred]) - { - meta->addStatement(new GenOp(" @.a = @;\r\n", norm, blendTotal)); - } - - output = meta; -} - //standard matInfo map contains data of the form .r = bitflags, .g = (will contain AO), //.b = specular strength, a= spec power. @@ -1197,21 +1136,25 @@ void TerrainORMMapFeatGLSL::processVert(Vector &componentList, Var *outTex = (Var*)LangElement::find(String::ToString("detCoord%d", detailIndex)); if (outTex == NULL) { + outTex = new Var; outTex = connectComp->getElement(RT_TEXCOORD); outTex->setName(String::ToString("detCoord%d", detailIndex)); outTex->setStructName("OUT"); outTex->setType("vec4"); } // Get the detail scale and fade info. - Var *detScaleAndFade = (Var*)LangElement::find(String::ToString("detailScaleAndFade%d", detailIndex)); + Var *detScaleAndFade = (Var*)LangElement::find("detailScaleAndFade"); if (detScaleAndFade == NULL) { + detScaleAndFade = new Var; detScaleAndFade->setType("vec4"); - detScaleAndFade->setName(String::ToString("detailScaleAndFade%d", detailIndex)); + detScaleAndFade->setName("detailScaleAndFade"); detScaleAndFade->uniform = true; detScaleAndFade->constSortPos = cspPotentialPrimitive; } + detScaleAndFade->arraySize = mMax(detScaleAndFade->arraySize, detailIndex + 1); + // Setup the detail coord. // // NOTE: You see here we scale the texture coord by 'xyx' @@ -1221,11 +1164,11 @@ void TerrainORMMapFeatGLSL::processVert(Vector &componentList, // // See TerrainBaseMapFeatGLSL::processVert(). // - meta->addStatement(new GenOp(" @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade)); + meta->addStatement(new GenOp(" @.xyz = @ * @.xyx;\r\n", outTex, inTex, new IndexOp(detScaleAndFade, detailIndex))); // And sneak the detail fade thru the w detailCoord. meta->addStatement(new GenOp(" @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n", - outTex, detScaleAndFade, dist, detScaleAndFade)); + outTex, new IndexOp(detScaleAndFade, detailIndex), dist, new IndexOp(detScaleAndFade, detailIndex))); output = meta; } @@ -1241,9 +1184,10 @@ void TerrainORMMapFeatGLSL::processPix(Vector &componentList, /// Get the texture coord. Var *inDet = _getInDetailCoord(componentList); Var *inTex = getVertTexCoord("texCoord"); + Var* detailInfo = _getDetailIdStrengthParallax(); const S32 compositeIndex = getProcessIndex(); - Var *ormConfigMap = _getORMConfigMapTex(); + Var *ormConfigMap = _getOrmMapSampler(); // Sample the normal map. // // We take two normal samples and lerp between them for @@ -1252,11 +1196,11 @@ void TerrainORMMapFeatGLSL::processPix(Vector &componentList, if (fd.features.hasFeature(MFT_TerrainSideProject, compositeIndex)) { - texOp = new GenOp("lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z )", - ormConfigMap, inDet, ormConfigMap, inDet, inTex); + texOp = new GenOp("lerp( tex2D( @, vec3(@.yz, @.x) ), tex2D( @, vec3(@.xz, @.x) ), @.z )", + ormConfigMap, inDet, new IndexOp(detailInfo, compositeIndex), ormConfigMap, inDet, new IndexOp(detailInfo, compositeIndex), inTex); } else - texOp = new GenOp("tex2D(@, @.xy)", ormConfigMap, inDet); + texOp = new GenOp("tex2D(@, vec3(@.xy, @.x))", ormConfigMap, inDet, new IndexOp(detailInfo, compositeIndex)); // search for material var Var * ormConfig; diff --git a/Engine/source/terrain/glsl/terrFeatureGLSL.h b/Engine/source/terrain/glsl/terrFeatureGLSL.h index 830e396d7..3e954caf0 100644 --- a/Engine/source/terrain/glsl/terrFeatureGLSL.h +++ b/Engine/source/terrain/glsl/terrFeatureGLSL.h @@ -44,9 +44,9 @@ public: Var* _getInMacroCoord(Vector &componentList ); - Var* _getNormalMapTex(); - - Var* _getORMConfigMapTex(); + Var* _getDetailMapSampler(); + Var* _getNormalMapSampler(); + Var* _getOrmMapSampler(); static Var* _getUniformVar( const char *name, const char *type, ConstantSortPosition csp ); @@ -151,17 +151,6 @@ public: virtual String getName() { return "Terrain Lightmap Texture"; } }; - -class TerrainAdditiveFeatGLSL : public TerrainFeatGLSL -{ -public: - - virtual void processPix( Vector &componentList, - const MaterialFeatureData &fd ); - - virtual String getName() { return "Terrain Additive"; } -}; - class TerrainORMMapFeatGLSL : public TerrainFeatGLSL { public: diff --git a/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp b/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp index 74f002193..8c0dd82ba 100644 --- a/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp +++ b/Engine/source/terrain/hlsl/terrFeatureHLSL.cpp @@ -48,7 +48,6 @@ namespace FEATUREMGR->registerFeature( MFT_TerrainMacroMap, new NamedFeatureHLSL("TerrainMacroMap Deprecated")); // new TerrainMacroMapFeatHLSL); FEATUREMGR->registerFeature( MFT_TerrainLightMap, new TerrainLightMapFeatHLSL ); FEATUREMGR->registerFeature( MFT_TerrainSideProject, new NamedFeatureHLSL( "Terrain Side Projection" ) ); - FEATUREMGR->registerFeature( MFT_TerrainAdditive, new TerrainAdditiveFeatHLSL ); FEATUREMGR->registerFeature( MFT_TerrainORMMap, new TerrainORMMapFeatHLSL ); FEATUREMGR->registerFeature( MFT_DeferredTerrainBlankInfoMap, new TerrainBlankInfoMapFeatHLSL ); } @@ -123,56 +122,131 @@ Var* TerrainFeatHLSL::_getInMacroCoord( Vector &componentList return inDet; } -Var* TerrainFeatHLSL::_getNormalMapTex() +Var* TerrainFeatHLSL::_getDetailMapSampler() { - String name(String::ToString("normalMap%d", getProcessIndex())); - Var *normalMap = (Var*)LangElement::find(name); + String name("detailMapSampler"); + Var* detailMapSampler = (Var*)LangElement::find(name); - if (!normalMap) + if(!detailMapSampler) { - normalMap = new Var; - normalMap->setType("SamplerState"); - normalMap->setName(name); - normalMap->uniform = true; - normalMap->sampler = true; - normalMap->constNum = Var::getTexUnitNum(); + detailMapSampler = new Var; + detailMapSampler->setName(name); + detailMapSampler->setType("SamplerState"); + detailMapSampler->uniform = true; + detailMapSampler->sampler = true; + detailMapSampler->constNum = Var::getTexUnitNum(); } - return normalMap; + return detailMapSampler; } -Var* TerrainFeatHLSL::_getORMConfigMapTex() +Var* TerrainFeatHLSL::_getDetailMapArray() { - String name(String::ToString("ormConfigMap%d", getProcessIndex())); - Var *ormConfigMap = (Var*)LangElement::find(name); + String name("detailMapArray"); + Var* detailMapArray = (Var*)LangElement::find(name); - if (!ormConfigMap) + if(!detailMapArray) { - ormConfigMap = new Var; - ormConfigMap->setType("SamplerState"); - ormConfigMap->setName(name); - ormConfigMap->uniform = true; - ormConfigMap->sampler = true; - ormConfigMap->constNum = Var::getTexUnitNum(); + detailMapArray = new Var; + detailMapArray->setName(name); + detailMapArray->setType("Texture2DArray"); + detailMapArray->uniform = true; + detailMapArray->texture = true; + detailMapArray->constNum = _getDetailMapSampler()->constNum; } - return ormConfigMap; + return detailMapArray; +} + +Var* TerrainFeatHLSL::_getNormalMapSampler() +{ + String name("normalMapSampler"); + Var* normalMapSampler = (Var*)LangElement::find(name); + + if (!normalMapSampler) + { + normalMapSampler = new Var; + normalMapSampler->setName(name); + normalMapSampler->setType("SamplerState"); + normalMapSampler->uniform = true; + normalMapSampler->sampler = true; + normalMapSampler->constNum = Var::getTexUnitNum(); + } + + return normalMapSampler; +} + +Var* TerrainFeatHLSL::_getNormalMapArray() +{ + String name("normalMapArray"); + Var* normalMapArray = (Var*)LangElement::find(name); + + if (!normalMapArray) + { + normalMapArray = new Var; + normalMapArray->setName(name); + normalMapArray->setType("Texture2DArray"); + normalMapArray->uniform = true; + normalMapArray->texture = true; + normalMapArray->constNum = _getNormalMapSampler()->constNum; + } + + return normalMapArray; +} + +Var* TerrainFeatHLSL::_getOrmMapSampler() +{ + String name("ormMapSampler"); + Var* ormMapSampler = (Var*)LangElement::find(name); + + if (!ormMapSampler) + { + ormMapSampler = new Var; + ormMapSampler->setName(name); + ormMapSampler->setType("SamplerState"); + ormMapSampler->uniform = true; + ormMapSampler->sampler = true; + ormMapSampler->constNum = Var::getTexUnitNum(); + } + + return ormMapSampler; +} + +Var* TerrainFeatHLSL::_getOrmMapArray() +{ + String name("ormMapArray"); + Var* ormMapArray = (Var*)LangElement::find(name); + + if (!ormMapArray) + { + ormMapArray = new Var; + ormMapArray->setName(name); + ormMapArray->setType("Texture2DArray"); + ormMapArray->uniform = true; + ormMapArray->texture = true; + ormMapArray->constNum = _getOrmMapSampler()->constNum; + } + + return ormMapArray; } Var* TerrainFeatHLSL::_getDetailIdStrengthParallax() { - String name( String::ToString( "detailIdStrengthParallax%d", getProcessIndex() ) ); + String name( String::ToString( "detailIdStrengthParallax", getProcessIndex() ) ); Var *detailInfo = (Var*)LangElement::find( name ); if ( !detailInfo ) { detailInfo = new Var; - detailInfo->setType( "float3" ); + detailInfo->setType( "float4" ); detailInfo->setName( name ); detailInfo->uniform = true; detailInfo->constSortPos = cspPotentialPrimitive; + detailInfo->arraySize = getProcessIndex(); } + detailInfo->arraySize = mMax(detailInfo->arraySize, getProcessIndex() + 1); + return detailInfo; } @@ -383,11 +457,17 @@ void TerrainDetailMapFeatHLSL::processVert( Vector &component outTex->setType( "float4" ); // Get the detail scale and fade info. - Var *detScaleAndFade = new Var; - detScaleAndFade->setType( "float4" ); - detScaleAndFade->setName( String::ToString( "detailScaleAndFade%d", detailIndex ) ); - detScaleAndFade->uniform = true; - detScaleAndFade->constSortPos = cspPotentialPrimitive; + Var* detScaleAndFade = (Var*)LangElement::find("detailScaleAndFade"); + if (detScaleAndFade == NULL) + { + detScaleAndFade = new Var; + detScaleAndFade->setType("float4"); + detScaleAndFade->setName("detailScaleAndFade"); + detScaleAndFade->uniform = true; + detScaleAndFade->constSortPos = cspPotentialPrimitive; + } + + detScaleAndFade->arraySize = mMax(detScaleAndFade->arraySize, detailIndex + 1); // Setup the detail coord. // @@ -398,11 +478,11 @@ void TerrainDetailMapFeatHLSL::processVert( Vector &component // // See TerrainBaseMapFeatHLSL::processVert(). // - meta->addStatement( new GenOp( " @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade ) ); + meta->addStatement( new GenOp( " @.xyz = @ * @.xyx;\r\n", outTex, inTex, new IndexOp(detScaleAndFade, detailIndex) ) ); // And sneak the detail fade thru the w detailCoord. meta->addStatement( new GenOp( " @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n", - outTex, detScaleAndFade, dist, detScaleAndFade ) ); + outTex, new IndexOp(detScaleAndFade, detailIndex), dist, new IndexOp(detScaleAndFade, detailIndex)) ); output = meta; } @@ -485,52 +565,25 @@ void TerrainDetailMapFeatHLSL::processPix( Vector &component // Calculate the blend for this detail texture. meta->addStatement( new GenOp( " @ = calcBlend( @.x, @.xy, @, @ );\r\n", - new DecOp( detailBlend ), detailInfo, inTex, layerSize, layerSample ) ); - - // Get a var and accumulate the blend amount. - Var *blendTotal = (Var*)LangElement::find( "blendTotal" ); - if ( !blendTotal ) - { - blendTotal = new Var; - blendTotal->setName( "blendTotal" ); - blendTotal->setType( "float" ); - meta->addStatement( new GenOp( " @ = 0;\r\n", new DecOp( blendTotal ) ) ); - } - - // Add to the blend total. - - meta->addStatement(new GenOp(" @ = max( @, @ );\r\n", blendTotal, blendTotal, detailBlend)); + new DecOp( detailBlend ), new IndexOp(detailInfo, detailIndex), inTex, layerSize, layerSample ) ); // If we had a parallax feature... then factor in the parallax // amount so that it fades out with the layer blending. if (fd.features.hasFeature(MFT_TerrainParallaxMap, detailIndex)) { - // Get the rest of our inputs. - Var *normalMap = _getNormalMapTex(); - - String name(String::ToString("normalMapTex%d", getProcessIndex())); - Var *normalMapTex = (Var*)LangElement::find(name); - - if (!normalMapTex) - { - normalMapTex = new Var; - normalMapTex->setName(String::ToString("normalMapTex%d", getProcessIndex())); - normalMapTex->setType("Texture2D"); - normalMapTex->uniform = true; - normalMapTex->texture = true; - normalMapTex->constNum = normalMap->constNum; - } + Var* normalMapArray = _getNormalMapArray(); + Var* normalMapSampler = _getNormalMapSampler(); // Call the library function to do the rest. if (fd.features.hasFeature(MFT_IsBC3nm, detailIndex)) { - meta->addStatement(new GenOp(" @.xy += parallaxOffsetDxtnm( @, @, @.xy, @, @.z * @ );\r\n", - inDet, normalMapTex, normalMap, inDet, negViewTS, detailInfo, detailBlend)); + meta->addStatement(new GenOp(" @.xy += parallaxOffsetDxtnmTexArray( @, @, float3(@.xy, @.x), @, @.z * @ );\r\n", + inDet, normalMapArray, normalMapSampler, inDet, new IndexOp(detailInfo, detailIndex), negViewTS, new IndexOp(detailInfo, detailIndex), detailBlend)); } else { - meta->addStatement(new GenOp(" @.xy += parallaxOffset( @, @, @.xy, @, @.z * @ );\r\n", - inDet, normalMapTex, normalMap, inDet, negViewTS, detailInfo, detailBlend)); + meta->addStatement(new GenOp(" @.xy += parallaxOffsetTexArray( @, @, float3(@.xy, @.x), @, @.z * @ );\r\n", + inDet, normalMapArray, normalMapSampler, inDet, new IndexOp(detailInfo, detailIndex), negViewTS, new IndexOp(detailInfo, detailIndex), detailBlend)); } } @@ -559,14 +612,6 @@ void TerrainDetailMapFeatHLSL::processPix( Vector &component meta->addStatement( new GenOp( " @;\r\n", new DecOp( detailColor ) ) ); } - // Get the detail texture. - Var *detailMap = new Var; - detailMap->setType( "SamplerState" ); - detailMap->setName( String::ToString( "detailMap%d", detailIndex ) ); - detailMap->uniform = true; - detailMap->sampler = true; - detailMap->constNum = Var::getTexUnitNum(); // used as texture unit num here - // If we're using SM 3.0 then take advantage of // dynamic branching to skip layers per-pixel. @@ -585,27 +630,23 @@ void TerrainDetailMapFeatHLSL::processPix( Vector &component // //Sampled detail texture that is not expanded - Var* detailTex = new Var; - detailTex->setName(String::ToString("detailTex%d", detailIndex)); - detailTex->setType("Texture2D"); - detailTex->uniform = true; - detailTex->texture = true; - detailTex->constNum = detailMap->constNum; + Var* detailMapArray = _getDetailMapArray(); + Var* detailMapSampler = _getDetailMapSampler(); if (fd.features.hasFeature(MFT_TerrainSideProject, detailIndex)) { - meta->addStatement(new GenOp(" @ = ( lerp( @.Sample( @, @.yz ), @.Sample( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n", - detailColor, detailTex, detailMap, inDet, detailTex, detailMap, inDet, inTex)); + meta->addStatement(new GenOp(" @ = ( lerp( @.Sample( @, float3(@.yz, @.x) ), @.Sample( @, float3(@.xz, @.x) ), @.z ) * 2.0 ) - 1.0;\r\n", + detailColor, detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex), detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex), inTex)); } else { - meta->addStatement(new GenOp(" @ = ( @.Sample( @, @.xy ) * 2.0 ) - 1.0;\r\n", - detailColor, detailTex, detailMap, inDet)); + meta->addStatement(new GenOp(" @ = ( @.Sample( @, float3(@.xy, @.x) ) * 2.0 ) - 1.0;\r\n", + detailColor, detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex))); } meta->addStatement( new GenOp( " @ *= @.y * @.w;\r\n", - detailColor, detailInfo, inDet ) ); + detailColor, new IndexOp(detailInfo, detailIndex), inDet ) ); ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget; @@ -635,25 +676,24 @@ ShaderFeature::Resources TerrainDetailMapFeatHLSL::getResources( const MaterialF // If this is the first detail pass then we // samples from the layer tex. res.numTex += 1; + res.numTexReg += 1; - // If this material also does parallax then it - // will generate the negative view vector and the - // worldToTanget transform. - if ( fd.features.hasFeature( MFT_TerrainParallaxMap ) ) - res.numTexReg += 4; + // Add Detail TextureArray + res.numTex += 1; + res.numTexReg += 1; } // sample from the detail texture for diffuse coloring. - res.numTex += 1; + // res.numTex += 1; // If we have parallax for this layer then we'll also // be sampling the normal map for the parallax heightmap. - if ( fd.features.hasFeature( MFT_TerrainParallaxMap, getProcessIndex() ) ) - res.numTex += 1; + //if ( fd.features.hasFeature( MFT_TerrainParallaxMap, getProcessIndex() ) ) + //res.numTex += 1; // Finally we always send the detail texture // coord to the pixel shader. - res.numTexReg += 1; + // res.numTexReg += 1; return res; } @@ -714,18 +754,24 @@ void TerrainMacroMapFeatHLSL::processVert( Vector &componentL outTex->setType( "float4" ); // Get the detail scale and fade info. - Var *detScaleAndFade = new Var; - detScaleAndFade->setType( "float4" ); - detScaleAndFade->setName( String::ToString( "macroScaleAndFade%d", detailIndex ) ); - detScaleAndFade->uniform = true; - detScaleAndFade->constSortPos = cspPotentialPrimitive; + Var* macroScaleAndFade = (Var*)LangElement::find("macroScaleAndFade"); + if (macroScaleAndFade == NULL) + { + macroScaleAndFade = new Var; + macroScaleAndFade->setType("float4"); + macroScaleAndFade->setName("macroScaleAndFade"); + macroScaleAndFade->uniform = true; + macroScaleAndFade->constSortPos = cspPotentialPrimitive; + } + + macroScaleAndFade->arraySize = mMax(macroScaleAndFade->arraySize, detailIndex + 1); // Setup the detail coord. - meta->addStatement( new GenOp( " @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade ) ); + meta->addStatement( new GenOp( " @.xyz = @ * @.xyx;\r\n", outTex, inTex, new IndexOp(macroScaleAndFade, detailIndex)) ); // And sneak the detail fade thru the w detailCoord. meta->addStatement( new GenOp( " @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n", - outTex, detScaleAndFade, dist, detScaleAndFade ) ); + outTex, new IndexOp(macroScaleAndFade, detailIndex), dist, new IndexOp(macroScaleAndFade, detailIndex)) ); output = meta; } @@ -809,20 +855,7 @@ void TerrainMacroMapFeatHLSL::processPix( Vector &componentL // Calculate the blend for this detail texture. meta->addStatement( new GenOp( " @ = calcBlend( @.x, @.xy, @, @ );\r\n", - new DecOp( detailBlend ), detailInfo, inTex, layerSize, layerSample ) ); - - // Get a var and accumulate the blend amount. - Var *blendTotal = (Var*)LangElement::find( "blendTotal" ); - if ( !blendTotal ) - { - blendTotal = new Var; - blendTotal->setName( "blendTotal" ); - blendTotal->setType( "float" ); - meta->addStatement( new GenOp( " @ = 0;\r\n", new DecOp( blendTotal ) ) ); - } - - // Add to the blend total. - meta->addStatement(new GenOp(" @ = max( @, @ );\r\n", blendTotal, blendTotal, detailBlend)); + new DecOp( detailBlend ), new IndexOp(detailInfo, detailIndex), inTex, layerSize, layerSample ) ); // Check to see if we have a gbuffer normal. Var *gbNormal = (Var*)LangElement::find( "gbNormal" ); @@ -849,22 +882,6 @@ void TerrainMacroMapFeatHLSL::processPix( Vector &componentL meta->addStatement( new GenOp( " @;\r\n", new DecOp( detailColor ) ) ); } - // Get the detail texture. - Var *detailMap = new Var; - detailMap->setType( "SamplerState" ); - detailMap->setName( String::ToString( "macroMap%d", detailIndex ) ); - detailMap->uniform = true; - detailMap->sampler = true; - detailMap->constNum = Var::getTexUnitNum(); // used as texture unit num here - - //Create texture object for directx 11 - Var *detailTex = new Var; - detailTex->setName(String::ToString("macroMapTex%d", detailIndex)); - detailTex->setType("Texture2D"); - detailTex->uniform = true; - detailTex->texture = true; - detailTex->constNum = detailMap->constNum; - // If we're using SM 3.0 then take advantage of // dynamic branching to skip layers per-pixel. if ( GFX->getPixelShaderVersion() >= 3.0f ) @@ -872,6 +889,9 @@ void TerrainMacroMapFeatHLSL::processPix( Vector &componentL meta->addStatement( new GenOp( " {\r\n" ) ); + Var* detailMapArray = _getDetailMapArray(); + Var* detailMapSampler = _getDetailMapSampler(); + // Note that we're doing the standard greyscale detail // map technique here which can darken and lighten the // diffuse texture. @@ -881,17 +901,17 @@ void TerrainMacroMapFeatHLSL::processPix( Vector &componentL // if (fd.features.hasFeature(MFT_TerrainSideProject, detailIndex)) { - meta->addStatement(new GenOp(" @ = ( lerp( @.Sample( @, @.yz ), @.Sample( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n", - detailColor, detailTex, detailMap, inDet, detailTex, detailMap, inDet, inTex)); + meta->addStatement(new GenOp(" @ = ( lerp( @.Sample( @, float3(@.yz, @.x) ), @.Sample( @, float3(@.xz, @.x) ), @.z ) * 2.0 ) - 1.0;\r\n", + detailColor, detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex), detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex), inTex)); } else { - meta->addStatement(new GenOp(" @ = ( @.Sample( @, @.xy ) * 2.0 ) - 1.0;\r\n", - detailColor, detailTex, detailMap, inDet)); + meta->addStatement(new GenOp(" @ = ( @.Sample( @, float3(@.xy, @.x) ) * 2.0 ) - 1.0;\r\n", + detailColor, detailMapArray, detailMapSampler, inDet, new IndexOp(detailInfo, detailIndex))); } meta->addStatement( new GenOp( " @ *= @.y * @.w;\r\n", - detailColor, detailInfo, inDet ) ); + detailColor, new IndexOp(detailInfo, detailIndex), inDet ) ); ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget; @@ -987,38 +1007,28 @@ void TerrainNormalMapFeatHLSL::processPix( Vector &component meta->addStatement( new GenOp( " {\r\n" ) ); - // Get the normal map texture. - Var *normalMap = _getNormalMapTex(); - /// Get the texture coord. Var *inDet = _getInDetailCoord( componentList ); Var *inTex = getVertTexCoord( "texCoord" ); + Var* detailInfo = _getDetailIdStrengthParallax(); + // Sample the normal map. // // We take two normal samples and lerp between them for // side projection layers... else a single sample. LangElement *texOp; - - String name(String::ToString("normalMapTex%d", getProcessIndex())); - Var *normalMapTex = (Var*)LangElement::find(name); - if (!normalMapTex) - { - normalMapTex = new Var; - normalMapTex->setName(String::ToString("normalMapTex%d", getProcessIndex())); - normalMapTex->setType("Texture2D"); - normalMapTex->uniform = true; - normalMapTex->texture = true; - normalMapTex->constNum = normalMap->constNum; - } + + Var* normalMapSampler = _getNormalMapSampler(); + Var* normalMapArray = _getNormalMapArray(); if (fd.features.hasFeature(MFT_TerrainSideProject, normalIndex)) { - texOp = new GenOp("lerp( @.Sample( @, @.yz ), @.Sample( @, @.xz ), @.z )", - normalMapTex, normalMap, inDet, normalMapTex, normalMap, inDet, inTex); + texOp = new GenOp("lerp( @.Sample( @, float3(@.yz, @.x) ), @.Sample( @, float3(@.xz, @.x) ), @.z )", + normalMapArray, normalMapSampler, inDet, new IndexOp(detailInfo, normalIndex), normalMapArray, normalMapSampler, inDet, new IndexOp(detailInfo, normalIndex), inTex); } else - texOp = new GenOp("@.Sample(@, @.xy)", normalMapTex, normalMap, inDet); + texOp = new GenOp("@.Sample(@, float3(@.xy, @.x))", normalMapArray, normalMapSampler, inDet, new IndexOp(detailInfo, normalIndex)); // create bump normal Var *bumpNorm = new Var; @@ -1028,25 +1038,11 @@ void TerrainNormalMapFeatHLSL::processPix( Vector &component LangElement *bumpNormDecl = new DecOp( bumpNorm ); meta->addStatement( expandNormalMap( texOp, bumpNormDecl, bumpNorm, fd ) ); - // If this is the last normal map then we - // can test to see the total blend value - // to see if we should clip the result. - Var* blendTotal = (Var*)LangElement::find("blendTotal"); - if (blendTotal) - { - if (fd.features.getNextFeatureIndex(MFT_TerrainNormalMap, normalIndex) == -1) - meta->addStatement(new GenOp(" if ( @ > 0.0001f ){\r\n\r\n", blendTotal)); - } // Normalize is done later... // Note: The reverse mul order is intentional. Affine matrix. meta->addStatement( new GenOp( " @ = lerp( @, mul( @.xyz, @ ), min( @, @.w ) );\r\n", gbNormal, gbNormal, bumpNorm, viewToTangent, detailBlend, inDet ) ); - if (blendTotal) - { - if (fd.features.getNextFeatureIndex(MFT_TerrainNormalMap, normalIndex) == -1) - meta->addStatement(new GenOp(" }\r\n")); - } // End the conditional block. meta->addStatement( new GenOp( " }\r\n" ) ); @@ -1056,14 +1052,21 @@ void TerrainNormalMapFeatHLSL::processPix( Vector &component ShaderFeature::Resources TerrainNormalMapFeatHLSL::getResources( const MaterialFeatureData &fd ) { Resources res; + + + if (getProcessIndex() == 0) + { + res.numTexReg += 1; + res.numTex += 1; + } // If this is the first normal map and there // are no parallax features then we will // generate the worldToTanget transform. - if ( !fd.features.hasFeature( MFT_TerrainParallaxMap ) && - ( getProcessIndex() == 0 || !fd.features.hasFeature( MFT_TerrainNormalMap, getProcessIndex() - 1 ) ) ) - res.numTexReg = 3; - res.numTex = 1; + //if ( !fd.features.hasFeature( MFT_TerrainParallaxMap ) && + // ( getProcessIndex() == 0 || !fd.features.hasFeature( MFT_TerrainNormalMap, getProcessIndex() - 1 ) ) ) + // res.numTexReg = 3; + //res.numTex = 1; return res; } @@ -1116,35 +1119,6 @@ ShaderFeature::Resources TerrainLightMapFeatHLSL::getResources( const MaterialFe return res; } -void TerrainAdditiveFeatHLSL::processPix( Vector &componentList, - const MaterialFeatureData &fd ) -{ - Var *color = NULL; - Var* norm = NULL; - if (fd.features[MFT_isDeferred]) - { - color = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::RenderTarget1) ); - norm = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::DefaultTarget) ); - } - else - color = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::DefaultTarget) ); - - Var *blendTotal = (Var*)LangElement::find( "blendTotal" ); - if ( !color || !blendTotal ) - return; - - MultiLine *meta = new MultiLine; - - meta->addStatement( new GenOp( " clip( @ - 0.0001 );\r\n", blendTotal ) ); - meta->addStatement( new GenOp( " @.a = @;\r\n", color, blendTotal ) ); - if (fd.features[MFT_isDeferred]) - { - meta->addStatement(new GenOp(" @.a = @;\r\n", norm, blendTotal)); - } - - output = meta; -} - //standard matInfo map contains data of the form .r = bitflags, .g = (will contain AO), //.b = specular strength, a= spec power. @@ -1211,15 +1185,18 @@ void TerrainORMMapFeatHLSL::processVert(Vector &componentList, outTex->setType("float4"); } // Get the detail scale and fade info. - Var *detScaleAndFade = (Var*)LangElement::find(String::ToString("detailScaleAndFade%d", detailIndex)); + Var *detScaleAndFade = (Var*)LangElement::find("detailScaleAndFade"); if (detScaleAndFade == NULL) { + detScaleAndFade = new Var; detScaleAndFade->setType("float4"); - detScaleAndFade->setName(String::ToString("detailScaleAndFade%d", detailIndex)); + detScaleAndFade->setName("detailScaleAndFade"); detScaleAndFade->uniform = true; detScaleAndFade->constSortPos = cspPotentialPrimitive; } + detScaleAndFade->arraySize = mMax(detScaleAndFade->arraySize, detailIndex + 1); + // Setup the detail coord. // // NOTE: You see here we scale the texture coord by 'xyx' @@ -1229,11 +1206,11 @@ void TerrainORMMapFeatHLSL::processVert(Vector &componentList, // // See TerrainBaseMapFeatHLSL::processVert(). // - meta->addStatement(new GenOp(" @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade)); + meta->addStatement(new GenOp(" @.xyz = @ * @.xyx;\r\n", outTex, inTex, new IndexOp(detScaleAndFade, detailIndex))); // And sneak the detail fade thru the w detailCoord. meta->addStatement(new GenOp(" @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n", - outTex, detScaleAndFade, dist, detScaleAndFade)); + outTex, new IndexOp(detScaleAndFade, detailIndex), dist, new IndexOp(detScaleAndFade, detailIndex))); output = meta; } @@ -1249,32 +1226,24 @@ void TerrainORMMapFeatHLSL::processPix(Vector &componentList, /// Get the texture coord. Var *inDet = _getInDetailCoord(componentList); Var *inTex = getVertTexCoord("texCoord"); + Var* detailInfo = _getDetailIdStrengthParallax(); const S32 compositeIndex = getProcessIndex(); - Var *ormConfigMap = _getORMConfigMapTex(); // Sample the normal map. // // We take two normal samples and lerp between them for // side projection layers... else a single sample. LangElement *texOp; - String name(String::ToString("ormConfigMapTex%d", getProcessIndex())); - Var *ormConfigMapTex = (Var*)LangElement::find(name); - if (!ormConfigMapTex) - { - ormConfigMapTex = new Var; - ormConfigMapTex->setName(String::ToString("ormConfigMapTex%d", getProcessIndex())); - ormConfigMapTex->setType("Texture2D"); - ormConfigMapTex->uniform = true; - ormConfigMapTex->texture = true; - ormConfigMapTex->constNum = ormConfigMap->constNum; - } + + Var* ormMapArray = _getOrmMapArray(); + Var* ormMapSampler = _getOrmMapSampler(); if (fd.features.hasFeature(MFT_TerrainSideProject, compositeIndex)) { - texOp = new GenOp("lerp( @.Sample( @, @.yz ), @.Sample( @, @.xz ), @.z )", - ormConfigMapTex, ormConfigMap, inDet, ormConfigMapTex, ormConfigMap, inDet, inTex); + texOp = new GenOp("lerp( @.Sample( @, float3(@.yz, @.x) ), @.Sample( @, float3(@.xz, @.x) ), @.z )", + ormMapArray, ormMapSampler, inDet, new IndexOp(detailInfo, compositeIndex), ormMapArray, ormMapSampler, inDet, new IndexOp(detailInfo, compositeIndex), inTex); } else - texOp = new GenOp("@.Sample(@, @.xy)", ormConfigMapTex, ormConfigMap, inDet); + texOp = new GenOp("@.Sample(@, float3(@.xy, @.x))", ormMapArray, ormMapSampler, inDet, new IndexOp(detailInfo, compositeIndex)); // search for material var Var * ormConfig; diff --git a/Engine/source/terrain/hlsl/terrFeatureHLSL.h b/Engine/source/terrain/hlsl/terrFeatureHLSL.h index e2b5fdb55..57851621a 100644 --- a/Engine/source/terrain/hlsl/terrFeatureHLSL.h +++ b/Engine/source/terrain/hlsl/terrFeatureHLSL.h @@ -45,6 +45,12 @@ public: Var* _getInMacroCoord(Vector &componentList ); + Var* _getDetailMapSampler(); + Var* _getDetailMapArray(); + Var* _getNormalMapSampler(); + Var* _getNormalMapArray(); + Var* _getOrmMapSampler(); + Var* _getOrmMapArray(); Var* _getNormalMapTex(); Var* _getORMConfigMapTex(); @@ -151,17 +157,6 @@ public: virtual String getName() { return "Terrain Lightmap Texture"; } }; - -class TerrainAdditiveFeatHLSL : public TerrainFeatHLSL -{ -public: - - virtual void processPix( Vector &componentList, - const MaterialFeatureData &fd ); - - virtual String getName() { return "Terrain Additive"; } -}; - class TerrainORMMapFeatHLSL : public TerrainFeatHLSL { public: diff --git a/Engine/source/terrain/terrCellMaterial.cpp b/Engine/source/terrain/terrCellMaterial.cpp index 7bcc252ff..588301442 100644 --- a/Engine/source/terrain/terrCellMaterial.cpp +++ b/Engine/source/terrain/terrCellMaterial.cpp @@ -23,6 +23,8 @@ #include "platform/platform.h" #include "terrain/terrCellMaterial.h" + +#include "core/util/safeRelease.h" #include "terrain/terrData.h" #include "terrain/terrCell.h" #include "materials/materialFeatureTypes.h" @@ -37,7 +39,7 @@ #include "gfx/util/screenspace.h" #include "lighting/advanced/advancedLightBinManager.h" -S32 sgMaxTerrainMaterialsPerPass = 3; +S32 sgMaxTerrainMaterialsPerPass = 32; AFTER_MODULE_INIT( MaterialManager ) { @@ -55,12 +57,18 @@ Vector _initSamplerNames() //samplerNames.push_back("$macrolayerTex"); samplerNames.push_back("$lightMapTex"); samplerNames.push_back("$lightInfoBuffer"); + samplerNames.push_back("$normalMapSampler"); + samplerNames.push_back("$detailMapSampler"); + samplerNames.push_back("$macroMapSampler"); + samplerNames.push_back("$ormMapSampler"); + // samplerNames.push_back("$ormConfigMapArray"); + for(int i = 0; i < sgMaxTerrainMaterialsPerPass; ++i) { - samplerNames.push_back(avar("$normalMap%d",i)); - samplerNames.push_back(avar("$detailMap%d",i)); + //samplerNames.push_back(avar("$normalMap%d",i)); + //samplerNames.push_back(avar("$detailMap%d",i)); //samplerNames.push_back(avar("$macroMap%d", i)); - samplerNames.push_back(avar("$ormConfigMap%d", i)); + // samplerNames.push_back(avar("$ormConfigMap%d", i)); } return samplerNames; @@ -71,10 +79,11 @@ const Vector TerrainCellMaterial::mSamplerNames = _initSamplerNames(); TerrainCellMaterial::TerrainCellMaterial() : mTerrain( NULL ), - mCurrPass( 0 ), mDeferredMat( NULL ), mReflectMat( NULL ), - mMaterials(0) + mShader( NULL ), + mCurrPass( 0 ), + mMaterials( 0 ) { smAllMaterials.push_back( this ); } @@ -84,6 +93,9 @@ TerrainCellMaterial::~TerrainCellMaterial() SAFE_DELETE( mDeferredMat ); SAFE_DELETE( mReflectMat ); smAllMaterials.remove( this ); + + T3D::for_each(mMaterialInfos.begin(), mMaterialInfos.end(), T3D::delete_pointer()); + mMaterialInfos.clear(); } void TerrainCellMaterial::_updateDefaultAnisotropy() @@ -101,86 +113,74 @@ void TerrainCellMaterial::_updateDefaultAnisotropy() Vector::iterator iter = smAllMaterials.begin(); for ( ; iter != smAllMaterials.end(); iter++ ) { - for ( U32 p=0; p < (*iter)->mPasses.size(); p++ ) + // Start from the existing state block. + GFXStateBlockDesc desc = (*iter)->mStateBlock->getDesc(); + + if ((*iter)->mDetailTexArrayConst->isValid()) { - Pass &pass = (*iter)->mPasses[p]; + const S32 sampler = (*iter)->mDetailTexArrayConst->getSamplerRegister(); - // Start from the existing state block. - GFXStateBlockDesc desc = pass.stateBlock->getDesc(); - - for ( U32 m=0; m < pass.materials.size(); m++ ) + if (maxAnisotropy > 1) { - const MaterialInfo *matInfo = pass.materials[m]; + desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; + desc.samplers[sampler].maxAnisotropy = maxAnisotropy; + } + else + desc.samplers[sampler].minFilter = GFXTextureFilterLinear; + } - if ( matInfo->detailTexConst->isValid() ) - { - const S32 sampler = matInfo->detailTexConst->getSamplerRegister(); + if ((*iter)->mMacroTexArrayConst->isValid()) + { + const S32 sampler = (*iter)->mMacroTexArrayConst->getSamplerRegister(); - if ( maxAnisotropy > 1 ) - { - desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; - desc.samplers[sampler].maxAnisotropy = maxAnisotropy; - } - else - desc.samplers[sampler].minFilter = GFXTextureFilterLinear; - } + if (maxAnisotropy > 1) + { + desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; + desc.samplers[sampler].maxAnisotropy = maxAnisotropy; + } + else + desc.samplers[sampler].minFilter = GFXTextureFilterLinear; + } - if ( matInfo->macroTexConst->isValid() ) - { - const S32 sampler = matInfo->macroTexConst->getSamplerRegister(); + if ((*iter)->mNormalTexArrayConst->isValid()) + { + const S32 sampler = (*iter)->mNormalTexArrayConst->getSamplerRegister(); - if ( maxAnisotropy > 1 ) - { - desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; - desc.samplers[sampler].maxAnisotropy = maxAnisotropy; - } - else - desc.samplers[sampler].minFilter = GFXTextureFilterLinear; - } + if (maxAnisotropy > 1) + { + desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; + desc.samplers[sampler].maxAnisotropy = maxAnisotropy; + } + else + desc.samplers[sampler].minFilter = GFXTextureFilterLinear; + } - if ( matInfo->normalTexConst->isValid() ) - { - const S32 sampler = matInfo->normalTexConst->getSamplerRegister(); + if ((*iter)->mOrmTexArrayConst->isValid()) + { + const S32 sampler = (*iter)->mOrmTexArrayConst->getSamplerRegister(); - if ( maxAnisotropy > 1 ) - { - desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; - desc.samplers[sampler].maxAnisotropy = maxAnisotropy; - } - else - desc.samplers[sampler].minFilter = GFXTextureFilterLinear; - } + if (maxAnisotropy > 1) + { + desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; + desc.samplers[sampler].maxAnisotropy = maxAnisotropy; + } + else + desc.samplers[sampler].minFilter = GFXTextureFilterLinear; + } - if (matInfo->ormTexConst->isValid()) - { - const S32 sampler = matInfo->ormTexConst->getSamplerRegister(); + // Set the updated stateblock. + desc.setCullMode(GFXCullCCW); + (*iter)->mStateBlock = GFX->createStateBlock(desc); - if (maxAnisotropy > 1) - { - desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; - desc.samplers[sampler].maxAnisotropy = maxAnisotropy; - } - else - desc.samplers[sampler].minFilter = GFXTextureFilterLinear; - } + //reflection + desc.setCullMode(GFXCullCW); + (*iter)->mReflectionStateBlock = GFX->createStateBlock(desc); - } // for ( U32 m=0; m < pass.materials.size(); m++ ) - - // Set the updated stateblock. - desc.setCullMode( GFXCullCCW ); - pass.stateBlock = GFX->createStateBlock( desc ); - - //reflection - desc.setCullMode( GFXCullCW ); - pass.reflectionStateBlock = GFX->createStateBlock(desc); - - // Create the wireframe state blocks. - GFXStateBlockDesc wireframe( desc ); - wireframe.fillMode = GFXFillWireframe; - wireframe.setCullMode( GFXCullCCW ); - pass.wireframeStateBlock = GFX->createStateBlock( wireframe ); - - } // for ( U32 p=0; i < (*iter)->mPasses.size(); p++ ) + // Create the wireframe state blocks. + GFXStateBlockDesc wireframe(desc); + wireframe.fillMode = GFXFillWireframe; + wireframe.setCullMode(GFXCullCCW); + (*iter)->mWireframeStateBlock = GFX->createStateBlock(wireframe); } } @@ -207,31 +207,26 @@ void TerrainCellMaterial::setTransformAndEye( const MatrixF &modelXfm, VectorF vEye = invViewXfm.getForwardVector(); vEye.normalize( 1.0f / farPlane ); - for ( U32 i=0; i < mPasses.size(); i++ ) + mConsts->setSafe(mModelViewProjConst, modelViewProj); + + if (mViewToObjConst->isValid() || mWorldViewOnlyConst->isValid()) { - Pass &pass = mPasses[i]; + MatrixF worldViewOnly = viewXfm * modelXfm; - pass.consts->setSafe( pass.modelViewProjConst, modelViewProj ); + mConsts->setSafe(mWorldViewOnlyConst, worldViewOnly); - if( pass.viewToObj->isValid() || pass.worldViewOnly->isValid() ) + if (mViewToObjConst->isValid()) { - MatrixF worldViewOnly = viewXfm * modelXfm; - - pass.consts->setSafe( pass.worldViewOnly, worldViewOnly ); - - if( pass.viewToObj->isValid() ) - { - worldViewOnly.affineInverse(); - pass.consts->set( pass.viewToObj, worldViewOnly); - } + worldViewOnly.affineInverse(); + mConsts->set(mViewToObjConst, worldViewOnly); } - - pass.consts->setSafe( pass.eyePosWorldConst, eyePos ); - pass.consts->setSafe( pass.eyePosConst, objEyePos ); - pass.consts->setSafe( pass.objTransConst, modelXfm ); - pass.consts->setSafe( pass.worldToObjConst, invModelXfm ); - pass.consts->setSafe( pass.vEyeConst, vEye ); } + + mConsts->setSafe(mEyePosWorldConst, eyePos); + mConsts->setSafe(mEyePosConst, objEyePos); + mConsts->setSafe(mObjTransConst, modelXfm); + mConsts->setSafe(mWorldToObjConst, invModelXfm); + mConsts->setSafe(mVEyeConst, vEye); } TerrainCellMaterial* TerrainCellMaterial::getDeferredMat() @@ -268,8 +263,7 @@ void TerrainCellMaterial::init( TerrainBlock *block, mTerrain = block; mMaterials = activeMaterials; - Vector materials; - + mMaterialInfos.clear(); for ( U32 i = 0; i < 64; i++ ) { if ( !( mMaterials & ((U64)1 << i ) ) ) @@ -280,41 +274,20 @@ void TerrainCellMaterial::init( TerrainBlock *block, MaterialInfo *info = new MaterialInfo(); info->layerId = i; info->mat = mat; - materials.push_back( info ); + mMaterialInfos.push_back(info); } - mCurrPass = 0; - mPasses.clear(); - - // Ok... loop till we successfully generate all - // the shader passes for the materials. - while ( materials.size() > 0 || baseOnly ) + if (!_initShader(deferredMat, + reflectMat, + baseOnly)) { - mPasses.increment(); + Con::errorf("TerrainCellMaterial::init - Failed to init shader!"); - if ( !_createPass( &materials, - &mPasses.last(), - mPasses.size() == 1, - deferredMat, - reflectMat, - baseOnly ) ) - { - Con::errorf( "TerrainCellMaterial::init - Failed to create pass!" ); - - // The pass failed to be generated... give up. - mPasses.last().materials.clear(); - mPasses.clear(); - T3D::for_each( materials.begin(), materials.end(), T3D::delete_pointer() ); - return; - } - - if ( baseOnly ) - break; + T3D::for_each(mMaterialInfos.begin(), mMaterialInfos.end(), T3D::delete_pointer()); + mMaterialInfos.clear(); + return; } - // Cleanup any remaining matinfo. - T3D::for_each( materials.begin(), materials.end(), T3D::delete_pointer() ); - // If we have attached mats then update them too. if ( mDeferredMat ) mDeferredMat->init( mTerrain, mMaterials, true, false, baseOnly ); @@ -322,14 +295,11 @@ void TerrainCellMaterial::init( TerrainBlock *block, mReflectMat->init( mTerrain, mMaterials, false, true, baseOnly ); } -bool TerrainCellMaterial::_createPass( Vector *materials, - Pass *pass, - bool firstPass, - bool deferredMat, - bool reflectMat, - bool baseOnly ) +bool TerrainCellMaterial::_initShader(bool deferredMat, + bool reflectMat, + bool baseOnly) { - if ( GFX->getPixelShaderVersion() < 3.0f ) + if (GFX->getPixelShaderVersion() < 3.0f) baseOnly = true; // NOTE: At maximum we only try to combine sgMaxTerrainMaterialsPerPass materials @@ -337,7 +307,7 @@ bool TerrainCellMaterial::_createPass( Vector *materials, // cases, but the most common case results in much fewer // shader generation failures and permutations leading to // faster load time and less hiccups during gameplay. - U32 matCount = getMin( sgMaxTerrainMaterialsPerPass, materials->size() ); + U32 matCount = getMin(sgMaxTerrainMaterialsPerPass, mMaterialInfos.size()); Vector normalMaps; @@ -347,96 +317,89 @@ bool TerrainCellMaterial::_createPass( Vector *materials, // TODO: This seems ugly... we should trigger // features like this differently in the future. // - bool useBLM = String::compare( LIGHTMGR->getId(), "BLM" ) == 0; + bool useBLM = String::compare(LIGHTMGR->getId(), "BLM") == 0; // Do we need to disable normal mapping? - const bool disableNormalMaps = MATMGR->getExclusionFeatures().hasFeature( MFT_NormalMap ) || useBLM; + const bool disableNormalMaps = MATMGR->getExclusionFeatures().hasFeature(MFT_NormalMap) || useBLM; // How about parallax? - const bool disableParallaxMaps = GFX->getPixelShaderVersion() < 3.0f || - MATMGR->getExclusionFeatures().hasFeature( MFT_Parallax ); + const bool disableParallaxMaps = GFX->getPixelShaderVersion() < 3.0f || + MATMGR->getExclusionFeatures().hasFeature(MFT_Parallax); // Has advanced lightmap support been enabled for deferred. bool advancedLightmapSupport = false; - if ( deferredMat ) + if (deferredMat) { // This sucks... but it works. - AdvancedLightBinManager *lightBin; - if ( Sim::findObject( "AL_LightBinMgr", lightBin ) ) + AdvancedLightBinManager* lightBin; + if (Sim::findObject("AL_LightBinMgr", lightBin)) advancedLightmapSupport = lightBin->MRTLightmapsDuringDeferred(); } // Loop till we create a valid shader! - while( true ) + while (true) { FeatureSet features; - features.addFeature( MFT_VertTransform ); - features.addFeature( MFT_TerrainBaseMap ); + features.addFeature(MFT_VertTransform); + features.addFeature(MFT_TerrainBaseMap); - if ( deferredMat ) + if (deferredMat) { - features.addFeature( MFT_EyeSpaceDepthOut ); - features.addFeature( MFT_DeferredConditioner ); + features.addFeature(MFT_EyeSpaceDepthOut); + features.addFeature(MFT_DeferredConditioner); features.addFeature(MFT_isDeferred); - if ( advancedLightmapSupport ) - features.addFeature( MFT_RenderTarget3_Zero ); + if (advancedLightmapSupport) + features.addFeature(MFT_RenderTarget3_Zero); } else { - features.addFeature( MFT_RTLighting ); + features.addFeature(MFT_RTLighting); // The HDR feature is always added... it will compile out // if HDR is not enabled in the engine. - features.addFeature( MFT_HDROut ); + features.addFeature(MFT_HDROut); } // Enable lightmaps and fogging if we're in BL. - if ( reflectMat || useBLM ) + if (reflectMat || useBLM) { - features.addFeature( MFT_Fog ); - features.addFeature( MFT_ForwardShading ); + features.addFeature(MFT_Fog); + features.addFeature(MFT_ForwardShading); } - if ( useBLM ) - features.addFeature( MFT_TerrainLightMap ); - - // The additional passes need to be lerp blended into the - // target to maintain the results of the previous passes. - if (!firstPass && deferredMat) - features.addFeature( MFT_TerrainAdditive ); + if (useBLM) + features.addFeature(MFT_TerrainLightMap); normalMaps.clear(); - pass->materials.clear(); + + S32 featureIndex = 0; // Now add all the material layer features. - - for ( U32 i=0; i < matCount && !baseOnly; i++ ) + for (U32 i = 0; i < matCount && !baseOnly; i++) { - TerrainMaterial *mat = (*materials)[i]->mat; + TerrainMaterial* mat = mMaterialInfos[i]->mat; - if ( mat == NULL ) + if (mat == NULL) continue; // We only include materials that // have more than a base texture. - if ( mat->getDetailSize() <= 0 || - mat->getDetailDistance() <= 0 || - mat->getDetailMap().isEmpty() ) - continue; + if (mat->getDetailSize() <= 0 || + mat->getDetailDistance() <= 0 || + mat->getDetailMap().isEmpty()) + continue; - S32 featureIndex = pass->materials.size(); - - // check for macro detail texture - if ( !(mat->getMacroSize() <= 0 || mat->getMacroDistance() <= 0 || mat->getMacroMap().isEmpty() ) ) + // check for macro detail texture + if (!(mat->getMacroSize() <= 0 || mat->getMacroDistance() <= 0 || mat->getMacroMap().isEmpty())) { - if(deferredMat) + if (deferredMat) features.addFeature(MFT_isDeferred, featureIndex); - features.addFeature( MFT_TerrainMacroMap, featureIndex ); + features.addFeature(MFT_TerrainMacroMap, featureIndex); } - if(deferredMat) + if (deferredMat) features.addFeature(MFT_isDeferred, featureIndex); - features.addFeature( MFT_TerrainDetailMap, featureIndex ); + features.addFeature(MFT_TerrainDetailMap, featureIndex); if (!(mat->getORMConfigMap().isEmpty())) { @@ -451,33 +414,34 @@ bool TerrainCellMaterial::_createPass( Vector *materials, if (mat->getInvertRoughness()) features.addFeature(MFT_InvertRoughness, featureIndex); - pass->materials.push_back( (*materials)[i] ); normalMaps.increment(); // Skip normal maps if we need to. - if ( !disableNormalMaps && mat->getNormalMap().isNotEmpty() ) + if (!disableNormalMaps && mat->getNormalMap().isNotEmpty()) { - features.addFeature( MFT_TerrainNormalMap, featureIndex ); + features.addFeature(MFT_TerrainNormalMap, featureIndex); - normalMaps.last().set( mat->getNormalMap(), - &GFXNormalMapProfile, "TerrainCellMaterial::_createPass() - NormalMap" ); + normalMaps.last().set(mat->getNormalMap(), + &GFXNormalMapProfile, "TerrainCellMaterial::_initShader() - NormalMap"); GFXFormat normalFmt = normalMaps.last().getFormat(); - if ( normalFmt == GFXFormatBC3 ) - features.addFeature( MFT_IsBC3nm, featureIndex ); - else if ( normalFmt == GFXFormatBC5) - features.addFeature( MFT_IsBC5nm, featureIndex); + if (normalFmt == GFXFormatBC3) + features.addFeature(MFT_IsBC3nm, featureIndex); + else if (normalFmt == GFXFormatBC5) + features.addFeature(MFT_IsBC5nm, featureIndex); // Do we need and can we do parallax mapping? - if ( !disableParallaxMaps && - mat->getParallaxScale() > 0.0f && - !mat->useSideProjection() ) - features.addFeature( MFT_TerrainParallaxMap, featureIndex ); + if (!disableParallaxMaps && + mat->getParallaxScale() > 0.0f && + !mat->useSideProjection()) + features.addFeature(MFT_TerrainParallaxMap, featureIndex); } // Is this layer got side projection? - if ( mat->useSideProjection() ) - features.addFeature( MFT_TerrainSideProject, featureIndex ); + if (mat->useSideProjection()) + features.addFeature(MFT_TerrainSideProject, featureIndex); + + featureIndex++; } MaterialFeatureData featureData; @@ -488,16 +452,16 @@ bool TerrainCellMaterial::_createPass( Vector *materials, // registers we're gonna need. U32 numTex = 0; U32 numTexReg = 0; - for ( U32 i=0; i < features.getCount(); i++ ) + for (U32 i = 0; i < features.getCount(); i++) { S32 index; - const FeatureType &type = features.getAt( i, &index ); - ShaderFeature* sf = FEATUREMGR->getByType( type ); - if ( !sf ) + const FeatureType& type = features.getAt(i, &index); + ShaderFeature* sf = FEATUREMGR->getByType(type); + if (!sf) continue; - sf->setProcessIndex( index ); - ShaderFeature::Resources res = sf->getResources( featureData ); + sf->setProcessIndex(index); + ShaderFeature::Resources res = sf->getResources(featureData); numTex += res.numTex; numTexReg += res.numTexReg; @@ -509,9 +473,9 @@ bool TerrainCellMaterial::_createPass( Vector *materials, // limit. Its really supposed to be 11, but that // always fails to compile so far. // - if ( numTex < GFX->getNumSamplers() && - numTexReg <= 10 ) - { + if (numTex < GFX->getNumSamplers() && + numTexReg <= 10) + { // NOTE: We really shouldn't be getting errors building the shaders, // but we can generate more instructions than the ps_2_x will allow. // @@ -524,18 +488,18 @@ bool TerrainCellMaterial::_createPass( Vector *materials, // we get down to a single material. If a single material case // fails it means it cannot generate any passes at all! const bool logErrors = true;// matCount == 1; - GFXShader::setLogging( logErrors, true ); + GFXShader::setLogging(logErrors, true); - pass->shader = SHADERGEN->getShader( featureData, getGFXVertexFormat(), NULL, mSamplerNames ); + mShader = SHADERGEN->getShader(featureData, getGFXVertexFormat(), NULL, mSamplerNames); } // If we got a shader then we can continue. - if ( pass->shader ) + if (mShader) break; // If the material count is already 1 then this // is a real shader error... give up! - if ( matCount <= 1 ) + if (matCount <= 1) return false; // If we failed we next try half the input materials @@ -544,180 +508,130 @@ bool TerrainCellMaterial::_createPass( Vector *materials, } // Setup the constant buffer. - pass->consts = pass->shader->allocConstBuffer(); + mConsts = mShader->allocConstBuffer(); // Prepare the basic constants. - pass->modelViewProjConst = pass->shader->getShaderConstHandle( "$modelview" ); - pass->worldViewOnly = pass->shader->getShaderConstHandle( "$worldViewOnly" ); - pass->viewToObj = pass->shader->getShaderConstHandle( "$viewToObj" ); - pass->eyePosWorldConst = pass->shader->getShaderConstHandle( "$eyePosWorld" ); - pass->eyePosConst = pass->shader->getShaderConstHandle( "$eyePos" ); - pass->vEyeConst = pass->shader->getShaderConstHandle( "$vEye" ); - pass->layerSizeConst = pass->shader->getShaderConstHandle( "$layerSize" ); - pass->objTransConst = pass->shader->getShaderConstHandle( "$objTrans" ); - pass->worldToObjConst = pass->shader->getShaderConstHandle( "$worldToObj" ); - pass->lightInfoBufferConst = pass->shader->getShaderConstHandle( "$lightInfoBuffer" ); - pass->baseTexMapConst = pass->shader->getShaderConstHandle( "$baseTexMap" ); - pass->layerTexConst = pass->shader->getShaderConstHandle( "$layerTex" ); - pass->fogDataConst = pass->shader->getShaderConstHandle( "$fogData" ); - pass->fogColorConst = pass->shader->getShaderConstHandle( "$fogColor" ); - pass->lightMapTexConst = pass->shader->getShaderConstHandle( "$lightMapTex" ); - pass->oneOverTerrainSize = pass->shader->getShaderConstHandle( "$oneOverTerrainSize" ); - pass->squareSize = pass->shader->getShaderConstHandle( "$squareSize" ); + mModelViewProjConst = mShader->getShaderConstHandle("$modelview"); + mWorldViewOnlyConst = mShader->getShaderConstHandle("$worldViewOnly"); + mViewToObjConst = mShader->getShaderConstHandle("$viewToObj"); + mEyePosWorldConst = mShader->getShaderConstHandle("$eyePosWorld"); + mEyePosConst = mShader->getShaderConstHandle("$eyePos"); + mVEyeConst = mShader->getShaderConstHandle("$vEye"); + mLayerSizeConst = mShader->getShaderConstHandle("$layerSize"); + mObjTransConst = mShader->getShaderConstHandle("$objTrans"); + mWorldToObjConst = mShader->getShaderConstHandle("$worldToObj"); + mLightInfoBufferConst = mShader->getShaderConstHandle("$lightInfoBuffer"); + mBaseTexMapConst = mShader->getShaderConstHandle("$baseTexMap"); + mLayerTexConst = mShader->getShaderConstHandle("$layerTex"); + mFogDataConst = mShader->getShaderConstHandle("$fogData"); + mFogColorConst = mShader->getShaderConstHandle("$fogColor"); + mLightMapTexConst = mShader->getShaderConstHandle("$lightMapTex"); + mOneOverTerrainSizeConst = mShader->getShaderConstHandle("$oneOverTerrainSize"); + mSquareSizeConst = mShader->getShaderConstHandle("$squareSize"); - pass->lightParamsConst = pass->shader->getShaderConstHandle( "$rtParamslightInfoBuffer" ); + mLightParamsConst = mShader->getShaderConstHandle("$rtParamslightInfoBuffer"); // Now prepare the basic stateblock. GFXStateBlockDesc desc; - if ( !firstPass ) - { - desc.setBlend( true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha ); - - // If this is the deferred then we don't want to - // write to the last two color channels (where - // depth is usually encoded). - // - // This trick works in combination with the - // MFT_TerrainAdditive feature to lerp the - // output normal with the previous pass. - // - if ( deferredMat ) - desc.setColorWrites( true, true, true, false ); - } // We write to the zbuffer if this is a deferred // material or if the deferred is disabled. - desc.setZReadWrite( true, !MATMGR->getDeferredEnabled() || - deferredMat || - reflectMat ); + desc.setZReadWrite(true, !MATMGR->getDeferredEnabled() || + deferredMat || + reflectMat); desc.samplersDefined = true; - if ( pass->baseTexMapConst->isValid() ) - desc.samplers[pass->baseTexMapConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear(); + if (mBaseTexMapConst->isValid()) + desc.samplers[mBaseTexMapConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear(); - if ( pass->layerTexConst->isValid() ) - desc.samplers[pass->layerTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint(); + if (mLayerTexConst->isValid()) + desc.samplers[mLayerTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint(); - if ( pass->lightInfoBufferConst->isValid() ) - desc.samplers[pass->lightInfoBufferConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint(); + if (mLightInfoBufferConst->isValid()) + desc.samplers[mLightInfoBufferConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint(); - if ( pass->lightMapTexConst->isValid() ) - desc.samplers[pass->lightMapTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear(); + if (mLightMapTexConst->isValid()) + desc.samplers[mLightMapTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear(); const U32 maxAnisotropy = MATMGR->getDefaultAnisotropy(); - // Finally setup the material specific shader - // constants and stateblock state. - // - // NOTE: If this changes be sure to check TerrainCellMaterial::_updateDefaultAnisotropy - // to see if it needs the same changes. - // - for ( U32 i=0; i < pass->materials.size(); i++ ) + mDetailInfoVArrayConst = mShader->getShaderConstHandle("$detailScaleAndFade"); + mDetailInfoPArrayConst = mShader->getShaderConstHandle("$detailIdStrengthParallax"); + mMacroInfoVArrayConst = mShader->getShaderConstHandle("$macroIdStrengthParallax"); + mMacroInfoPArrayConst = mShader->getShaderConstHandle("$macroIdStrengthParallax"); + + mDetailTexArrayConst = mShader->getShaderConstHandle("$detailMapSampler"); + if (mDetailTexArrayConst->isValid()) { - MaterialInfo *matInfo = pass->materials[i]; + const S32 sampler = mDetailTexArrayConst->getSamplerRegister(); - matInfo->detailInfoVConst = pass->shader->getShaderConstHandle( avar( "$detailScaleAndFade%d", i ) ); - matInfo->detailInfoPConst = pass->shader->getShaderConstHandle( avar( "$detailIdStrengthParallax%d", i ) ); + desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); + desc.samplers[sampler].magFilter = GFXTextureFilterLinear; + desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; - matInfo->detailTexConst = pass->shader->getShaderConstHandle( avar( "$detailMap%d", i ) ); - if ( matInfo->detailTexConst->isValid() ) + if (maxAnisotropy > 1) { - const S32 sampler = matInfo->detailTexConst->getSamplerRegister(); - - desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); - desc.samplers[sampler].magFilter = GFXTextureFilterLinear; - desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; - - if ( maxAnisotropy > 1 ) - { - desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; - desc.samplers[sampler].maxAnisotropy = maxAnisotropy; - } - else - desc.samplers[sampler].minFilter = GFXTextureFilterLinear; - - matInfo->detailTex.set( matInfo->mat->getDetailMap(), - &GFXStaticTextureProfile, "TerrainCellMaterial::_createPass() - DetailMap" ); - } - - matInfo->ormTexConst = pass->shader->getShaderConstHandle(avar("$ormConfigMap%d", i)); - if (matInfo->ormTexConst->isValid()) - { - GFXTextureProfile* profile = &GFXStaticTextureProfile; - if (matInfo->mat->getIsSRGB()) - profile = &GFXStaticTextureSRGBProfile; - - matInfo->ormTex.set(matInfo->mat->getORMConfigMap(), - profile, "TerrainCellMaterial::_createPass() - CompositeMap"); - const S32 sampler = matInfo->ormTexConst->getSamplerRegister(); - - desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); - desc.samplers[sampler].magFilter = GFXTextureFilterLinear; - desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; - - if (maxAnisotropy > 1) - { - desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; - desc.samplers[sampler].maxAnisotropy = maxAnisotropy; - } - else - desc.samplers[sampler].minFilter = GFXTextureFilterLinear; - } - - matInfo->macroInfoVConst = pass->shader->getShaderConstHandle( avar( "$macroScaleAndFade%d", i ) ); - matInfo->macroInfoPConst = pass->shader->getShaderConstHandle( avar( "$macroIdStrengthParallax%d", i ) ); - - matInfo->macroTexConst = pass->shader->getShaderConstHandle( avar( "$macroMap%d", i ) ); - if ( matInfo->macroTexConst->isValid() ) - { - const S32 sampler = matInfo->macroTexConst->getSamplerRegister(); - - desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); - desc.samplers[sampler].magFilter = GFXTextureFilterLinear; - desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; - - if ( maxAnisotropy > 1 ) - { - desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; - desc.samplers[sampler].maxAnisotropy = maxAnisotropy; - } - else - desc.samplers[sampler].minFilter = GFXTextureFilterLinear; - - matInfo->macroTex.set( matInfo->mat->getMacroMap(), - &GFXStaticTextureProfile, "TerrainCellMaterial::_createPass() - MacroMap" ); - } - //end macro texture - - matInfo->normalTexConst = pass->shader->getShaderConstHandle( avar( "$normalMap%d", i ) ); - if ( matInfo->normalTexConst->isValid() ) - { - const S32 sampler = matInfo->normalTexConst->getSamplerRegister(); - - desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); - desc.samplers[sampler].magFilter = GFXTextureFilterLinear; - desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; - - if ( maxAnisotropy > 1 ) - { - desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; - desc.samplers[sampler].maxAnisotropy = maxAnisotropy; - } - else - desc.samplers[sampler].minFilter = GFXTextureFilterLinear; - - matInfo->normalTex = normalMaps[i]; + desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; + desc.samplers[sampler].maxAnisotropy = maxAnisotropy; } + else + desc.samplers[sampler].minFilter = GFXTextureFilterLinear; } - // Remove the materials we processed and leave the - // ones that remain for the next pass. - for ( U32 i=0; i < matCount; i++ ) + mMacroTexArrayConst = mShader->getShaderConstHandle("$macroMapSampler"); + if (mMacroTexArrayConst->isValid()) { - MaterialInfo *matInfo = materials->first(); - if ( baseOnly || pass->materials.find_next( matInfo ) == -1 ) - delete matInfo; - materials->pop_front(); + const S32 sampler = mMacroTexArrayConst->getSamplerRegister(); + + desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); + desc.samplers[sampler].magFilter = GFXTextureFilterLinear; + desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; + + if (maxAnisotropy > 1) + { + desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; + desc.samplers[sampler].maxAnisotropy = maxAnisotropy; + } + else + desc.samplers[sampler].minFilter = GFXTextureFilterLinear; + } + + mNormalTexArrayConst = mShader->getShaderConstHandle("$normalMapSampler"); + if (mNormalTexArrayConst->isValid()) + { + const S32 sampler = mNormalTexArrayConst->getSamplerRegister(); + + desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); + desc.samplers[sampler].magFilter = GFXTextureFilterLinear; + desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; + + if (maxAnisotropy > 1) + { + desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; + desc.samplers[sampler].maxAnisotropy = maxAnisotropy; + } + else + desc.samplers[sampler].minFilter = GFXTextureFilterLinear; + } + + mOrmTexArrayConst = mShader->getShaderConstHandle("$ormMapSampler"); + if (mOrmTexArrayConst->isValid()) + { + GFXTextureProfile* profile = &GFXStaticTextureProfile; + + const S32 sampler = mOrmTexArrayConst->getSamplerRegister(); + + desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear(); + desc.samplers[sampler].magFilter = GFXTextureFilterLinear; + desc.samplers[sampler].mipFilter = GFXTextureFilterLinear; + + if (maxAnisotropy > 1) + { + desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic; + desc.samplers[sampler].maxAnisotropy = maxAnisotropy; + } + else + desc.samplers[sampler].minFilter = GFXTextureFilterLinear; } // If we're doing deferred it requires some @@ -726,28 +640,34 @@ bool TerrainCellMaterial::_createPass( Vector *materials, desc.addDesc( RenderDeferredMgr::getOpaqueStenciWriteDesc( false ) ); desc.setCullMode( GFXCullCCW ); - pass->stateBlock = GFX->createStateBlock(desc); + mStateBlock = GFX->createStateBlock(desc); //reflection stateblock desc.setCullMode( GFXCullCW ); - pass->reflectionStateBlock = GFX->createStateBlock(desc); + mReflectionStateBlock = GFX->createStateBlock(desc); // Create the wireframe state blocks. GFXStateBlockDesc wireframe( desc ); wireframe.fillMode = GFXFillWireframe; wireframe.setCullMode( GFXCullCCW ); - pass->wireframeStateBlock = GFX->createStateBlock( wireframe ); + mWireframeStateBlock = GFX->createStateBlock( wireframe ); return true; } -void TerrainCellMaterial::_updateMaterialConsts( Pass *pass ) +void TerrainCellMaterial::_updateMaterialConsts( ) { PROFILE_SCOPE( TerrainCellMaterial_UpdateMaterialConsts ); - - for ( U32 j=0; j < pass->materials.size(); j++ ) + if (mMaterialInfos.empty()) { - MaterialInfo *matInfo = pass->materials[j]; + return; + } + AlignedArray detailInfoArray(mMaterialInfos.size(), sizeof(Point4F)); + AlignedArray detailScaleAndFadeArray(mMaterialInfos.size(), sizeof(Point4F)); + + for ( U32 j=0; j < mMaterialInfos.size(); j++ ) + { + MaterialInfo *matInfo = mMaterialInfos[j]; F32 detailSize = matInfo->mat->getDetailSize(); F32 detailScale = 1.0f; @@ -775,38 +695,16 @@ void TerrainCellMaterial::_updateMaterialConsts( Pass *pass ) if ( !mIsZero( distance ) ) detailScaleAndFade.w = 1.0f / distance; - Point3F detailIdStrengthParallax( matInfo->layerId, + Point4F detailIdStrengthParallax( matInfo->layerId, matInfo->mat->getDetailStrength(), - matInfo->mat->getParallaxScale() ); + matInfo->mat->getParallaxScale(), 0 ); - pass->consts->setSafe( matInfo->detailInfoVConst, detailScaleAndFade ); - pass->consts->setSafe( matInfo->detailInfoPConst, detailIdStrengthParallax ); - - // macro texture info - - F32 macroSize = matInfo->mat->getMacroSize(); - F32 macroScale = 1.0f; - if ( !mIsZero( macroSize ) ) - macroScale = mTerrain->getWorldBlockSize() / macroSize; - - // Scale the distance by the global scalar. - const F32 macroDistance = mTerrain->smDetailScale * matInfo->mat->getMacroDistance(); - - Point4F macroScaleAndFade( macroScale, - -macroScale, - macroDistance, - 0 ); - - if ( !mIsZero( macroDistance ) ) - macroScaleAndFade.w = 1.0f / macroDistance; - - Point3F macroIdStrengthParallax( matInfo->layerId, - matInfo->mat->getMacroStrength(), - 0 ); - - pass->consts->setSafe( matInfo->macroInfoVConst, macroScaleAndFade ); - pass->consts->setSafe( matInfo->macroInfoPConst, macroIdStrengthParallax ); + detailScaleAndFadeArray[j] = detailScaleAndFade; + detailInfoArray[j] = detailIdStrengthParallax; } + + mConsts->setSafe(mDetailInfoVArrayConst, detailScaleAndFadeArray); + mConsts->setSafe(mDetailInfoPArrayConst, detailInfoArray); } bool TerrainCellMaterial::setupPass( const SceneRenderState *state, @@ -814,80 +712,80 @@ bool TerrainCellMaterial::setupPass( const SceneRenderState *state, { PROFILE_SCOPE( TerrainCellMaterial_SetupPass ); - if ( mCurrPass >= mPasses.size() ) + if (mCurrPass > 0) { mCurrPass = 0; return false; } - Pass &pass = mPasses[mCurrPass]; + if (mMaterialInfos.size() > 4) + { + int a = 2 + 2; + } - _updateMaterialConsts( &pass ); + mCurrPass++; - if ( pass.baseTexMapConst->isValid() ) - GFX->setTexture( pass.baseTexMapConst->getSamplerRegister(), mTerrain->mBaseTex.getPointer() ); + _updateMaterialConsts(); - if ( pass.layerTexConst->isValid() ) - GFX->setTexture( pass.layerTexConst->getSamplerRegister(), mTerrain->mLayerTex.getPointer() ); + if ( mBaseTexMapConst->isValid() ) + GFX->setTexture( mBaseTexMapConst->getSamplerRegister(), mTerrain->mBaseTex.getPointer() ); - if ( pass.lightMapTexConst->isValid() ) - GFX->setTexture( pass.lightMapTexConst->getSamplerRegister(), mTerrain->getLightMapTex() ); + if ( mLayerTexConst->isValid() ) + GFX->setTexture( mLayerTexConst->getSamplerRegister(), mTerrain->mLayerTex.getPointer() ); + + if ( mLightMapTexConst->isValid() ) + GFX->setTexture( mLightMapTexConst->getSamplerRegister(), mTerrain->getLightMapTex() ); if ( sceneData.wireframe ) - GFX->setStateBlock( pass.wireframeStateBlock ); + GFX->setStateBlock( mWireframeStateBlock ); else if ( state->isReflectPass( )) - GFX->setStateBlock( pass.reflectionStateBlock ); + GFX->setStateBlock( mReflectionStateBlock ); else - GFX->setStateBlock( pass.stateBlock ); + GFX->setStateBlock( mStateBlock ); - GFX->setShader( pass.shader ); - GFX->setShaderConstBuffer( pass.consts ); + GFX->setShader( mShader ); + GFX->setShaderConstBuffer( mConsts ); // Let the light manager prepare any light stuff it needs. LIGHTMGR->setLightInfo( NULL, NULL, sceneData, state, - mCurrPass, - pass.consts ); + 0, + mConsts ); - for ( U32 i=0; i < pass.materials.size(); i++ ) - { - MaterialInfo *matInfo = pass.materials[i]; + if (mDetailTexArrayConst->isValid()) + GFX->setTextureArray(mDetailTexArrayConst->getSamplerRegister(), mTerrain->getDetailTextureArray()); + if (mMacroTexArrayConst->isValid()) + GFX->setTextureArray(mMacroTexArrayConst->getSamplerRegister(), mTerrain->getMacroTextureArray()); + if (mNormalTexArrayConst->isValid()) + GFX->setTextureArray(mNormalTexArrayConst->getSamplerRegister(), mTerrain->getNormalTextureArray()); + if (mOrmTexArrayConst->isValid()) + GFX->setTextureArray(mOrmTexArrayConst->getSamplerRegister(), mTerrain->getOrmTextureArray()); - if ( matInfo->detailTexConst->isValid() ) - GFX->setTexture( matInfo->detailTexConst->getSamplerRegister(), matInfo->detailTex ); - if ( matInfo->macroTexConst->isValid() ) - GFX->setTexture( matInfo->macroTexConst->getSamplerRegister(), matInfo->macroTex ); - if ( matInfo->normalTexConst->isValid() ) - GFX->setTexture( matInfo->normalTexConst->getSamplerRegister(), matInfo->normalTex ); - if ( matInfo->ormTexConst->isValid() ) - GFX->setTexture( matInfo->ormTexConst->getSamplerRegister(), matInfo->ormTex ); - } + mConsts->setSafe( mLayerSizeConst, (F32)mTerrain->mLayerTex.getWidth() ); - pass.consts->setSafe( pass.layerSizeConst, (F32)mTerrain->mLayerTex.getWidth() ); - - if ( pass.oneOverTerrainSize->isValid() ) + if ( mOneOverTerrainSizeConst->isValid() ) { F32 oneOverTerrainSize = 1.0f / mTerrain->getWorldBlockSize(); - pass.consts->set( pass.oneOverTerrainSize, oneOverTerrainSize ); + mConsts->set( mOneOverTerrainSizeConst, oneOverTerrainSize ); } - pass.consts->setSafe( pass.squareSize, mTerrain->getSquareSize() ); + mConsts->setSafe( mSquareSizeConst, mTerrain->getSquareSize() ); - if ( pass.fogDataConst->isValid() ) + if ( mFogDataConst->isValid() ) { Point3F fogData; fogData.x = sceneData.fogDensity; fogData.y = sceneData.fogDensityOffset; fogData.z = sceneData.fogHeightFalloff; - pass.consts->set( pass.fogDataConst, fogData ); + mConsts->set( mFogDataConst, fogData ); } - pass.consts->setSafe( pass.fogColorConst, sceneData.fogColor ); + mConsts->setSafe( mFogColorConst, sceneData.fogColor ); - if ( pass.lightInfoBufferConst->isValid() && - pass.lightParamsConst->isValid() ) + if ( mLightInfoBufferConst->isValid() && + mLightParamsConst->isValid() ) { if ( !mLightInfoTarget ) mLightInfoTarget = NamedTexTarget::find( "diffuseLighting" ); @@ -900,17 +798,16 @@ bool TerrainCellMaterial::setupPass( const SceneRenderState *state, if ( texObject ) { - GFX->setTexture( pass.lightInfoBufferConst->getSamplerRegister(), texObject ); + GFX->setTexture( mLightInfoBufferConst->getSamplerRegister(), texObject ); const Point3I &targetSz = texObject->getSize(); const RectI &targetVp = mLightInfoTarget->getViewport(); Point4F rtParams; ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams); - pass.consts->setSafe( pass.lightParamsConst, rtParams ); + mConsts->setSafe( mLightParamsConst, rtParams ); } } - ++mCurrPass; return true; } diff --git a/Engine/source/terrain/terrCellMaterial.h b/Engine/source/terrain/terrCellMaterial.h index 91d1f40e3..c73e3ba56 100644 --- a/Engine/source/terrain/terrCellMaterial.h +++ b/Engine/source/terrain/terrCellMaterial.h @@ -40,6 +40,7 @@ #endif +class GFXTextureArray; class SceneRenderState; struct SceneData; class TerrainMaterial; @@ -58,8 +59,7 @@ protected: public: MaterialInfo() - :mat(NULL), layerId(0), detailTexConst(NULL), macroTexConst(NULL), normalTexConst(NULL), - ormTexConst(NULL), detailInfoVConst(NULL), detailInfoPConst(NULL), macroInfoVConst(NULL), macroInfoPConst(NULL) + :mat(NULL), layerId(0) { } @@ -69,95 +69,60 @@ protected: TerrainMaterial *mat; U32 layerId; - - GFXShaderConstHandle *detailTexConst; - GFXTexHandle detailTex; - - GFXShaderConstHandle *macroTexConst; - GFXTexHandle macroTex; - - GFXShaderConstHandle *normalTexConst; - GFXTexHandle normalTex; - - GFXShaderConstHandle *ormTexConst; - GFXTexHandle ormTex; - - GFXShaderConstHandle *detailInfoVConst; - GFXShaderConstHandle *detailInfoPConst; - - GFXShaderConstHandle *macroInfoVConst; - GFXShaderConstHandle *macroInfoPConst; }; - class Pass - { - public: + /// + GFXShader *mShader; - Pass() - : shader( NULL ), - modelViewProjConst(NULL), worldViewOnly(NULL), viewToObj(NULL), - eyePosWorldConst(NULL), eyePosConst(NULL), - objTransConst(NULL), worldToObjConst(NULL), vEyeConst(NULL), - layerSizeConst(NULL), lightParamsConst(NULL), lightInfoBufferConst(NULL), - baseTexMapConst(NULL), layerTexConst(NULL), - lightMapTexConst(NULL), - squareSize(NULL), oneOverTerrainSize(NULL), - fogDataConst(NULL), fogColorConst(NULL) - { - } + GFXShaderConstBufferRef mConsts; - ~Pass() - { - for ( U32 i=0; i < materials.size(); i++ ) - delete materials[i]; - } + GFXStateBlockRef mStateBlock; + GFXStateBlockRef mWireframeStateBlock; + GFXStateBlockRef mReflectionStateBlock; - Vector materials; + GFXShaderConstHandle *mModelViewProjConst; + GFXShaderConstHandle *mWorldViewOnlyConst; + GFXShaderConstHandle *mViewToObjConst; - /// - GFXShader *shader; + GFXShaderConstHandle *mEyePosWorldConst; + GFXShaderConstHandle *mEyePosConst; - GFXShaderConstBufferRef consts; + GFXShaderConstHandle *mObjTransConst; + GFXShaderConstHandle *mWorldToObjConst; + GFXShaderConstHandle *mVEyeConst; - GFXStateBlockRef stateBlock; - GFXStateBlockRef wireframeStateBlock; - GFXStateBlockRef reflectionStateBlock; + GFXShaderConstHandle *mLayerSizeConst; + GFXShaderConstHandle *mLightParamsConst; + GFXShaderConstHandle *mLightInfoBufferConst; - GFXShaderConstHandle *modelViewProjConst; - GFXShaderConstHandle *worldViewOnly; - GFXShaderConstHandle *viewToObj; + GFXShaderConstHandle *mBaseTexMapConst; + GFXShaderConstHandle *mLayerTexConst; - GFXShaderConstHandle *eyePosWorldConst; - GFXShaderConstHandle *eyePosConst; + GFXShaderConstHandle *mLightMapTexConst; - GFXShaderConstHandle *objTransConst; - GFXShaderConstHandle *worldToObjConst; - GFXShaderConstHandle *vEyeConst; + GFXShaderConstHandle *mSquareSizeConst; + GFXShaderConstHandle *mOneOverTerrainSizeConst; - GFXShaderConstHandle *layerSizeConst; - GFXShaderConstHandle *lightParamsConst; - GFXShaderConstHandle *lightInfoBufferConst; + GFXShaderConstHandle* mDetailInfoVArrayConst; + GFXShaderConstHandle* mDetailInfoPArrayConst; + GFXShaderConstHandle* mMacroInfoVArrayConst; + GFXShaderConstHandle* mMacroInfoPArrayConst; - GFXShaderConstHandle *baseTexMapConst; - GFXShaderConstHandle *layerTexConst; + GFXShaderConstHandle *mFogDataConst; + GFXShaderConstHandle *mFogColorConst; - GFXShaderConstHandle *lightMapTexConst; - - GFXShaderConstHandle *squareSize; - GFXShaderConstHandle *oneOverTerrainSize; - - GFXShaderConstHandle *fogDataConst; - GFXShaderConstHandle *fogColorConst; - }; + GFXShaderConstHandle *mDetailTexArrayConst; + GFXShaderConstHandle *mMacroTexArrayConst; + GFXShaderConstHandle *mNormalTexArrayConst; + GFXShaderConstHandle *mOrmTexArrayConst; TerrainBlock *mTerrain; - U64 mMaterials; - - Vector mPasses; - U32 mCurrPass; + U64 mMaterials; + Vector mMaterialInfos; + static const Vector mSamplerNames; GFXTexHandle mBaseMapTexture; @@ -175,14 +140,11 @@ protected: /// A vector of all terrain cell materials loaded in the system. static Vector smAllMaterials; - bool _createPass( Vector *materials, - Pass *pass, - bool firstPass, - bool deferredMat, + bool _initShader( bool deferredMat, bool reflectMat, bool baseOnly ); - void _updateMaterialConsts( Pass *pass ); + void _updateMaterialConsts(); public: diff --git a/Engine/source/terrain/terrData.cpp b/Engine/source/terrain/terrData.cpp index dc7f44e76..be29ec7c9 100644 --- a/Engine/source/terrain/terrData.cpp +++ b/Engine/source/terrain/terrData.cpp @@ -52,6 +52,7 @@ #include "T3D/physics/physicsBody.h" #include "T3D/physics/physicsCollision.h" #include "console/engineAPI.h" +#include "core/util/safeRelease.h" #include "T3D/assets/TerrainMaterialAsset.h" using namespace Torque; @@ -203,7 +204,11 @@ TerrainBlock::TerrainBlock() mScreenError( 16 ), mCastShadows( true ), mZoningDirty( false ), - mUpdateBasetex ( true ) + mUpdateBasetex ( true ), + mDetailTextureArray( NULL ), + mMacroTextureArray( NULL ), + mOrmTextureArray( NULL ), + mNormalTextureArray( NULL ) { mTypeMask = TerrainObjectType | StaticObjectType | StaticShapeObjectType; mNetFlags.set(Ghostable | ScopeAlways); @@ -231,6 +236,11 @@ TerrainBlock::~TerrainBlock() editor->detachTerrain(this); #endif deleteZodiacPrimitiveBuffer(); + + SAFE_RELEASE(mDetailTextureArray); + SAFE_RELEASE(mMacroTextureArray); + SAFE_RELEASE(mNormalTextureArray); + SAFE_RELEASE(mOrmTextureArray); } void TerrainBlock::_onTextureEvent( GFXTexCallbackCode code ) diff --git a/Engine/source/terrain/terrData.h b/Engine/source/terrain/terrData.h index 021a11dae..68521a166 100644 --- a/Engine/source/terrain/terrData.h +++ b/Engine/source/terrain/terrData.h @@ -135,6 +135,11 @@ protected: /// Vector mBaseTextures; + GFXTextureArray* mDetailTextureArray; + GFXTextureArray* mMacroTextureArray; + GFXTextureArray* mNormalTextureArray; + GFXTextureArray* mOrmTextureArray; + /// GFXTexHandle mLayerTex; @@ -324,6 +329,11 @@ public: U32 getMaterialCount() const; + GFXTextureArray* getDetailTextureArray() const { return mDetailTextureArray; } + GFXTextureArray* getMacroTextureArray() const { return mMacroTextureArray; } + GFXTextureArray* getNormalTextureArray() const { return mNormalTextureArray; } + GFXTextureArray* getOrmTextureArray() const { return mOrmTextureArray; } + //BaseMatInstance* getMaterialInst( U32 x, U32 y ); void setHeight( const Point2I &pos, F32 height ); diff --git a/Engine/source/terrain/terrRender.cpp b/Engine/source/terrain/terrRender.cpp index d75196778..745a06219 100644 --- a/Engine/source/terrain/terrRender.cpp +++ b/Engine/source/terrain/terrRender.cpp @@ -96,7 +96,7 @@ void TerrainBlock::_updateMaterials() { TerrainMaterial *mat = mFile->mMaterials[i]; - if (!mat->getDiffuseMap().isEmpty()) + if (mat->getDiffuseMap().isNotEmpty()) { mBaseTextures[i].set(mat->getDiffuseMap(), &GFXStaticTextureSRGBProfile, "TerrainBlock::_updateMaterials() - DiffuseMap"); @@ -114,6 +114,63 @@ void TerrainBlock::_updateMaterials() mMaxDetailDistance = mat->getMacroDistance(); } + Vector detailTexArray; + detailTexArray.setSize(mFile->mMaterials.size()); + Vector macroTexArray; + macroTexArray.setSize(mFile->mMaterials.size()); + Vector normalTexArray; + normalTexArray.setSize(mFile->mMaterials.size()); + Vector ormTexArray; + ormTexArray.setSize(mFile->mMaterials.size()); + + for (U32 i = 0; i < mFile->mMaterials.size(); i++) + { + TerrainMaterial* mat = mFile->mMaterials[i]; + GFXTextureProfile* profile = &GFXStaticTextureProfile; + if (mat->getIsSRGB()) + profile = &GFXStaticTextureSRGBProfile; + + if (mat->getDetailMap().isNotEmpty()) + detailTexArray[i] = TEXMGR->createTexture(mat->getDetailMap(), profile); + if (mat->getMacroMap().isNotEmpty()) + macroTexArray[i] = TEXMGR->createTexture(mat->getMacroMap(), profile); + if (mat->getNormalMap().isNotEmpty()) + normalTexArray[i] = TEXMGR->createTexture(mat->getNormalMap(), profile); + if (mat->getORMConfigMap().isNotEmpty()) + ormTexArray[i] = TEXMGR->createTexture(mat->getORMConfigMap(), profile); + } + + mDetailTextureArray = NULL; + mMacroTextureArray = NULL; + mNormalTextureArray = NULL; + mOrmTextureArray = NULL; + + + mDetailTextureArray = GFX->createTextureArray(); + mMacroTextureArray = GFX->createTextureArray(); + mNormalTextureArray = GFX->createTextureArray(); + mOrmTextureArray = GFX->createTextureArray(); + + if(!mDetailTextureArray->fromTextureArray(detailTexArray)) + { + Con::errorf("TerrainBlock::_updateMaterials - an issue with the diffuse terrain materials was detected. Please ensure they are all of the same size and format!"); + } + + if(!mMacroTextureArray->fromTextureArray(macroTexArray)) + { + Con::errorf("TerrainBlock::_updateMaterials - an issue with the detail terrain materials was detected. Please ensure they are all of the same size and format!"); + } + + if(!mNormalTextureArray->fromTextureArray(normalTexArray)) + { + Con::errorf("TerrainBlock::_updateMaterials - an issue with the normal terrain materials was detected. Please ensure they are all of the same size and format!"); + } + + if(!mOrmTextureArray->fromTextureArray(ormTexArray)) + { + Con::errorf("TerrainBlock::_updateMaterials - an issue with the orm terrain materials was detected. Please ensure they are all of the same size and format!"); + } + if ( mCell ) mCell->deleteMaterials(); }