diff --git a/Engine/source/gfx/D3D11/gfxD3D11Device.cpp b/Engine/source/gfx/D3D11/gfxD3D11Device.cpp index 7c83d098b..6e937bc34 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Device.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11Device.cpp @@ -105,6 +105,7 @@ GFXD3D11Device::GFXD3D11Device(U32 index) mLastVertShader = NULL; mLastPixShader = NULL; + mLastGeoShader = NULL; mCanCurrentlyRender = false; mTextureManager = NULL; @@ -159,6 +160,11 @@ GFXD3D11Device::~GFXD3D11Device() for (; sampIter != mSamplersMap.end(); ++sampIter) SAFE_RELEASE(sampIter->value); + // Free device buffers + DeviceBufferMap::Iterator bufferIter = mDeviceBufferMap.begin(); + for (; bufferIter != mDeviceBufferMap.end(); ++bufferIter) + SAFE_RELEASE(bufferIter->value); + // Free the vertex declarations. VertexDeclMap::Iterator iter = mVertexDecls.begin(); for (; iter != mVertexDecls.end(); ++iter) @@ -202,7 +208,7 @@ GFXFormat GFXD3D11Device::selectSupportedFormat(GFXTextureProfile *profile, cons features |= D3D11_FORMAT_SUPPORT_BLENDABLE; if(mustfilter) features |= D3D11_FORMAT_SUPPORT_SHADER_SAMPLE; - + for(U32 i = 0; i < formats.size(); i++) { if(GFXD3D11TextureFormat[formats[i]] == DXGI_FORMAT_UNKNOWN) @@ -213,7 +219,7 @@ GFXFormat GFXD3D11Device::selectSupportedFormat(GFXTextureProfile *profile, cons if(supportFlag & features) return formats[i]; } - + return GFXFormatR8G8B8A8; } @@ -261,7 +267,7 @@ void GFXD3D11Device::enumerateAdapters(Vector &adapterList) CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast(&DXGIFactory)); - for(U32 adapterIndex = 0; DXGIFactory->EnumAdapters1(adapterIndex, &EnumAdapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) + for(U32 adapterIndex = 0; DXGIFactory->EnumAdapters1(adapterIndex, &EnumAdapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) { GFXAdapter *toAdd = new GFXAdapter; toAdd->mType = Direct3D11; @@ -286,7 +292,7 @@ void GFXD3D11Device::enumerateAdapters(Vector &adapterList) dStrncpy(toAdd->mName, Description.c_str(), GFXAdapter::MaxAdapterNameLen); dStrncat(toAdd->mName, " (D3D11)", sizeof(toAdd->mName) - strlen(toAdd->mName) - 1); - IDXGIOutput* pOutput = NULL; + IDXGIOutput* pOutput = NULL; HRESULT hr; hr = EnumAdapter->EnumOutputs(adapterIndex, &pOutput); @@ -310,7 +316,7 @@ void GFXD3D11Device::enumerateAdapters(Vector &adapterList) if(FAILED(hr)) AssertFatal(false, "GFXD3D11Device::enumerateAdapters -> GetDisplayModeList call failure"); - displayModes = new DXGI_MODE_DESC[numModes]; + displayModes = new DXGI_MODE_DESC[numModes]; // Get the list hr = pOutput->GetDisplayModeList(format, 0, &numModes, displayModes); @@ -376,7 +382,7 @@ void GFXD3D11Device::enumerateAdapters(Vector &adapterList) SAFE_RELEASE(DXGIFactory); } -void GFXD3D11Device::enumerateVideoModes() +void GFXD3D11Device::enumerateVideoModes() { mVideoModes.clear(); @@ -389,9 +395,9 @@ void GFXD3D11Device::enumerateVideoModes() if (FAILED(hr)) AssertFatal(false, "GFXD3D11Device::enumerateVideoModes -> CreateDXGIFactory1 call failure"); - for(U32 adapterIndex = 0; DXGIFactory->EnumAdapters1(adapterIndex, &EnumAdapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) + for(U32 adapterIndex = 0; DXGIFactory->EnumAdapters1(adapterIndex, &EnumAdapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) { - IDXGIOutput* pOutput = NULL; + IDXGIOutput* pOutput = NULL; hr = EnumAdapter->EnumOutputs(adapterIndex, &pOutput); @@ -414,7 +420,7 @@ void GFXD3D11Device::enumerateVideoModes() if(FAILED(hr)) AssertFatal(false, "GFXD3D11Device::enumerateVideoModes -> GetDisplayModeList call failure"); - displayModes = new DXGI_MODE_DESC[numModes]; + displayModes = new DXGI_MODE_DESC[numModes]; // Get the list hr = pOutput->GetDisplayModeList(format, 0, &numModes, displayModes); @@ -519,14 +525,16 @@ void GFXD3D11Device::init(const GFXVideoMode &mode, PlatformWindow *window) { case D3D_FEATURE_LEVEL_11_1: case D3D_FEATURE_LEVEL_11_0: - mVertexShaderTarget = "vs_5_0"; - mPixelShaderTarget = "ps_5_0"; + mVertexShaderTarget = "vs_5_0"; + mPixelShaderTarget = "ps_5_0"; + mGeometryShaderTarget = "gs_5_0"; mPixVersion = 5.0f; mShaderModel = "50"; break; case D3D_FEATURE_LEVEL_10_1: - mVertexShaderTarget = "vs_4_1"; - mPixelShaderTarget = "ps_4_1"; + mVertexShaderTarget = "vs_4_1"; + mPixelShaderTarget = "ps_4_1"; + mGeometryShaderTarget = "gs_4_1"; mPixVersion = 4.1f; mShaderModel = "41"; break; @@ -546,7 +554,7 @@ void GFXD3D11Device::init(const GFXVideoMode &mode, PlatformWindow *window) SAFE_RELEASE(testQuery); Con::printf("Hardware occlusion query detected: %s", mOcclusionQuerySupported ? "Yes" : "No"); - + mCardProfiler = new GFXD3D11CardProfiler(); mCardProfiler->init(); @@ -589,10 +597,10 @@ void GFXD3D11Device::_suppressDebugMessages() } } -bool GFXD3D11Device::beginSceneInternal() +bool GFXD3D11Device::beginSceneInternal() { mCanCurrentlyRender = true; - return mCanCurrentlyRender; + return mCanCurrentlyRender; } GFXWindowTarget * GFXD3D11Device::allocWindowTarget(PlatformWindow *window) @@ -739,7 +747,7 @@ void GFXD3D11Device::setupGenericShaders(GenericShaderType type) _updateRenderTargets(); } - MatrixF tempMatrix = mProjectionMatrix * mViewMatrix * mWorldMatrix[mWorldStackSize]; + MatrixF tempMatrix = mProjectionMatrix * mViewMatrix * mWorldMatrix[mWorldStackSize]; mGenericShaderBuffer[type]->setSafe(mModelViewProjSC[type], tempMatrix); setShader(mGenericShader[type]); @@ -764,7 +772,7 @@ void GFXD3D11Device::setStateBlockInternal(GFXStateBlock* block, bool force) if (force) d3dCurrent = NULL; - d3dBlock->activate(d3dCurrent); + d3dBlock->activate(d3dCurrent); } /// Called by base GFXDevice to actually set a const buffer @@ -863,7 +871,7 @@ void GFXD3D11Device::clearColorAttachment(const U32 attachment, const LinearColo mD3DDeviceContext->ClearRenderTargetView(rtView, clearColor); } -void GFXD3D11Device::endSceneInternal() +void GFXD3D11Device::endSceneInternal() { mCanCurrentlyRender = false; } @@ -875,7 +883,7 @@ void GFXD3D11Device::_updateRenderTargets() if (mRTDeactivate) { mRTDeactivate->deactivate(); - mRTDeactivate = NULL; + mRTDeactivate = NULL; } // NOTE: The render target changes are not really accurate @@ -887,7 +895,7 @@ void GFXD3D11Device::_updateRenderTargets() mCurrentRT->activate(); mRTDirty = false; - } + } if (mViewportDirty) { @@ -906,7 +914,7 @@ void GFXD3D11Device::_updateRenderTargets() } } -void GFXD3D11Device::releaseDefaultPoolResources() +void GFXD3D11Device::releaseDefaultPoolResources() { // Release all the dynamic vertex buffer arrays // Forcibly clean up the pools @@ -919,7 +927,7 @@ void GFXD3D11Device::releaseDefaultPoolResources() // We gotta clear the current const buffer else the next // activate may erroneously think the device is still holding - // this state and fail to set it. + // this state and fail to set it. mCurrentConstBuffer = NULL; // Set current VB to NULL and set state dirty @@ -943,7 +951,7 @@ void GFXD3D11Device::releaseDefaultPoolResources() mPrimitiveBufferDirty = true; // Zombify texture manager (for D3D this only modifies default pool textures) - if( mTextureManager ) + if( mTextureManager ) mTextureManager->zombify(); // Set global dirty state so the IB/PB and VB get reset @@ -958,7 +966,7 @@ void GFXD3D11Device::releaseDefaultPoolResources() } } -void GFXD3D11Device::reacquireDefaultPoolResources() +void GFXD3D11Device::reacquireDefaultPoolResources() { // Now do the dynamic index buffers if( mDynamicPB == NULL ) @@ -974,7 +982,7 @@ void GFXD3D11Device::reacquireDefaultPoolResources() HRESULT hr = D3D11DEVICE->CreateBuffer(&desc, NULL, &mDynamicPB->ib); - if(FAILED(hr)) + if(FAILED(hr)) { AssertFatal(false, "Failed to allocate dynamic IB"); } @@ -1020,7 +1028,7 @@ GFXD3D11VertexBuffer * GFXD3D11Device::createVBPool( const GFXVertexFormat *vert newBuff->mDevice = this; // Requesting it will allocate it. - vertexFormat->getDecl(); + vertexFormat->getDecl(); D3D11_BUFFER_DESC desc; desc.ByteWidth = vertSize * GFX_MAX_DYNAMIC_VERTS; @@ -1032,7 +1040,7 @@ GFXD3D11VertexBuffer * GFXD3D11Device::createVBPool( const GFXVertexFormat *vert HRESULT hr = D3D11DEVICE->CreateBuffer(&desc, NULL, &newBuff->vb); - if(FAILED(hr)) + if(FAILED(hr)) { AssertFatal(false, "Failed to allocate dynamic VB"); } @@ -1042,9 +1050,9 @@ GFXD3D11VertexBuffer * GFXD3D11Device::createVBPool( const GFXVertexFormat *vert //----------------------------------------------------------------------------- -void GFXD3D11Device::setClipRect( const RectI &inRect ) +void GFXD3D11Device::setClipRect( const RectI &inRect ) { - // We transform the incoming rect by the view + // We transform the incoming rect by the view // matrix first, so that it can be used to pan // and scale the clip rect. // @@ -1052,7 +1060,7 @@ void GFXD3D11Device::setClipRect( const RectI &inRect ) Point3F pos( inRect.point.x, inRect.point.y, 0.0f ); Point3F extent( inRect.extent.x, inRect.extent.y, 0.0f ); getViewMatrix().mulP( pos ); - getViewMatrix().mulV( extent ); + getViewMatrix().mulV( extent ); RectI rect( pos.x, pos.y, extent.x, extent.y ); // Clip the rect against the renderable size. @@ -1068,8 +1076,8 @@ void GFXD3D11Device::setClipRect( const RectI &inRect ) F32 b = F32( mClipRect.point.y + mClipRect.extent.y ); F32 t = F32( mClipRect.point.y ); - // Set up projection matrix, - static Point4F pt; + // Set up projection matrix, + static Point4F pt; pt.set(2.0f / (r - l), 0.0f, 0.0f, 0.0f); mTempMatrix.setColumn(0, pt); @@ -1085,7 +1093,7 @@ void GFXD3D11Device::setClipRect( const RectI &inRect ) setProjectionMatrix( mTempMatrix ); // Set up world/view matrix - mTempMatrix.identity(); + mTempMatrix.identity(); setWorldMatrix( mTempMatrix ); setViewport( mClipRect ); @@ -1097,7 +1105,7 @@ void GFXD3D11Device::setVertexStream( U32 stream, GFXVertexBuffer *buffer ) if ( stream == 0 ) { - // Set the volatile buffer which is used to + // Set the volatile buffer which is used to // offset the start index when doing draw calls. if ( d3dBuffer && d3dBuffer->mVolatileStart > 0 ) mVolatileVB = d3dBuffer; @@ -1106,7 +1114,7 @@ void GFXD3D11Device::setVertexStream( U32 stream, GFXVertexBuffer *buffer ) } // NOTE: We do not use the stream offset here for stream 0 - // as that feature is *supposedly* not as well supported as + // as that feature is *supposedly* not as well supported as // using the start index in drawPrimitive. // // If we can verify that this is not the case then we should @@ -1125,7 +1133,7 @@ void GFXD3D11Device::setVertexStreamFrequency( U32 stream, U32 frequency ) mDrawInstancesCount = frequency; // instances count } -void GFXD3D11Device::_setPrimitiveBuffer( GFXPrimitiveBuffer *buffer ) +void GFXD3D11Device::_setPrimitiveBuffer( GFXPrimitiveBuffer *buffer ) { mCurrentPB = static_cast( buffer ); @@ -1160,7 +1168,7 @@ U32 GFXD3D11Device::primCountToIndexCount(GFXPrimitiveType primType, U32 primiti } -void GFXD3D11Device::drawPrimitive( GFXPrimitiveType primType, U32 vertexStart, U32 primitiveCount ) +void GFXD3D11Device::drawPrimitive( GFXPrimitiveType primType, U32 vertexStart, U32 primitiveCount ) { // This is done to avoid the function call overhead if possible if( mStateDirty ) @@ -1172,12 +1180,12 @@ void GFXD3D11Device::drawPrimitive( GFXPrimitiveType primType, U32 vertexStart, vertexStart += mVolatileVB->mVolatileStart; mD3DDeviceContext->IASetPrimitiveTopology(GFXD3D11PrimType[primType]); - + if ( mDrawInstancesCount ) mD3DDeviceContext->DrawInstanced(primCountToIndexCount(primType, primitiveCount), mDrawInstancesCount, vertexStart, 0); else mD3DDeviceContext->Draw(primCountToIndexCount(primType, primitiveCount), vertexStart); - + mDeviceStatistics.mDrawCalls++; if ( mVertexBufferFrequency[0] > 1 ) mDeviceStatistics.mPolyCount += primitiveCount * mVertexBufferFrequency[0]; @@ -1185,12 +1193,12 @@ void GFXD3D11Device::drawPrimitive( GFXPrimitiveType primType, U32 vertexStart, mDeviceStatistics.mPolyCount += primitiveCount; } -void GFXD3D11Device::drawIndexedPrimitive( GFXPrimitiveType primType, - U32 startVertex, - U32 minIndex, - U32 numVerts, - U32 startIndex, - U32 primitiveCount ) +void GFXD3D11Device::drawIndexedPrimitive( GFXPrimitiveType primType, + U32 startVertex, + U32 minIndex, + U32 numVerts, + U32 startIndex, + U32 primitiveCount ) { // This is done to avoid the function call overhead if possible if( mStateDirty ) @@ -1204,11 +1212,11 @@ void GFXD3D11Device::drawIndexedPrimitive( GFXPrimitiveType primType, startVertex += mVolatileVB->mVolatileStart; mD3DDeviceContext->IASetPrimitiveTopology(GFXD3D11PrimType[primType]); - + if ( mDrawInstancesCount ) mD3DDeviceContext->DrawIndexedInstanced(primCountToIndexCount(primType, primitiveCount), mDrawInstancesCount, mCurrentPB->mVolatileStart + startIndex, startVertex, 0); else - mD3DDeviceContext->DrawIndexed(primCountToIndexCount(primType,primitiveCount), mCurrentPB->mVolatileStart + startIndex, startVertex); + mD3DDeviceContext->DrawIndexed(primCountToIndexCount(primType,primitiveCount), mCurrentPB->mVolatileStart + startIndex, startVertex); mDeviceStatistics.mDrawCalls++; if ( mVertexBufferFrequency[0] > 1 ) @@ -1245,7 +1253,13 @@ void GFXD3D11Device::setShader(GFXShader *shader, bool force) { mD3DDeviceContext->VSSetShader( d3dShader->mVertShader, NULL, 0); mLastVertShader = d3dShader->mVertShader; - } + } + + if (d3dShader->mGeoShader != mLastGeoShader || force) + { + mD3DDeviceContext->GSSetShader(d3dShader->mGeoShader, NULL, 0); + mLastGeoShader = d3dShader->mGeoShader; + } } else { @@ -1308,7 +1322,7 @@ GFXPrimitiveBuffer * GFXD3D11Device::allocPrimitiveBuffer(U32 numIndices, U32 nu HRESULT hr = D3D11DEVICE->CreateBuffer(&desc, NULL, &res->ib); - if(FAILED(hr)) + if(FAILED(hr)) { AssertFatal(false, "Failed to allocate an index buffer."); } @@ -1329,12 +1343,12 @@ GFXVertexBuffer * GFXD3D11Device::allocVertexBuffer(U32 numVerts, const GFXVerte { PROFILE_SCOPE( GFXD3D11Device_allocVertexBuffer ); - GFXD3D11VertexBuffer *res = new GFXD3D11VertexBuffer( this, - numVerts, - vertexFormat, - vertSize, + GFXD3D11VertexBuffer *res = new GFXD3D11VertexBuffer( this, + numVerts, + vertexFormat, + vertSize, bufferType ); - + // Determine usage flags D3D11_USAGE usage = D3D11_USAGE_DEFAULT; @@ -1387,7 +1401,7 @@ GFXVertexBuffer * GFXD3D11Device::allocVertexBuffer(U32 numVerts, const GFXVerte HRESULT hr = D3D11DEVICE->CreateBuffer(&desc, NULL, &res->vb); - if(FAILED(hr)) + if(FAILED(hr)) { AssertFatal(false, "Failed to allocate VB"); } @@ -1540,16 +1554,16 @@ GFXVertexDecl* GFXD3D11Device::allocVertexDecl( const GFXVertexFormat *vertexFor return decl; U32 elemCount = vertexFormat->getElementCount(); - + ID3DBlob* code = NULL; - + // We have to generate a temporary shader here for now since the input layout creation // expects a shader to be already compiled to verify the vertex layout structure. The problem // is that most of the time the regular shaders are compiled AFTER allocVertexDecl is called. if(!decl) { //TODO: Perhaps save/cache the ID3DBlob for later use on identical vertex formats,save creating/compiling the temp shader everytime - String shaderData = _createTempShaderInternal(vertexFormat); + String shaderData = _createTempShaderInternal(vertexFormat); #ifdef TORQUE_DEBUG U32 flags = D3DCOMPILE_DEBUG | D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_WARNINGS_ARE_ERRORS; @@ -1569,11 +1583,11 @@ GFXVertexDecl* GFXD3D11Device::allocVertexDecl( const GFXVertexFormat *vertexFor SAFE_RELEASE(errorBlob); } - + AssertFatal(code, "D3D11Device::allocVertexDecl - compiled vert shader code missing!"); // Setup the declaration struct. - + U32 stream; D3D11_INPUT_ELEMENT_DESC *vd = new D3D11_INPUT_ELEMENT_DESC[ elemCount]; @@ -1599,7 +1613,7 @@ GFXVertexDecl* GFXD3D11Device::allocVertexDecl( const GFXVertexFormat *vertexFor vd[i].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; vd[i].InstanceDataStepRate = 0; } - // We force the usage index of 0 for everything but + // We force the usage index of 0 for everything but // texture coords for now... this may change later. vd[i].SemanticIndex = 0; @@ -1634,7 +1648,7 @@ GFXVertexDecl* GFXD3D11Device::allocVertexDecl( const GFXVertexFormat *vertexFor decl = new D3D11VertexDecl(); HRESULT hr = mD3DDevice->CreateInputLayout(vd, elemCount,code->GetBufferPointer(), code->GetBufferSize(), &decl->decl); - + if (FAILED(hr)) { AssertFatal(false, "GFXD3D11Device::allocVertexDecl - Failed to create vertex input layout!"); @@ -1654,7 +1668,7 @@ void GFXD3D11Device::setVertexDecl( const GFXVertexDecl *decl ) ID3D11InputLayout *dx11Decl = NULL; if (decl) dx11Decl = static_cast(decl)->decl; - + mD3DDeviceContext->IASetInputLayout(dx11Decl); } @@ -1709,7 +1723,7 @@ GFXFence *GFXD3D11Device::createFence() } // CodeReview: At some point I would like a specialized implementation of - // the method used by the general fence, only without the overhead incurred + // the method used by the general fence, only without the overhead incurred // by using the GFX constructs. Primarily the lock() method on texture handles // will do a data copy, and this method doesn't require a copy, just a lock // [5/10/2007 Pat] @@ -1719,12 +1733,12 @@ GFXFence *GFXD3D11Device::createFence() } GFXOcclusionQuery* GFXD3D11Device::createOcclusionQuery() -{ +{ GFXOcclusionQuery *query; if (mOcclusionQuerySupported) query = new GFXD3D11OcclusionQuery( this ); else - return NULL; + return NULL; query->registerResourceWithDevice(this); return query; @@ -1794,7 +1808,7 @@ const char* GFXD3D11Device::interpretDebugResult(long result) //generics case E_UNEXPECTED: error = "E_UNEXPECTED"; - break; + break; case E_NOTIMPL: error = "E_NOTIMPL"; break; @@ -1852,3 +1866,39 @@ const char* GFXD3D11Device::interpretDebugResult(long result) } return error; } + +ID3D11Buffer* GFXD3D11Device::getDeviceBuffer(const GFXShaderConstDesc desc) +{ + String name(desc.name + "_" + String::ToString(desc.size)); + DeviceBufferMap::Iterator buf = mDeviceBufferMap.find(name); + if (buf != mDeviceBufferMap.end()) + { + mDeviceBufferMap[name]->AddRef(); + return mDeviceBufferMap[name]; + } + + ID3D11Buffer* tempBuf; + D3D11_BUFFER_DESC cbDesc; + cbDesc.ByteWidth = desc.size; + cbDesc.Usage = D3D11_USAGE_DEFAULT; + cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + cbDesc.CPUAccessFlags = 0; + cbDesc.MiscFlags = 0; + cbDesc.StructureByteStride = 0; + + HRESULT hr; + hr = D3D11DEVICE->CreateBuffer(&cbDesc, NULL, &tempBuf); + + if (FAILED(hr)) + { + AssertFatal(false, "Failed to create device buffer."); + } + + mDeviceBufferMap[name] = tempBuf; + +#ifdef TORQUE_DEBUG + tempBuf->SetPrivateData(WKPDID_D3DDebugObjectName, name.size(), name.c_str()); +#endif + + return tempBuf; +} diff --git a/Engine/source/gfx/D3D11/gfxD3D11Device.h b/Engine/source/gfx/D3D11/gfxD3D11Device.h index c1b775152..41b3415e9 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Device.h +++ b/Engine/source/gfx/D3D11/gfxD3D11Device.h @@ -51,6 +51,7 @@ class GFXD3D11Device : public GFXDevice { public: typedef Map SamplerMap; + typedef Map DeviceBufferMap; private: friend class GFXResource; @@ -105,6 +106,7 @@ protected: /// Used to lookup sampler state for a given hash key SamplerMap mSamplersMap; + DeviceBufferMap mDeviceBufferMap; ID3D11RenderTargetView* mDeviceBackBufferView; ID3D11DepthStencilView* mDeviceDepthStencilView; @@ -121,6 +123,7 @@ protected: ID3D11VertexShader *mLastVertShader; ID3D11PixelShader *mLastPixShader; + ID3D11GeometryShader *mLastGeoShader; S32 mCreateFenceType; @@ -140,6 +143,7 @@ protected: // Shader Model targers String mVertexShaderTarget; String mPixelShaderTarget; + String mGeometryShaderTarget; // String for use with shader macros in the form of shader model version * 10 String mShaderModel; bool mDebugLayers; @@ -148,7 +152,7 @@ protected: bool mOcclusionQuerySupported; - U32 mDrawInstancesCount; + U32 mDrawInstancesCount; /// To manage creating and re-creating of these when device is aquired void reacquireDefaultPoolResources(); @@ -181,11 +185,11 @@ protected: // Index buffer management // { virtual void _setPrimitiveBuffer( GFXPrimitiveBuffer *buffer ); - virtual void drawIndexedPrimitive( GFXPrimitiveType primType, - U32 startVertex, - U32 minIndex, - U32 numVerts, - U32 startIndex, + virtual void drawIndexedPrimitive( GFXPrimitiveType primType, + U32 startVertex, + U32 minIndex, + U32 numVerts, + U32 startIndex, U32 primitiveCount ); // } @@ -197,7 +201,7 @@ protected: String _createTempShaderInternal(const GFXVertexFormat *vertexFormat); // Supress any debug layer messages we don't want to see void _suppressDebugMessages(); - + public: static GFXDevice *createInstance( U32 adapterIndex ); @@ -229,7 +233,7 @@ public: virtual GFXTextureArray* createTextureArray(); virtual F32 getPixelShaderVersion() const { return mPixVersion; } - virtual void setPixelShaderVersion( F32 version ){ mPixVersion = version;} + virtual void setPixelShaderVersion( F32 version ){ mPixVersion = version;} virtual void setShader(GFXShader *shader, bool force = false); virtual U32 getNumSamplers() const { return 16; } @@ -252,10 +256,10 @@ public: virtual void setClipRect( const RectI &rect ); virtual const RectI& getClipRect() const { return mClipRect; } - // } + // } + - /// @name Render Targets /// @{ virtual void _updateRenderTargets(); @@ -263,14 +267,14 @@ public: // Vertex/Index buffer management // { - virtual GFXVertexBuffer* allocVertexBuffer( U32 numVerts, + virtual GFXVertexBuffer* allocVertexBuffer( U32 numVerts, const GFXVertexFormat *vertexFormat, U32 vertSize, GFXBufferType bufferType, void* data = NULL); - virtual GFXPrimitiveBuffer *allocPrimitiveBuffer( U32 numIndices, - U32 numPrimitives, + virtual GFXPrimitiveBuffer *allocPrimitiveBuffer( U32 numIndices, + U32 numPrimitives, GFXBufferType bufferType, void* data = NULL); @@ -307,7 +311,7 @@ public: GFXFence *createFence(); - GFXOcclusionQuery* createOcclusionQuery(); + GFXOcclusionQuery* createOcclusionQuery(); // Default multisample parameters DXGI_SAMPLE_DESC getMultisampleType() const { return mMultisampleDesc; } @@ -317,12 +321,16 @@ public: // Shader Model targers const String &getVertexShaderTarget() const { return mVertexShaderTarget; } const String &getPixelShaderTarget() const { return mPixelShaderTarget; } + const String &getGeometryShaderTarget() const { return mGeometryShaderTarget; } const String &getShaderModel() const { return mShaderModel; } // grab the sampler map const SamplerMap &getSamplersMap() const { return mSamplersMap; } SamplerMap &getSamplersMap(){ return mSamplersMap; } const char* interpretDebugResult(long result); + + // grab device buffer. + ID3D11Buffer* getDeviceBuffer(const GFXShaderConstDesc desc); }; #endif diff --git a/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp b/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp index 17827349d..6259be330 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11Shader.cpp @@ -93,262 +93,78 @@ HRESULT gfxD3D11Include::Close( THIS_ LPCVOID pData ) return S_OK; } -GFXD3D11ShaderConstHandle::GFXD3D11ShaderConstHandle() +GFXD3D11ShaderConstHandle::GFXD3D11ShaderConstHandle(GFXD3D11Shader* shader) + : mShader(shader), + mInstancingConstant(false) { - clear(); + dMemset(&mDesc, 0, sizeof(mDesc)); + mValid = false; + mStageFlags = 0; } -const String& GFXD3D11ShaderConstHandle::getName() const +GFXD3D11ShaderConstHandle::GFXD3D11ShaderConstHandle(GFXD3D11Shader* shader, + const GFXShaderConstDesc& desc) + : mShader(shader), + mDesc(desc), + mInstancingConstant(false) { - if ( mVertexConstant ) - return mVertexHandle.name; + if (desc.constType == GFXSCT_ConstBuffer) + mValid = false; else - return mPixelHandle.name; + mValid = true; + + addDesc(desc.shaderStage, desc); + mStageFlags = desc.shaderStage; } -GFXShaderConstType GFXD3D11ShaderConstHandle::getType() const +GFXD3D11ShaderConstHandle::~GFXD3D11ShaderConstHandle() { - if ( mVertexConstant ) - return mVertexHandle.constType; - else - return mPixelHandle.constType; } -U32 GFXD3D11ShaderConstHandle::getArraySize() const +void GFXD3D11ShaderConstHandle::addDesc(GFXShaderStage stage, const GFXShaderConstDesc& desc) { - if ( mVertexConstant ) - return mVertexHandle.arraySize; - else - return mPixelHandle.arraySize; + // just add for now. + mDescMap[stage] = desc; } -S32 GFXD3D11ShaderConstHandle::getSamplerRegister() const +const GFXShaderConstDesc GFXD3D11ShaderConstHandle::getDesc(GFXShaderStage stage) { - if ( !mValid || !isSampler() ) - return -1; - - // We always store sampler type and register index in the pixelHandle, - // sampler registers are shared between vertex and pixel shaders anyway. - - return mPixelHandle.offset; -} - -GFXD3D11ConstBufferLayout::GFXD3D11ConstBufferLayout() -{ - mSubBuffers.reserve(CBUFFER_MAX); -} - -bool GFXD3D11ConstBufferLayout::set(const ParamDesc& pd, const GFXShaderConstType constType, const U32 inSize, const void* data, U8* basePointer) -{ - PROFILE_SCOPE(GenericConstBufferLayout_set); - S32 size = inSize; - // Shader compilers like to optimize float4x4 uniforms into float3x3s. - // So long as the real paramater is a matrix of-some-type and the data - // passed in is a MatrixF ( which is will be ), we DO NOT have a - // mismatched const type. - AssertFatal(pd.constType == constType || - ( - (pd.constType == GFXSCT_Float2x2 || - pd.constType == GFXSCT_Float3x3 || - pd.constType == GFXSCT_Float4x3 || - pd.constType == GFXSCT_Float4x4) && - (constType == GFXSCT_Float2x2 || - constType == GFXSCT_Float3x3 || - constType == GFXSCT_Float4x3 || - constType == GFXSCT_Float4x4) - ), "Mismatched const type!"); - - // This "cute" bit of code allows us to support 2x3 and 3x3 matrices in shader constants but use our MatrixF class. Yes, a hack. -BTR - switch (pd.constType) - { - case GFXSCT_Float2x2: - case GFXSCT_Float3x3: - case GFXSCT_Float4x3: - case GFXSCT_Float4x4: - return setMatrix(pd, constType, size, data, basePointer); - break; - // TODO add other AlignedVector here - case GFXSCT_Float2: - if (size > sizeof(Point2F)) - size = pd.size; - default: - break; - } - - AssertFatal(pd.size >= size, "Not enough room in the buffer for this data!"); - - // Ok, we only set data if it's different than the data we already have, this maybe more expensive than just setting the data, but - // we'll have to do some timings to see. For example, the lighting shader constants rarely change, but we can't assume that at the - // renderInstMgr level, but we can check down here. -BTR - if (dMemcmp(basePointer + pd.offset, data, size) != 0) - { - dMemcpy(basePointer + pd.offset, data, size); - return true; - } - return false; -} - -bool GFXD3D11ConstBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer) -{ - PROFILE_SCOPE(GFXD3D11ConstBufferLayout_setMatrix); - - if (pd.constType == GFXSCT_Float4x4) - { - // Special case, we can just blast this guy. - AssertFatal(pd.size >= size, "Not enough room in the buffer for this data!"); - if (dMemcmp(basePointer+pd.offset, data, size) != 0) - { - dMemcpy(basePointer+pd.offset, data, size); - return true; - } - - return false; - } - else - { - PROFILE_SCOPE(GFXD3D11ConstBufferLayout_setMatrix_not4x4); - - // Figure out how big of a chunk we are copying. We're going to copy 4 columns by N rows of data - U32 csize; - switch (pd.constType) - { - case GFXSCT_Float2x2 : - csize = 24; //this takes up 16+8 - break; - case GFXSCT_Float3x3 : - csize = 44; //This takes up 16+16+12 - break; - case GFXSCT_Float4x3: - csize = 48; - break; - default: - AssertFatal(false, "Unhandled case!"); - return false; - break; - } - - // Loop through and copy - bool ret = false; - U8* currDestPointer = basePointer+pd.offset; - const U8* currSourcePointer = static_cast(data); - const U8* endData = currSourcePointer + size; - while (currSourcePointer < endData) - { - if (dMemcmp(currDestPointer, currSourcePointer, csize) != 0) - { - dMemcpy(currDestPointer, currSourcePointer, csize); - ret = true; - } - else if (pd.constType == GFXSCT_Float4x3) - { - ret = true; - } - - currDestPointer += csize; - currSourcePointer += sizeof(MatrixF); - } - - return ret; - } + return mDescMap[stage]; } //------------------------------------------------------------------------------ -GFXD3D11ShaderConstBuffer::GFXD3D11ShaderConstBuffer( GFXD3D11Shader* shader, - GFXD3D11ConstBufferLayout* vertexLayout, - GFXD3D11ConstBufferLayout* pixelLayout) + +GFXD3D11ShaderConstBuffer::GFXD3D11ShaderConstBuffer(GFXD3D11Shader* shader) { - AssertFatal( shader, "GFXD3D11ShaderConstBuffer() - Got a null shader!" ); + mShader = shader; + mDeviceContext = D3D11DEVICECONTEXT; - // We hold on to this so we don't have to call - // this virtual method during activation. - mShader = shader; - - for (U32 i = 0; i < CBUFFER_MAX; ++i) - { - mConstantBuffersV[i] = NULL; - mConstantBuffersP[i] = NULL; - } - - // TODO: Remove buffers and layouts that don't exist for performance? - //Mandatory - mVertexConstBufferLayout = vertexLayout; - mVertexConstBuffer = new GenericConstBuffer(vertexLayout); - - mPixelConstBufferLayout = pixelLayout; - mPixelConstBuffer = new GenericConstBuffer(pixelLayout); - - mDeviceContext = D3D11DEVICECONTEXT; - - _createBuffers(); - + for (U32 i = 0; i < 6; i++) + { + for (U32 j = 0; j < 16; j++) + { + mBoundBuffers[i][j] = nullptr; + } + } } GFXD3D11ShaderConstBuffer::~GFXD3D11ShaderConstBuffer() -{ - // release constant buffer - for (U32 i = 0; i < CBUFFER_MAX; ++i) - { - SAFE_RELEASE(mConstantBuffersP[i]); - SAFE_RELEASE(mConstantBuffersV[i]); - } - - SAFE_DELETE(mVertexConstBuffer); - SAFE_DELETE(mPixelConstBuffer); - - - if ( mShader ) - mShader->_unlinkBuffer( this ); -} - -void GFXD3D11ShaderConstBuffer::_createBuffers() { - HRESULT hr; - // Create a vertex constant buffer - if (mVertexConstBufferLayout->getBufferSize() > 0) + for (auto& pair : mBufferMap) { + delete[] pair.value.data; + } + mBufferMap.clear(); // Clear the map + + for (U32 i = 0; i < 6; i++) { - const Vector &subBuffers = mVertexConstBufferLayout->getSubBufferDesc(); - for (U32 i = 0; i < subBuffers.size(); ++i) + for (U32 j = 0; j < 16; j++) { - D3D11_BUFFER_DESC cbDesc; - cbDesc.ByteWidth = subBuffers[i].size; - cbDesc.Usage = D3D11_USAGE_DEFAULT; - cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - cbDesc.CPUAccessFlags = 0; - cbDesc.MiscFlags = 0; - cbDesc.StructureByteStride = 0; - - hr = D3D11DEVICE->CreateBuffer(&cbDesc, NULL, &mConstantBuffersV[i]); - - if (FAILED(hr)) - { - AssertFatal(false, "can't create constant mConstantBuffersV!"); - } + mBoundBuffers[i][j] = nullptr; } } - // Create a pixel constant buffer - if (mPixelConstBufferLayout->getBufferSize()) - { - const Vector &subBuffers = mPixelConstBufferLayout->getSubBufferDesc(); - for (U32 i = 0; i < subBuffers.size(); ++i) - { - // Create a pixel float constant buffer - D3D11_BUFFER_DESC cbDesc; - cbDesc.ByteWidth = subBuffers[i].size; - cbDesc.Usage = D3D11_USAGE_DEFAULT; - cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - cbDesc.CPUAccessFlags = 0; - cbDesc.MiscFlags = 0; - cbDesc.StructureByteStride = 0; - - hr = D3D11DEVICE->CreateBuffer(&cbDesc, NULL, &mConstantBuffersP[i]); - - if (FAILED(hr)) - { - AssertFatal(false, "can't create constant mConstantBuffersP!"); - } - } - } + if (mShader) + mShader->_unlinkBuffer(this); } GFXShader* GFXD3D11ShaderConstBuffer::getShader() @@ -356,141 +172,229 @@ GFXShader* GFXD3D11ShaderConstBuffer::getShader() return mShader; } -// This is kind of cheesy, but I don't think templates would work well here because -// these functions potentially need to be handled differently by other derived types -template -inline void GFXD3D11ShaderConstBuffer::SET_CONSTANT( GFXShaderConstHandle* handle, const T& fv, - GenericConstBuffer *vBuffer, GenericConstBuffer *pBuffer ) +void GFXD3D11ShaderConstBuffer::setMatrix(const GFXShaderConstDesc& constDesc, const U32 inSize, const void* data, U8* basePointer) { - AssertFatal(static_cast(handle), "Incorrect const buffer type!"); - const GFXD3D11ShaderConstHandle* h = static_cast(handle); - AssertFatal(h, "Handle is NULL!" ); - AssertFatal(h->isValid(), "Handle is not valid!" ); - AssertFatal(!h->isSampler(), "Handle is sampler constant!" ); - AssertFatal(!mShader.isNull(), "Buffer's shader is null!" ); - AssertFatal(!h->mShader.isNull(), "Handle's shader is null!" ); - AssertFatal(h->mShader.getPointer() == mShader.getPointer(), "Mismatched shaders!"); + U8* buf = basePointer; - if ( h->mInstancingConstant ) + if (constDesc.constType == GFXSCT_Float4x4) { - dMemcpy( mInstPtr+h->mPixelHandle.offset, &fv, sizeof( fv ) ); + // Special case, we can just blast this guy. + if (dMemcmp(buf + constDesc.offset, data, inSize) != 0) + { + dMemcpy(buf + constDesc.offset, data, inSize); + } + return; } - if (h->mVertexConstant) - vBuffer->set(h->mVertexHandle, fv); - if (h->mPixelConstant) - pBuffer->set(h->mPixelHandle, fv); + else + { + PROFILE_SCOPE(GFXD3D11ConstBufferLayout_setMatrix_not4x4); + + // Figure out how big of a chunk we are copying. We're going to copy 4 columns by N rows of data + U32 csize; + switch (constDesc.constType) + { + case GFXSCT_Float2x2: + csize = 24; //this takes up 16+8 + break; + case GFXSCT_Float3x3: + csize = 44; //This takes up 16+16+12 + break; + case GFXSCT_Float4x3: + csize = 48; + break; + default: + AssertFatal(false, "Unhandled case!"); + return; + break; + } + + // Loop through and copy + bool ret = false; + U8* currDestPointer = buf + constDesc.offset; + const U8* currSourcePointer = static_cast(data); + const U8* endData = currSourcePointer + inSize; + while (currSourcePointer < endData) + { + if (dMemcmp(currDestPointer, currSourcePointer, csize) != 0) + { + dMemcpy(currDestPointer, currSourcePointer, csize); + ret = true; + } + + currDestPointer += csize; + currSourcePointer += sizeof(MatrixF); + } + } } -void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const F32 fv) +void GFXD3D11ShaderConstBuffer::internalSet(GFXShaderConstHandle* handle, const U32 inSize, const void* data) { - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); + AssertFatal(handle, "GFXD3D11ShaderConstBuffer::internalSet - Handle is NULL!"); + AssertFatal(handle->isValid(), "GFXD3D11ShaderConstBuffer::internalSet - Handle is not valid!"); + AssertFatal(dynamic_cast(handle), "GFXD3D11ShaderConstBuffer::internalSet - Incorrect const buffer type"); + + GFXD3D11ShaderConstHandle* _dxHandle = static_cast(handle); + AssertFatal(mShader == _dxHandle->mShader, "GFXD3D11ShaderConstBuffer::internalSet - Should only set handles which are owned by our shader"); + S32 size = inSize; + + for (U32 i = VERTEX_SHADER; i <= COMPUTE_SHADER; i = GFXShaderStage(i << 1)) + { + if (_dxHandle->mStageFlags & i) + { + S32 shaderStageID = -1; // Initialize to -1 (bit not found) + for (int j = 0; j < sizeof(S32) * 8; ++j) { + if (i & (1 << j)) { + shaderStageID = j; + break; + } + } + + GFXShaderConstDesc constDesc = _dxHandle->getDesc((GFXShaderStage)i); + BufferKey bufDesc(constDesc.bindPoint, shaderStageID); + U8* basePointer = mBufferMap[bufDesc].data; + + if (_dxHandle->mInstancingConstant) + { + dMemcpy(mInstPtr + constDesc.offset, data, size); + return; + } + + switch (constDesc.constType) + { + case GFXSCT_Float2x2: + case GFXSCT_Float3x3: + case GFXSCT_Float4x3: + case GFXSCT_Float4x4: + setMatrix(constDesc, size, data, basePointer); + return; + break; + // TODO add other AlignedVector here + case GFXSCT_Float2: + if (size > sizeof(Point2F)) + size = constDesc.size; + break; + default: + break; + } + + if (dMemcmp(basePointer + constDesc.offset, data, size) != 0) + { + dMemcpy(basePointer + constDesc.offset, data, size); + } + } + } } -void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point2F& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const F32 fv) +{ + internalSet(handle, sizeof(F32), &fv); } -void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point3F& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point2F& fv) +{ + internalSet(handle, sizeof(Point2F), &fv); } -void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4F& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point3F& fv) +{ + internalSet(handle, sizeof(Point3F), &fv); } -void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const PlaneF& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4F& fv) +{ + internalSet(handle, sizeof(Point4F), &fv); +} + +void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const PlaneF& fv) +{ + internalSet(handle, sizeof(PlaneF), &fv); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const LinearColorF& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, sizeof(Point4F), &fv); } -void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const S32 f) -{ +void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const S32 fv) +{ // This is the only type that is allowed to be used // with a sampler shader constant type, but it is only // allowed to be set from GLSL. // // So we ignore it here... all other cases will assert. // - if ( ((GFXD3D11ShaderConstHandle*)handle)->isSampler() ) + if (((GFXD3D11ShaderConstHandle*)handle)->isSampler()) return; - SET_CONSTANT(handle, f, mVertexConstBuffer, mPixelConstBuffer); + internalSet(handle, sizeof(S32), &fv); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point2I& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, sizeof(Point2I), &fv); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point3I& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, sizeof(Point3I), &fv); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4I& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, sizeof(Point4I), &fv); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, fv.getElementSize() * fv.size(), fv.getBuffer()); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, fv.getElementSize() * fv.size(), fv.getBuffer()); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, fv.getElementSize() * fv.size(), fv.getBuffer()); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, fv.getElementSize() * fv.size(), fv.getBuffer()); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, fv.getElementSize() * fv.size(), fv.getBuffer()); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, fv.getElementSize() * fv.size(), fv.getBuffer()); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, fv.getElementSize() * fv.size(), fv.getBuffer()); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray& fv) -{ - SET_CONSTANT(handle, fv, mVertexConstBuffer, mPixelConstBuffer); +{ + internalSet(handle, fv.getElementSize() * fv.size(), fv.getBuffer()); } -#undef SET_CONSTANT -void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& mat, const GFXShaderConstType matrixType) -{ - AssertFatal(handle, "Handle is NULL!" ); - AssertFatal(handle->isValid(), "Handle is not valid!" ); +void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& mat, const GFXShaderConstType matrixType) +{ + AssertFatal(handle, "Handle is NULL!"); + AssertFatal(handle->isValid(), "Handle is not valid!"); - AssertFatal(static_cast(handle), "Incorrect const buffer type!"); - const GFXD3D11ShaderConstHandle* h = static_cast(handle); - AssertFatal(!h->isSampler(), "Handle is sampler constant!" ); - AssertFatal(h->mShader == mShader, "Mismatched shaders!"); + AssertFatal(static_cast(handle), "Incorrect const buffer type!"); + GFXD3D11ShaderConstHandle* _dxHandle = static_cast(handle); + + AssertFatal(!_dxHandle->isSampler(), "Handle is sampler constant!"); + AssertFatal(_dxHandle->mShader == mShader, "Mismatched shaders!"); MatrixF transposed; if (matrixType == GFXSCT_Float4x3) @@ -502,30 +406,28 @@ void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& mat.transposeTo(transposed); } - if (h->mInstancingConstant) + if (_dxHandle->mInstancingConstant) { - if ( matrixType == GFXSCT_Float4x4 ) - dMemcpy( mInstPtr+h->mPixelHandle.offset, mat, sizeof( mat ) ); - - // TODO: Support 3x3 and 2x2 matricies? + GFXShaderConstDesc constDesc = _dxHandle->getDesc(GFXShaderStage::PIXEL_SHADER); + if (matrixType == GFXSCT_Float4x4) + dMemcpy(mInstPtr + constDesc.offset, mat, sizeof(mat)); + + // TODO: Support 3x3 and 2x2 matricies? return; } - if (h->mVertexConstant) - mVertexConstBuffer->set(h->mVertexHandle, transposed, matrixType); - if (h->mPixelConstant) - mPixelConstBuffer->set(h->mPixelHandle, transposed, matrixType); + internalSet(handle, sizeof(MatrixF), &transposed); } void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF* mat, const U32 arraySize, const GFXShaderConstType matrixType) { - AssertFatal(handle, "Handle is NULL!" ); - AssertFatal(handle->isValid(), "Handle is not valid!" ); + AssertFatal(handle, "Handle is NULL!"); + AssertFatal(handle->isValid(), "Handle is not valid!"); - AssertFatal(static_cast(handle), "Incorrect const buffer type!"); - const GFXD3D11ShaderConstHandle* h = static_cast(handle); - AssertFatal(!h->isSampler(), "Handle is sampler constant!" ); - AssertFatal(h->mShader == mShader, "Mismatched shaders!"); + AssertFatal(static_cast(handle), "Incorrect const buffer type!"); + const GFXD3D11ShaderConstHandle* _dxHandle = static_cast(handle); + AssertFatal(!_dxHandle->isSampler(), "Handle is sampler constant!"); + AssertFatal(_dxHandle->mShader == mShader, "Mismatched shaders!"); static Vector transposed; if (arraySize > transposed.size()) @@ -542,13 +444,10 @@ void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF* } // TODO: Maybe support this in the future? - if (h->mInstancingConstant) + if (_dxHandle->mInstancingConstant) return; - if (h->mVertexConstant) - mVertexConstBuffer->set(h->mVertexHandle, transposed.begin(), arraySize, matrixType); - if (h->mPixelConstant) - mPixelConstBuffer->set(h->mPixelHandle, transposed.begin(), arraySize, matrixType); + internalSet(handle, sizeof(MatrixF) * arraySize, transposed.begin()); } const String GFXD3D11ShaderConstBuffer::describeSelf() const @@ -556,154 +455,133 @@ const String GFXD3D11ShaderConstBuffer::describeSelf() const String ret; ret = String(" GFXD3D11ShaderConstBuffer\n"); - for (U32 i = 0; i < mVertexConstBufferLayout->getParameterCount(); i++) - { - GenericConstBufferLayout::ParamDesc pd; - mVertexConstBufferLayout->getDesc(i, pd); - ret += String::ToString(" Constant name: %s", pd.name.c_str()); + return ret; +} + +void GFXD3D11ShaderConstBuffer::addBuffer(const GFXShaderConstDesc desc) +{ + S32 shaderStageID = -1; // Initialize to -1 (bit not found) + for (int i = 0; i < sizeof(S32) * 8; ++i) { + if (desc.shaderStage & (1 << i)) { + shaderStageID = i; + break; + } } - return ret; -} + // no shaderstage defined? cannot be!!! + if (shaderStageID == -1) + { + AssertFatal(false, "DX Const buffer requires a shaderStage flag."); + } -void GFXD3D11ShaderConstBuffer::zombify() -{ -} + const BufferKey bufKey(desc.bindPoint, shaderStageID); + // doesnt matter if its already added. + U8* buf = new U8[desc.size]; + dMemset(buf, 0, desc.size); + mBufferMap[bufKey].data = buf; + mBufferMap[bufKey].size = desc.size; + mBufferMap[bufKey].isDirty = true; -void GFXD3D11ShaderConstBuffer::resurrect() -{ -} - -bool GFXD3D11ShaderConstBuffer::isDirty() -{ - bool ret = mVertexConstBuffer->isDirty(); - ret |= mPixelConstBuffer->isDirty(); - - return ret; + mBoundBuffers[(U32)shaderStageID][desc.bindPoint] = D3D11->getDeviceBuffer(desc); } void GFXD3D11ShaderConstBuffer::activate( GFXD3D11ShaderConstBuffer *prevShaderBuffer ) { PROFILE_SCOPE(GFXD3D11ShaderConstBuffer_activate); - // NOTE: This is a really critical function as it gets - // called between every draw call to update the constants. - // - // Alot of the calls here are inlined... be careful - // what you change. + BufferRange bufRanges[6]; - // If the buffer has changed we need to compare it - // with the new buffer to see if we can skip copying - // equal buffer content. - // - // If the buffer hasn't changed then we only will - // be copying the changes that have occured since - // the last activate call. - if ( prevShaderBuffer != this ) + for (BufferMap::Iterator i = mBufferMap.begin(); i != mBufferMap.end(); ++i) { - // If the previous buffer is dirty, than we can't compare - // against it, because it hasn't sent its contents to the - // card yet and must be copied. - if ( prevShaderBuffer && !prevShaderBuffer->isDirty() ) + const BufferKey thisBufferDesc = i->key; + ConstantBuffer thisBuff = i->value; + + if (prevShaderBuffer && prevShaderBuffer != this) { - PROFILE_SCOPE(GFXD3D11ShaderConstBuffer_activate_dirty_check_1); - // If the buffer content is equal then we set the dirty - // flag to false knowing the current state of the card matches - // the new buffer. - // - // If the content is not equal we set the dirty flag to - // true which causes the full content of the buffer to be - // copied to the card. - // - mVertexConstBuffer->setDirty( !prevShaderBuffer->mVertexConstBuffer->isEqual( mVertexConstBuffer ) ); - mPixelConstBuffer->setDirty( !prevShaderBuffer->mPixelConstBuffer->isEqual( mPixelConstBuffer ) ); - } + const ConstantBuffer prevBuffer = prevShaderBuffer->mBufferMap[i->key]; + + if (prevBuffer.data && !prevBuffer.isDirty) + { + if (prevBuffer.size != thisBuff.size) + { + thisBuff.isDirty = true; + } + else + { + if (dMemcmp(prevBuffer.data, thisBuff.data, thisBuff.size) != 0) + { + thisBuff.isDirty = true; + } + else + { + thisBuff.isDirty = false; + } + } + } + else + { + thisBuff.isDirty = true; + } + } else { - // This happens rarely... but it can happen. - // We copy the entire dirty state to the card. - PROFILE_SCOPE(GFXD3D11ShaderConstBuffer_activate_dirty_check_2); + thisBuff.isDirty = true; + } - mVertexConstBuffer->setDirty( true ); - mPixelConstBuffer->setDirty( true ); - } + if (thisBuff.data && thisBuff.isDirty) + { + D3D11DEVICECONTEXT->UpdateSubresource(mBoundBuffers[thisBufferDesc.key2][thisBufferDesc.key1], 0, NULL, thisBuff.data, thisBuff.size, 0); + bufRanges[thisBufferDesc.key2].addSlot(thisBufferDesc.key1); + } } - D3D11_MAPPED_SUBRESOURCE pConstData; - ZeroMemory(&pConstData, sizeof(D3D11_MAPPED_SUBRESOURCE)); - - const U8* buf; - U32 nbBuffers = 0; - if(mVertexConstBuffer->isDirty()) + if (mShader->mVertShader && bufRanges[0].isValid()) { - const Vector &subBuffers = mVertexConstBufferLayout->getSubBufferDesc(); - // TODO: This is not very effecient updating the whole lot, re-implement the dirty system to work with multiple constant buffers. - // TODO: Implement DX 11.1 UpdateSubresource1 which supports updating ranges with constant buffers - buf = mVertexConstBuffer->getEntireBuffer(); - for (U32 i = 0; i < subBuffers.size(); ++i) - { - const ConstSubBufferDesc &desc = subBuffers[i]; - mDeviceContext->UpdateSubresource(mConstantBuffersV[i], 0, NULL, buf + desc.start, desc.size, 0); - nbBuffers++; - } + const U32 bufStartSlot = bufRanges[0].mBufMin; + const U32 numBufs = bufRanges[0].mBufMax - bufRanges[0].mBufMin + 1; + ID3D11Buffer** vsBuffers = mBoundBuffers[0] + bufStartSlot; - mDeviceContext->VSSetConstantBuffers(0, nbBuffers, mConstantBuffersV); + D3D11DEVICECONTEXT->VSSetConstantBuffers(bufStartSlot, numBufs, vsBuffers); } - nbBuffers = 0; - - if(mPixelConstBuffer->isDirty()) + if (mShader->mPixShader && bufRanges[1].isValid()) { - const Vector &subBuffers = mPixelConstBufferLayout->getSubBufferDesc(); - // TODO: This is not very effecient updating the whole lot, re-implement the dirty system to work with multiple constant buffers. - // TODO: Implement DX 11.1 UpdateSubresource1 which supports updating ranges with constant buffers - buf = mPixelConstBuffer->getEntireBuffer(); - for (U32 i = 0; i < subBuffers.size(); ++i) - { - const ConstSubBufferDesc &desc = subBuffers[i]; - mDeviceContext->UpdateSubresource(mConstantBuffersP[i], 0, NULL, buf + desc.start, desc.size, 0); - nbBuffers++; - } + const U32 bufStartSlot = bufRanges[1].mBufMin; + const U32 numBufs = bufRanges[1].mBufMax - bufRanges[1].mBufMin + 1; + ID3D11Buffer** psBuffers = mBoundBuffers[1] + bufStartSlot; - mDeviceContext->PSSetConstantBuffers(0, nbBuffers, mConstantBuffersP); + D3D11DEVICECONTEXT->PSSetConstantBuffers(bufStartSlot, numBufs, psBuffers); } - #ifdef TORQUE_DEBUG - // Make sure all the constants for this buffer were assigned. - if(mWasLost) - { - mVertexConstBuffer->assertUnassignedConstants( mShader->getVertexShaderFile().c_str() ); - mPixelConstBuffer->assertUnassignedConstants( mShader->getPixelShaderFile().c_str() ); - } - #endif + if (mShader->mGeoShader && bufRanges[2].isValid()) + { + const U32 bufStartSlot = bufRanges[2].mBufMin; + const U32 numBufs = bufRanges[2].mBufMax - bufRanges[2].mBufMin + 1; + ID3D11Buffer** psBuffers = mBoundBuffers[2] + bufStartSlot; + + D3D11DEVICECONTEXT->GSSetConstantBuffers(bufStartSlot, numBufs, psBuffers); + } - // Clear the lost state. mWasLost = false; + } void GFXD3D11ShaderConstBuffer::onShaderReload( GFXD3D11Shader *shader ) { AssertFatal( shader == mShader, "GFXD3D11ShaderConstBuffer::onShaderReload is hosed!" ); - // release constant buffers - for (U32 i = 0; i < CBUFFER_MAX; ++i) + for (auto& pair : mBufferMap) { + delete[] pair.value.data; + } + mBufferMap.clear(); // Clear the map + + for (GFXD3D11Shader::BufferMap::Iterator i = shader->mBuffers.begin(); i != shader->mBuffers.end(); ++i) { - SAFE_RELEASE(mConstantBuffersP[i]); - SAFE_RELEASE(mConstantBuffersV[i]); + // add our buffer descriptions to the full const buffer. + this->addBuffer(i->value); } - SAFE_DELETE( mVertexConstBuffer ); - SAFE_DELETE( mPixelConstBuffer ); - - AssertFatal( mVertexConstBufferLayout == shader->mVertexConstBufferLayout, "GFXD3D11ShaderConstBuffer::onShaderReload is hosed!" ); - AssertFatal( mPixelConstBufferLayout == shader->mPixelConstBufferLayout, "GFXD3D11ShaderConstBuffer::onShaderReload is hosed!" ); - - mVertexConstBuffer = new GenericConstBuffer( mVertexConstBufferLayout ); - mPixelConstBuffer = new GenericConstBuffer( mPixelConstBufferLayout ); - - _createBuffers(); - // Set the lost state. mWasLost = true; } @@ -717,8 +595,7 @@ GFXD3D11Shader::GFXD3D11Shader() AssertFatal(D3D11DEVICE, "Invalid device for shader."); mVertShader = NULL; mPixShader = NULL; - mVertexConstBufferLayout = NULL; - mPixelConstBufferLayout = NULL; + mGeoShader = NULL; if( smD3DInclude == NULL ) smD3DInclude = new gfxD3D11Include; @@ -728,16 +605,18 @@ GFXD3D11Shader::GFXD3D11Shader() GFXD3D11Shader::~GFXD3D11Shader() { - for (HandleMap::Iterator i = mHandles.begin(); i != mHandles.end(); i++) - delete i->value; - - // delete const buffer layouts - SAFE_DELETE(mVertexConstBufferLayout); - SAFE_DELETE(mPixelConstBufferLayout); + for (auto& pair : mHandles) { + if (pair.value != nullptr) { + delete pair.value; + pair.value = nullptr; + } + } + mHandles.clear(); // release shaders SAFE_RELEASE(mVertShader); SAFE_RELEASE(mPixShader); + SAFE_RELEASE(mGeoShader); //maybe add SAFE_RELEASE(mVertexCode) ? } @@ -747,6 +626,7 @@ bool GFXD3D11Shader::_init() SAFE_RELEASE(mVertShader); SAFE_RELEASE(mPixShader); + SAFE_RELEASE(mGeoShader); // Create the macro array including the system wide macros. const U32 macroCount = smGlobalMacros.size() + mMacros.size() + 2; @@ -769,65 +649,30 @@ bool GFXD3D11Shader::_init() memset(&d3dMacros[macroCount - 1], 0, sizeof(D3D_SHADER_MACRO)); - if ( !mVertexConstBufferLayout ) - mVertexConstBufferLayout = new GFXD3D11ConstBufferLayout(); - else - mVertexConstBufferLayout->clear(); - - if ( !mPixelConstBufferLayout ) - mPixelConstBufferLayout = new GFXD3D11ConstBufferLayout(); - else - mPixelConstBufferLayout->clear(); - - - mSamplerDescriptions.clear(); mShaderConsts.clear(); + mSamplerDescriptions.clear(); - String vertTarget = D3D11->getVertexShaderTarget(); - String pixTarget = D3D11->getPixelShaderTarget(); + if (!mVertexFile.isEmpty() && !_compileShader( mVertexFile, GFXShaderStage::VERTEX_SHADER, d3dMacros) ) + return false; - if ( !Con::getBoolVariable( "$shaders::forceLoadCSF", false ) ) + if (!mPixelFile.isEmpty() && !_compileShader( mPixelFile, GFXShaderStage::PIXEL_SHADER, d3dMacros)) + return false; + + if (!mGeometryFile.isEmpty()) { - if (!mVertexFile.isEmpty() && !_compileShader( mVertexFile, vertTarget, d3dMacros, mVertexConstBufferLayout, mSamplerDescriptions ) ) + if (!_compileShader(mGeometryFile, GFXShaderStage::GEOMETRY_SHADER, d3dMacros)) return false; - - if (!mPixelFile.isEmpty() && !_compileShader( mPixelFile, pixTarget, d3dMacros, mPixelConstBufferLayout, mSamplerDescriptions ) ) - return false; - - } - else - { - if ( !_loadCompiledOutput( mVertexFile, vertTarget, mVertexConstBufferLayout, mSamplerDescriptions ) ) - { - if ( smLogErrors ) - Con::errorf( "GFXD3D11Shader::init - Unable to load precompiled vertex shader for '%s'.", mVertexFile.getFullPath().c_str() ); - - return false; - } - - if ( !_loadCompiledOutput( mPixelFile, pixTarget, mPixelConstBufferLayout, mSamplerDescriptions ) ) - { - if ( smLogErrors ) - Con::errorf( "GFXD3D11Shader::init - Unable to load precompiled pixel shader for '%s'.", mPixelFile.getFullPath().c_str() ); - - return false; - } } - // Existing handles are resored to an uninitialized state. - // Those that are found when parsing the layout parameters - // will then be re-initialized. - HandleMap::Iterator iter = mHandles.begin(); - for ( ; iter != mHandles.end(); iter++ ) - (iter->value)->clear(); + // Mark all existing handles as invalid. + // Those that are found when parsing the descriptions will then be marked valid again. + for (auto& pair : mHandles) { + pair.value->clear(); + } - _buildShaderConstantHandles(mVertexConstBufferLayout, true); - _buildShaderConstantHandles(mPixelConstBufferLayout, false); + _buildShaderConstantHandles(); - _buildSamplerShaderConstantHandles( mSamplerDescriptions ); - _buildInstancingShaderConstantHandles(); - - // Notify any existing buffers that the buffer + // Notify any existing buffers that the buffer // layouts have changed and they need to update. Vector::iterator biter = mActiveBuffers.begin(); for ( ; biter != mActiveBuffers.end(); biter++ ) @@ -836,11 +681,9 @@ bool GFXD3D11Shader::_init() return true; } -bool GFXD3D11Shader::_compileShader( const Torque::Path &filePath, - const String& target, - const D3D_SHADER_MACRO *defines, - GenericConstBufferLayout* bufferLayout, - Vector &samplerDescriptions ) +bool GFXD3D11Shader::_compileShader( const Torque::Path &filePath, + GFXShaderStage shaderStage, + const D3D_SHADER_MACRO *defines) { PROFILE_SCOPE( GFXD3D11Shader_CompileShader ); @@ -852,7 +695,7 @@ bool GFXD3D11Shader::_compileShader( const Torque::Path &filePath, ID3D11ShaderReflection* reflectionTable = NULL; #ifdef TORQUE_GFX_VISUAL_DEBUG //for use with NSight, GPU Perf studio, VS graphics debugger - U32 flags = D3DCOMPILE_DEBUG | D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_PREFER_FLOW_CONTROL | D3DCOMPILE_SKIP_OPTIMIZATION; + U32 flags = D3DCOMPILE_DEBUG | D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_PREFER_FLOW_CONTROL | D3DCOMPILE_SKIP_OPTIMIZATION; #elif defined(TORQUE_DEBUG) //debug build U32 flags = D3DCOMPILE_DEBUG | D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_WARNINGS_ARE_ERRORS; #else //release build @@ -864,9 +707,9 @@ bool GFXD3D11Shader::_compileShader( const Torque::Path &filePath, #endif // Is it an HLSL shader? - if(filePath.getExtension().equal("hlsl", String::NoCase)) + if(filePath.getExtension().equal("hlsl", String::NoCase)) { - // Set this so that the D3DInclude::Open will have this + // Set this so that the D3DInclude::Open will have this // information for relative paths. smD3DInclude->setPath(filePath.getRootAndPath()); @@ -896,35 +739,31 @@ bool GFXD3D11Shader::_compileShader( const Torque::Path &filePath, s.read(bufSize, buffer); buffer[bufSize] = 0; - res = D3DCompile(buffer, bufSize, realPath.getFullPath().c_str(), defines, smD3DInclude, "main", target, flags, 0, &code, &errorBuff); - - } + String target; - // Is it a precompiled obj shader? - else if(filePath.getExtension().equal("obj", String::NoCase)) - { - FileStream s; - if(!s.open(filePath, Torque::FS::File::Read)) + switch (shaderStage) { - AssertISV(false, avar("GFXD3D11Shader::initShader - failed to open shader '%s'.", filePath.getFullPath().c_str())); - - if ( smLogErrors ) - Con::errorf( "GFXD3D11Shader::_compileShader - Failed to open shader file '%s'.", filePath.getFullPath().c_str() ); - - return false; + case VERTEX_SHADER: + target = D3D11->getVertexShaderTarget(); + break; + case PIXEL_SHADER: + target = D3D11->getPixelShaderTarget(); + break; + case GEOMETRY_SHADER: + target = D3D11->getGeometryShaderTarget(); + break; + case DOMAIN_SHADER: + break; + case HULL_SHADER: + break; + case COMPUTE_SHADER: + break; + default: + break; } - res = D3DCreateBlob(s.getStreamSize(), &code); - AssertISV(SUCCEEDED(res), "Unable to create buffer!"); - s.read(s.getStreamSize(), code->GetBufferPointer()); + res = D3DCompile(buffer, bufSize, realPath.getFullPath().c_str(), defines, smD3DInclude, "main", target, flags, 0, &code, &errorBuff); } - else - { - if (smLogErrors) - Con::errorf("GFXD3D11Shader::_compileShader - Unsupported shader file type '%s'.", filePath.getFullPath().c_str()); - - return false; - } if(errorBuff) { @@ -951,56 +790,41 @@ bool GFXD3D11Shader::_compileShader( const Torque::Path &filePath, if(code != NULL) { -#ifndef TORQUE_SHIPPING + switch (shaderStage) + { + case VERTEX_SHADER: + res = D3D11DEVICE->CreateVertexShader(code->GetBufferPointer(), code->GetBufferSize(), NULL, &mVertShader); + break; + case PIXEL_SHADER: + res = D3D11DEVICE->CreatePixelShader(code->GetBufferPointer(), code->GetBufferSize(), NULL, &mPixShader); + break; + case GEOMETRY_SHADER: + res = D3D11DEVICE->CreateGeometryShader(code->GetBufferPointer(), code->GetBufferSize(), NULL, &mGeoShader); + break; + case DOMAIN_SHADER: + break; + case HULL_SHADER: + break; + case COMPUTE_SHADER: + break; + default: + break; + } - if(gDisassembleAllShaders) - { - ID3DBlob* disassem = NULL; - D3DDisassemble(code->GetBufferPointer(), code->GetBufferSize(), 0, NULL, &disassem); - mDissasembly = (const char*)disassem->GetBufferPointer(); + if (FAILED(res)) + { + AssertFatal(false, "D3D11Shader::_compilershader- failed to create shader"); + } - String filename = filePath.getFullPath(); - filename.replace( ".hlsl", "_dis.txt" ); + if(res == S_OK) + { + HRESULT reflectionResult = D3DReflect(code->GetBufferPointer(), code->GetBufferSize(), IID_ID3D11ShaderReflection, (void**)&reflectionTable); + if(FAILED(reflectionResult)) + AssertFatal(false, "D3D11Shader::_compilershader - Failed to get shader reflection table interface"); + } - FileStream *fstream = FileStream::createAndOpen( filename, Torque::FS::File::Write ); - if ( fstream ) - { - fstream->write( mDissasembly ); - fstream->close(); - delete fstream; - } - - SAFE_RELEASE(disassem); - } - -#endif - - if (target.compare("ps_", 3) == 0) - res = D3D11DEVICE->CreatePixelShader(code->GetBufferPointer(), code->GetBufferSize(), NULL, &mPixShader); - else if (target.compare("vs_", 3) == 0) - res = D3D11DEVICE->CreateVertexShader(code->GetBufferPointer(), code->GetBufferSize(), NULL, &mVertShader); - - if (FAILED(res)) - { - AssertFatal(false, "D3D11Shader::_compilershader- failed to create shader"); - } - - if(res == S_OK){ - HRESULT reflectionResult = D3DReflect(code->GetBufferPointer(), code->GetBufferSize(), IID_ID3D11ShaderReflection, (void**)&reflectionTable); - if(FAILED(reflectionResult)) - AssertFatal(false, "D3D11Shader::_compilershader - Failed to get shader reflection table interface"); - } - - if(res == S_OK) - _getShaderConstants(reflectionTable, bufferLayout, samplerDescriptions); - -#ifdef TORQUE_ENABLE_CSF_GENERATION - - // Ok, we've got a valid shader and constants, let's write them all out. - if (!_saveCompiledOutput(filePath, code, bufferLayout) && smLogErrors) - Con::errorf( "GFXD3D11Shader::_compileShader - Unable to save shader compile output for: %s", - filePath.getFullPath().c_str()); -#endif + if(res == S_OK) + _getShaderConstants(reflectionTable, shaderStage); if(FAILED(res) && smLogErrors) Con::errorf("GFXD3D11Shader::_compileShader - Unable to create shader for '%s'.", filePath.getFullPath().c_str()); @@ -1010,403 +834,325 @@ bool GFXD3D11Shader::_compileShader( const Torque::Path &filePath, bool result = code && SUCCEEDED(res); #ifdef TORQUE_DEBUG - if (target.compare("vs_", 3) == 0) + String shader; + switch (shaderStage) { - String vertShader = mVertexFile.getFileName(); - mVertShader->SetPrivateData(WKPDID_D3DDebugObjectName, vertShader.size(), vertShader.c_str()); - } - else if (target.compare("ps_", 3) == 0) - { - String pixelShader = mPixelFile.getFileName(); - mPixShader->SetPrivateData(WKPDID_D3DDebugObjectName, pixelShader.size(), pixelShader.c_str()); + case VERTEX_SHADER: + shader = mVertexFile.getFileName(); + mVertShader->SetPrivateData(WKPDID_D3DDebugObjectName, shader.size(), shader.c_str()); + break; + case PIXEL_SHADER: + shader = mPixelFile.getFileName(); + mPixShader->SetPrivateData(WKPDID_D3DDebugObjectName, shader.size(), shader.c_str()); + break; + case GEOMETRY_SHADER: + shader = mGeometryFile.getFileName(); + mGeoShader->SetPrivateData(WKPDID_D3DDebugObjectName, shader.size(), shader.c_str()); + break; + case DOMAIN_SHADER: + break; + case HULL_SHADER: + break; + case COMPUTE_SHADER: + break; + default: + break; } #endif - - SAFE_RELEASE(code); + + SAFE_RELEASE(code); SAFE_RELEASE(reflectionTable); SAFE_RELEASE(errorBuff); return result; } -void GFXD3D11Shader::_getShaderConstants( ID3D11ShaderReflection *refTable, - GenericConstBufferLayout *bufferLayoutIn, - Vector &samplerDescriptions ) + +void GFXD3D11Shader::_getShaderConstants( ID3D11ShaderReflection* refTable, + GFXShaderStage shaderStage) { - PROFILE_SCOPE( GFXD3D11Shader_GetShaderConstants ); + PROFILE_SCOPE(GFXD3D11Shader_GetShaderConstants); AssertFatal(refTable, "NULL constant table not allowed, is this an assembly shader?"); - GFXD3D11ConstBufferLayout *bufferLayout = (GFXD3D11ConstBufferLayout*)bufferLayoutIn; - Vector &subBuffers = bufferLayout->getSubBufferDesc(); - subBuffers.clear(); - - D3D11_SHADER_DESC tableDesc; - HRESULT hr = refTable->GetDesc(&tableDesc); - if (FAILED(hr)) + D3D11_SHADER_DESC shaderDesc; + if (refTable->GetDesc(&shaderDesc) != S_OK) { - AssertFatal(false, "Shader Reflection table unable to be created"); + AssertFatal(false, "Shader Reflection table unable to be created"); } - - //offset for sub constant buffers - U32 bufferOffset = 0; - for (U32 i = 0; i < tableDesc.ConstantBuffers; i++) + // we loop through and account for the most common data types. + for (U32 i = 0; i < shaderDesc.ConstantBuffers; i++) { - ID3D11ShaderReflectionConstantBuffer* constantBuffer = refTable->GetConstantBufferByIndex(i); - D3D11_SHADER_BUFFER_DESC constantBufferDesc; + GFXShaderConstDesc desc; + ID3D11ShaderReflectionConstantBuffer* constantBuffer = refTable->GetConstantBufferByIndex(i); + D3D11_SHADER_BUFFER_DESC constantBufferDesc; if (constantBuffer->GetDesc(&constantBufferDesc) == S_OK) { - - #ifdef TORQUE_DEBUG - AssertFatal(constantBufferDesc.Type == D3D_CT_CBUFFER, "Only scalar cbuffers supported for now."); - - if (String::compare(constantBufferDesc.Name, "$Globals") != 0 && String::compare(constantBufferDesc.Name, "$Params") != 0) - AssertFatal(false, "Only $Global and $Params cbuffer supported for now."); - #endif - #ifdef D3D11_DEBUG_SPEW - Con::printf("Constant Buffer Name: %s", constantBufferDesc.Name); - #endif - - for(U32 j =0; j< constantBufferDesc.Variables; j++) - { - GFXShaderConstDesc desc; - ID3D11ShaderReflectionVariable* variable = constantBuffer->GetVariableByIndex(j); - D3D11_SHADER_VARIABLE_DESC variableDesc; - D3D11_SHADER_TYPE_DESC variableTypeDesc; - - variable->GetDesc(&variableDesc); - - ID3D11ShaderReflectionType* variableType =variable->GetType(); - - variableType->GetDesc(&variableTypeDesc); - desc.name = String(variableDesc.Name); - // Prepend a "$" if it doesn't exist. Just to make things consistent. - if (desc.name.find("$") != 0) - desc.name = String::ToString("$%s", desc.name.c_str()); - - bool unusedVar = variableDesc.uFlags & D3D_SVF_USED ? false : true; - - if (variableTypeDesc.Elements == 0) - desc.arraySize = 1; - else - desc.arraySize = variableTypeDesc.Elements; - - #ifdef D3D11_DEBUG_SPEW - Con::printf("Variable Name %s:, offset: %d, size: %d, constantDesc.Elements: %d", desc.name.c_str(), variableDesc.StartOffset, variableDesc.Size, desc.arraySize); - #endif - if (_convertShaderVariable(variableTypeDesc, desc)) + desc.name = String(constantBufferDesc.Name); + desc.size = constantBufferDesc.Size; + desc.constType = GFXSCT_ConstBuffer; + desc.shaderStage = shaderStage; + desc.samplerReg = -1; + // get our binding point. + D3D11_SHADER_INPUT_BIND_DESC shaderInputBind; + refTable->GetResourceBindingDescByName(constantBufferDesc.Name, &shaderInputBind); + desc.bindPoint = shaderInputBind.BindPoint; + if (String::compare(desc.name, "$Globals") == 0 || String::compare(desc.name, "$Params") == 0) + { + switch (shaderStage) { - //The HLSL compiler for 4.0 and above doesn't strip out unused registered constants. We'll have to do it manually - if (!unusedVar) + case VERTEX_SHADER: + desc.name = desc.name + "_" + mVertexFile.getFileName(); + break; + case PIXEL_SHADER: + desc.name = desc.name + "_" + mPixelFile.getFileName(); + break; + case GEOMETRY_SHADER: + desc.name = desc.name + "_" + mGeometryFile.getFileName(); + break; + case DOMAIN_SHADER: + break; + case HULL_SHADER: + break; + case COMPUTE_SHADER: + break; + default: + break; + } + } + + mBuffers[desc.name] = desc; + + // now loop vars and add them to mShaderConsts. + for (U32 j = 0; j < constantBufferDesc.Variables; j++) + { + ID3D11ShaderReflectionVariable* bufferVar = constantBuffer->GetVariableByIndex(j); + D3D11_SHADER_VARIABLE_DESC shaderVarDesc; + bufferVar->GetDesc(&shaderVarDesc); + + D3D11_SHADER_TYPE_DESC shaderTypeDesc; + bufferVar->GetType()->GetDesc(&shaderTypeDesc); + + if (shaderTypeDesc.Class == D3D_SVC_STRUCT) + { + // we gotta loop through its variables =/ add support in future. for now continue so it skips. + // no idea how to handle arrays of structs.... + /*for (U32 j = 0; j < shaderTypeDesc.Members; j++) { - mShaderConsts.push_back(desc); - U32 alignBytes = getAlignmentValue(desc.constType); - U32 paramSize = variableDesc.Size; - bufferLayout->addParameter( desc.name, - desc.constType, - variableDesc.StartOffset + bufferOffset, - paramSize, - desc.arraySize, - alignBytes); + GFXShaderConstDesc memVarDesc; + ID3D11ShaderReflectionType* memType = bufferVar->GetType()->GetMemberTypeByIndex(j); + D3D11_SHADER_TYPE_DESC memTypeDesc; + memType->GetDesc(&memTypeDesc); + memVarDesc.name = String(shaderVarDesc.Name) + "." + String(memTypeDesc.Name); + if (memVarDesc.name.find("$") != 0) + memVarDesc.name = String::ToString("$%s", memVarDesc.name.c_str()); - } //unusedVar - } //_convertShaderVariable - } //constantBufferDesc.Variables + #ifdef D3D11_DEBUG_SPEW + Con::printf("Variable Name %s:, offset: %d", memVarDesc.name.c_str(), memVarDesc.Offset); + #endif - // fill out our const sub buffer sizes etc - ConstSubBufferDesc subBufferDesc; - subBufferDesc.size = constantBufferDesc.Size; - subBufferDesc.start = bufferOffset; - subBuffers.push_back(subBufferDesc); - // increase our bufferOffset by the constant buffer size - bufferOffset += constantBufferDesc.Size; + }*/ + + continue; + } + else + { + GFXShaderConstDesc varDesc; + varDesc.name = String(shaderVarDesc.Name); + if (varDesc.name.find("$") != 0) + varDesc.name = String::ToString("$%s", varDesc.name.c_str()); + + // set the bind point to the same as the const buffer. + varDesc.bindPoint = desc.bindPoint; + varDesc.offset = shaderVarDesc.StartOffset; + varDesc.arraySize = mMax(shaderTypeDesc.Elements, 1); + varDesc.size = shaderVarDesc.Size; + varDesc.shaderStage = shaderStage; + varDesc.samplerReg = -1; + varDesc.constType = convertConstType(shaderTypeDesc); + +#ifdef D3D11_DEBUG_SPEW + Con::printf("Variable Name %s:, offset: %d, size: %d, constantDesc.Elements: %d", varDesc.name.c_str(), varDesc.offset, varDesc.size, varDesc.arraySize); +#endif + mShaderConsts.push_back(varDesc); + } + } } else - AssertFatal(false, "Unable to get shader constant description! (may need more elements of constantDesc"); + { + AssertFatal(false, "Unable to get shader constant description! (may need more elements of constantDesc"); + } + } - // Set buffer size to the aligned size - bufferLayout->setSize(bufferOffset); - - - //get the sampler descriptions from the resource binding description - U32 resourceCount = tableDesc.BoundResources; - for (U32 i = 0; i < resourceCount; i++) + for (U32 i = 0; i < shaderDesc.BoundResources; i++) { GFXShaderConstDesc desc; - D3D11_SHADER_INPUT_BIND_DESC bindDesc; - refTable->GetResourceBindingDesc(i, &bindDesc); + D3D11_SHADER_INPUT_BIND_DESC shaderInputBind; + refTable->GetResourceBindingDesc(i, &shaderInputBind); - switch (bindDesc.Type) + if (shaderInputBind.Type == D3D_SIT_TEXTURE || shaderInputBind.Type == D3D_SIT_UAV_RWTYPED) + { + // these should return shaderResourceViews and add them to shaderResources. + /*switch (shaderInputBind.Dimension) + { + case D3D_SRV_DIMENSION::D3D_SRV_DIMENSION_TEXTURE1D: + break; + case D3D_SRV_DIMENSION::D3D_SRV_DIMENSION_TEXTURE1DARRAY: + break; + case D3D_SRV_DIMENSION::D3D_SRV_DIMENSION_TEXTURE2D: + break; + case D3D_SRV_DIMENSION::D3D_SRV_DIMENSION_TEXTURE2DARRAY: + break; + case D3D_SRV_DIMENSION::D3D_SRV_DIMENSION_TEXTURE2DMS: + break; + case D3D_SRV_DIMENSION::D3D_SRV_DIMENSION_TEXTURE2DMSARRAY: + break; + case D3D_SRV_DIMENSION::D3D_SRV_DIMENSION_TEXTURE3D: + break; + case D3D_SRV_DIMENSION::D3D_SRV_DIMENSION_TEXTURECUBE: + break; + case D3D_SRV_DIMENSION::D3D_SRV_DIMENSION_TEXTURECUBEARRAY: + break; + case D3D_SRV_DIMENSION::D3D_SRV_DIMENSION_BUFFER: + break; + case D3D_SRV_DIMENSION::D3D_SRV_DIMENSION_BUFFEREX: + break; + default: + break; + }*/ + } + else if (shaderInputBind.Type == D3D_SIT_SAMPLER) { - case D3D_SIT_SAMPLER: // Prepend a "$" if it doesn't exist. Just to make things consistent. - desc.name = String(bindDesc.Name); + desc.name = String(shaderInputBind.Name); if (desc.name.find("$") != 0) desc.name = String::ToString("$%s", desc.name.c_str()); desc.constType = GFXSCT_Sampler; - desc.arraySize = bindDesc.BindPoint; - samplerDescriptions.push_back(desc); - break; - + desc.samplerReg = shaderInputBind.BindPoint; + desc.bindPoint = -1; + desc.shaderStage = shaderStage; + desc.arraySize = shaderInputBind.BindCount; + mSamplerDescriptions.push_back(desc); + } + else if (shaderInputBind.Type == D3D_SIT_UAV_RWSTRUCTURED || + shaderInputBind.Type == D3D_SIT_UAV_RWBYTEADDRESS || + shaderInputBind.Type == D3D_SIT_UAV_APPEND_STRUCTURED || + shaderInputBind.Type == D3D_SIT_UAV_CONSUME_STRUCTURED || + shaderInputBind.Type == D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER) + { + // these should return an unorderedAccessViews and add them to shaderResources. + } + else if (shaderInputBind.Type == D3D_SIT_STRUCTURED || + shaderInputBind.Type == D3D_SIT_BYTEADDRESS) + { + // these should return shaderResourceViews and add them to shaderResources. } } - } -bool GFXD3D11Shader::_convertShaderVariable(const D3D11_SHADER_TYPE_DESC &typeDesc, GFXShaderConstDesc &desc) +GFXShaderConstType GFXD3D11Shader::convertConstType(const D3D11_SHADER_TYPE_DESC typeDesc) { - switch (typeDesc.Type) + if (typeDesc.Class == D3D_SVC_SCALAR || typeDesc.Class == D3D_SVC_VECTOR) { - case D3D_SVT_INT: - { - switch (typeDesc.Class) + switch (typeDesc.Type) { - case D3D_SVC_SCALAR: - desc.constType = GFXSCT_Int; + case D3D_SVT_BOOL: + return (GFXShaderConstType)((U32)GFXSCT_Bool + typeDesc.Columns - 1); break; - case D3D_SVC_VECTOR: - { - switch (typeDesc.Columns) - { - case 1: - desc.constType = GFXSCT_Int; - break; - case 2: - desc.constType = GFXSCT_Int2; - break; - case 3: - desc.constType = GFXSCT_Int3; - break; - case 4: - desc.constType = GFXSCT_Int4; - break; - } - } - break; - } - break; - } - case D3D_SVT_FLOAT: - { - switch (typeDesc.Class) - { - case D3D_SVC_SCALAR: - desc.constType = GFXSCT_Float; + case D3D_SVT_INT: + return (GFXShaderConstType)((U32)GFXSCT_Int + typeDesc.Columns - 1); break; - case D3D_SVC_VECTOR: + case D3D_SVT_FLOAT: + return (GFXShaderConstType)((U32)GFXSCT_Float + typeDesc.Columns - 1); + break; + case D3D_SVT_UINT: + return (GFXShaderConstType)((U32)GFXSCT_UInt + typeDesc.Columns - 1); + break; + default: + AssertFatal(false, "Unknown shader constant class enum, maybe you could add it?"); + break; + } + } + else if (typeDesc.Class == D3D_SVC_MATRIX_COLUMNS || typeDesc.Class == D3D_SVC_MATRIX_ROWS) + { + if (typeDesc.Type != D3D_SVT_FLOAT) { - switch (typeDesc.Columns) - { - case 1: - desc.constType = GFXSCT_Float; - break; - case 2: - desc.constType = GFXSCT_Float2; - break; - case 3: - desc.constType = GFXSCT_Float3; - break; - case 4: - desc.constType = GFXSCT_Float4; - break; - } + AssertFatal(false, "Only Float matrices are supported for now. Support for other types needs to be added."); } - break; - case D3D_SVC_MATRIX_ROWS: - case D3D_SVC_MATRIX_COLUMNS: + + switch (typeDesc.Rows) { - switch (typeDesc.Rows) - { - case 3: - desc.constType = typeDesc.Columns == 4 ? GFXSCT_Float3x4 : GFXSCT_Float3x3; - break; - case 4: - desc.constType = typeDesc.Columns == 3 ? GFXSCT_Float4x3 : GFXSCT_Float4x4; - break; - } - } - break; - case D3D_SVC_OBJECT: - case D3D_SVC_STRUCT: - return false; + case 3: + return typeDesc.Columns == 4 ? GFXSCT_Float3x4 : GFXSCT_Float3x3; + break; + case 4: + return typeDesc.Columns == 3 ? GFXSCT_Float4x3 : GFXSCT_Float4x4; + break; } } - break; - default: - AssertFatal(false, "Unknown shader constant class enum"); - break; - } + return GFXSCT_Uknown; - return true; } -const U32 GFXD3D11Shader::smCompiledShaderTag = MakeFourCC('t','c','s','f'); - -bool GFXD3D11Shader::_saveCompiledOutput( const Torque::Path &filePath, - ID3DBlob *buffer, - GenericConstBufferLayout *bufferLayout, - Vector &samplerDescriptions ) +void GFXD3D11Shader::_buildShaderConstantHandles() { - Torque::Path outputPath(filePath); - outputPath.setExtension("csf"); // "C"ompiled "S"hader "F"ile (fancy!) - - FileStream f; - if (!f.open(outputPath, Torque::FS::File::Write)) - return false; - if (!f.write(smCompiledShaderTag)) - return false; - // We could reverse engineer the structure in the compiled output, but this - // is a bit easier because we can just read it into the struct that we want. - if (!bufferLayout->write(&f)) - return false; - - U32 bufferSize = buffer->GetBufferSize(); - if (!f.write(bufferSize)) - return false; - if (!f.write(bufferSize, buffer->GetBufferPointer())) - return false; - - // Write out sampler descriptions. - - f.write( samplerDescriptions.size() ); - - for ( U32 i = 0; i < samplerDescriptions.size(); i++ ) + // loop through all constants, add them to the handle map + // and add the const buffers to the buffer map. + for (U32 i = 0; i < mShaderConsts.size(); i++) { - f.write( samplerDescriptions[i].name ); - f.write( (U32)(samplerDescriptions[i].constType) ); - f.write( samplerDescriptions[i].arraySize ); - } - - f.close(); - - return true; -} - -bool GFXD3D11Shader::_loadCompiledOutput( const Torque::Path &filePath, - const String &target, - GenericConstBufferLayout *bufferLayout, - Vector &samplerDescriptions ) -{ - Torque::Path outputPath(filePath); - outputPath.setExtension("csf"); // "C"ompiled "S"hader "F"ile (fancy!) - - FileStream f; - if (!f.open(outputPath, Torque::FS::File::Read)) - return false; - U32 fileTag; - if (!f.read(&fileTag)) - return false; - if (fileTag != smCompiledShaderTag) - return false; - if (!bufferLayout->read(&f)) - return false; - U32 bufferSize; - if (!f.read(&bufferSize)) - return false; - U32 waterMark = FrameAllocator::getWaterMark(); - DWORD* buffer = static_cast(FrameAllocator::alloc(bufferSize)); - if (!f.read(bufferSize, buffer)) - return false; - - // Read sampler descriptions. - - U32 samplerCount; - f.read( &samplerCount ); - - for ( U32 i = 0; i < samplerCount; i++ ) - { - GFXShaderConstDesc samplerDesc; - f.read( &(samplerDesc.name) ); - f.read( (U32*)&(samplerDesc.constType) ); - f.read( &(samplerDesc.arraySize) ); - - samplerDescriptions.push_back( samplerDesc ); - } - - f.close(); - - HRESULT res; - if (target.compare("ps_", 3) == 0) - res = D3D11DEVICE->CreatePixelShader(buffer, bufferSize, NULL, &mPixShader); - else - res = D3D11DEVICE->CreateVertexShader(buffer, bufferSize, NULL, &mVertShader); - AssertFatal(SUCCEEDED(res), "Unable to load shader!"); - - FrameAllocator::setWaterMark(waterMark); - return SUCCEEDED(res); -} - -void GFXD3D11Shader::_buildShaderConstantHandles(GenericConstBufferLayout* layout, bool vertexConst) -{ - for (U32 i = 0; i < layout->getParameterCount(); i++) - { - GenericConstBufferLayout::ParamDesc pd; - layout->getDesc(i, pd); - GFXD3D11ShaderConstHandle* handle; - HandleMap::Iterator j = mHandles.find(pd.name); - + GFXShaderConstDesc& desc = mShaderConsts[i]; + HandleMap::Iterator j = mHandles.find(desc.name); + // already added? reinit just in case.. + // not sure if we need to do anything different with samplers. if (j != mHandles.end()) { - handle = j->value; - handle->mShader = this; - handle->setValid( true ); - } - else - { - handle = new GFXD3D11ShaderConstHandle(); - handle->mShader = this; - mHandles[pd.name] = handle; - handle->setValid( true ); - } - - if (vertexConst) - { - handle->mVertexConstant = true; - handle->mVertexHandle = pd; - } - else - { - handle->mPixelConstant = true; - handle->mPixelHandle = pd; - } - } -} - -void GFXD3D11Shader::_buildSamplerShaderConstantHandles( Vector &samplerDescriptions ) -{ - Vector::iterator iter = samplerDescriptions.begin(); - for ( ; iter != samplerDescriptions.end(); iter++ ) - { - const GFXShaderConstDesc &desc = *iter; - - AssertFatal( desc.constType == GFXSCT_Sampler || - desc.constType == GFXSCT_SamplerCube || - desc.constType == GFXSCT_SamplerCubeArray || - desc.constType == GFXSCT_SamplerTextureArray, - "GFXD3D11Shader::_buildSamplerShaderConstantHandles - Invalid samplerDescription type!" ); - - GFXD3D11ShaderConstHandle *handle; - HandleMap::Iterator j = mHandles.find(desc.name); - - if ( j != mHandles.end() ) handle = j->value; + handle->mShader = this; + if((handle->mStageFlags & desc.shaderStage) == 0) + handle->mStageFlags |= (U32)desc.shaderStage; + handle->addDesc(desc.shaderStage, desc); + handle->setValid(true); + } else { - handle = new GFXD3D11ShaderConstHandle(); - mHandles[desc.name] = handle; + handle = new GFXD3D11ShaderConstHandle(this, desc); + mHandles[desc.name] = handle; + } + } + + for (U32 j = 0; j < mSamplerDescriptions.size(); j++) + { + const GFXShaderConstDesc& desc = mSamplerDescriptions[j]; + + AssertFatal(desc.constType == GFXSCT_Sampler || + desc.constType == GFXSCT_SamplerCube || + desc.constType == GFXSCT_SamplerCubeArray || + desc.constType == GFXSCT_SamplerTextureArray, + "GFXD3D11Shader::_buildShaderConstantHandles - Invalid samplerDescription type!"); + + GFXD3D11ShaderConstHandle* handle; + HandleMap::Iterator k = mHandles.find(desc.name); + // already added? reinit just in case.. + // not sure if we need to do anything different with samplers. + if (k != mHandles.end()) + { + handle = k->value; + } + else + { + handle = new GFXD3D11ShaderConstHandle(this, desc); + mHandles[desc.name] = handle; } - handle->mShader = this; - handle->setValid( true ); - handle->mPixelConstant = true; - handle->mPixelHandle.name = desc.name; - handle->mPixelHandle.constType = desc.constType; - handle->mPixelHandle.offset = desc.arraySize; + handle->mShader = this; + handle->setValid(true); } + + _buildInstancingShaderConstantHandles(); } void GFXD3D11Shader::_buildInstancingShaderConstantHandles() @@ -1419,40 +1165,42 @@ void GFXD3D11Shader::_buildInstancingShaderConstantHandles() for ( U32 i=0; i < mInstancingFormat->getElementCount(); i++ ) { const GFXVertexElement &element = mInstancingFormat->getElement( i ); - + String constName = String::ToString( "$%s", element.getSemantic().c_str() ); GFXD3D11ShaderConstHandle *handle; HandleMap::Iterator j = mHandles.find( constName ); + GFXShaderConstDesc desc; + + desc.name = constName; + desc.offset = offset; + switch (element.getType()) + { + case GFXDeclType_Float4: + desc.constType = GFXSCT_Float4; + break; + + default: + desc.constType = GFXSCT_Float; + break; + } + desc.shaderStage = GFXShaderStage::PIXEL_SHADER; + desc.samplerReg = -1; + desc.size = 0; + desc.arraySize = 1; if ( j != mHandles.end() ) - handle = j->value; + handle = j->value; else { - handle = new GFXD3D11ShaderConstHandle(); - mHandles[ constName ] = handle; + handle = new GFXD3D11ShaderConstHandle(this, desc); + mHandles[ constName ] = handle; } handle->mShader = this; - handle->setValid( true ); + handle->setValid( true ); handle->mInstancingConstant = true; - // We shouldn't have an instancing constant that is also - // a vertex or pixel constant! This means the shader features - // are confused as to what is instanced. - // - AssertFatal( !handle->mVertexConstant && - !handle->mPixelConstant, - "GFXD3D11Shader::_buildInstancingShaderConstantHandles - Bad instanced constant!" ); - - // HACK: The GFXD3D11ShaderConstHandle will check mVertexConstant then - // fall back to reading the mPixelHandle values. We depend on this here - // and store the data we need in the mPixelHandle constant although its - // not a pixel shader constant. - // - handle->mPixelHandle.name = constName; - handle->mPixelHandle.offset = offset; - // If this is a matrix we will have 2 or 3 more of these // semantics with the same name after it. for ( ; i < mInstancingFormat->getElementCount(); i++ ) @@ -1470,34 +1218,35 @@ void GFXD3D11Shader::_buildInstancingShaderConstantHandles() GFXShaderConstBufferRef GFXD3D11Shader::allocConstBuffer() { - if (mVertexConstBufferLayout && mPixelConstBufferLayout) - { - GFXD3D11ShaderConstBuffer* buffer = new GFXD3D11ShaderConstBuffer(this, mVertexConstBufferLayout, mPixelConstBufferLayout); - mActiveBuffers.push_back( buffer ); - buffer->registerResourceWithDevice(getOwningDevice()); - return buffer; - } + GFXD3D11ShaderConstBuffer* buffer = new GFXD3D11ShaderConstBuffer(this); - return NULL; + for (BufferMap::Iterator i = mBuffers.begin(); i != mBuffers.end(); ++i) + { + // add our buffer descriptions to the full const buffer. + buffer->addBuffer(i->value); + } + + mActiveBuffers.push_back( buffer ); + buffer->registerResourceWithDevice(getOwningDevice()); + return buffer; } /// Returns a shader constant handle for name, if the variable doesn't exist NULL is returned. GFXShaderConstHandle* GFXD3D11Shader::getShaderConstHandle(const String& name) { - HandleMap::Iterator i = mHandles.find(name); + HandleMap::Iterator i = mHandles.find(name); if ( i != mHandles.end() ) { return i->value; - } - else - { - GFXD3D11ShaderConstHandle *handle = new GFXD3D11ShaderConstHandle(); + } + else + { + GFXD3D11ShaderConstHandle *handle = new GFXD3D11ShaderConstHandle(this); handle->setValid( false ); - handle->mShader = this; mHandles[name] = handle; - return handle; - } + return handle; + } } GFXShaderConstHandle* GFXD3D11Shader::findShaderConstHandle(const String& name) @@ -1517,7 +1266,7 @@ const Vector& GFXD3D11Shader::getShaderConstDesc() const } U32 GFXD3D11Shader::getAlignmentValue(const GFXShaderConstType constType) const -{ +{ const U32 mRowSizeF = 16; const U32 mRowSizeI = 16; @@ -1525,7 +1274,7 @@ U32 GFXD3D11Shader::getAlignmentValue(const GFXShaderConstType constType) const { case GFXSCT_Float : case GFXSCT_Float2 : - case GFXSCT_Float3 : + case GFXSCT_Float3 : case GFXSCT_Float4 : return mRowSizeF; break; @@ -1533,7 +1282,7 @@ U32 GFXD3D11Shader::getAlignmentValue(const GFXShaderConstType constType) const case GFXSCT_Float2x2 : return mRowSizeF * 2; break; - case GFXSCT_Float3x3 : + case GFXSCT_Float3x3 : return mRowSizeF * 3; break; case GFXSCT_Float4x3: @@ -1541,11 +1290,11 @@ U32 GFXD3D11Shader::getAlignmentValue(const GFXShaderConstType constType) const break; case GFXSCT_Float4x4 : return mRowSizeF * 4; - break; + break; //// Scalar case GFXSCT_Int : case GFXSCT_Int2 : - case GFXSCT_Int3 : + case GFXSCT_Int3 : case GFXSCT_Int4 : return mRowSizeI; break; diff --git a/Engine/source/gfx/D3D11/gfxD3D11Shader.h b/Engine/source/gfx/D3D11/gfxD3D11Shader.h index 8ae17a979..80bb55b5e 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Shader.h +++ b/Engine/source/gfx/D3D11/gfxD3D11Shader.h @@ -29,282 +29,87 @@ #include "core/util/tDictionary.h" #include "gfx/gfxShader.h" #include "gfx/gfxResource.h" -#include "gfx/genericConstBuffer.h" #include "gfx/D3D11/gfxD3D11Device.h" class GFXD3D11Shader; -enum CONST_CLASS +typedef CompoundKey BufferKey; + +struct BufferRange { - D3DPC_SCALAR, - D3DPC_VECTOR, - D3DPC_MATRIX_ROWS, - D3DPC_MATRIX_COLUMNS, - D3DPC_OBJECT, - D3DPC_STRUCT -}; + U32 mBufMin = U32_MAX; + U32 mBufMax = 0; -enum CONST_TYPE -{ - D3DPT_VOID, - D3DPT_BOOL, - D3DPT_INT, - D3DPT_FLOAT, - D3DPT_STRING, - D3DPT_TEXTURE, - D3DPT_TEXTURE1D, - D3DPT_TEXTURE2D, - D3DPT_TEXTURE3D, - D3DPT_TEXTURECUBE, - D3DPT_SAMPLER, - D3DPT_SAMPLER1D, - D3DPT_SAMPLER2D, - D3DPT_SAMPLER3D, - D3DPT_SAMPLERCUBE, - D3DPT_PIXELSHADER, - D3DPT_VERTEXSHADER, - D3DPT_PIXELFRAGMENT, - D3DPT_VERTEXFRAGMENT -}; - -enum REGISTER_TYPE -{ - D3DRS_BOOL, - D3DRS_INT4, - D3DRS_FLOAT4, - D3DRS_SAMPLER -}; - -struct ConstantDesc -{ - String Name = String::EmptyString; - S32 RegisterIndex = 0; - S32 RegisterCount = 0; - S32 Rows = 0; - S32 Columns = 0; - S32 Elements = 0; - S32 StructMembers = 0; - REGISTER_TYPE RegisterSet = D3DRS_FLOAT4; - CONST_CLASS Class = D3DPC_SCALAR; - CONST_TYPE Type = D3DPT_FLOAT; - U32 Bytes = 0; -}; - -class ConstantTable -{ -public: - bool Create(const void* data); - - U32 GetConstantCount() const { return m_constants.size(); } - const String& GetCreator() const { return m_creator; } - - const ConstantDesc* GetConstantByIndex(U32 i) const { return &m_constants[i]; } - const ConstantDesc* GetConstantByName(const String& name) const; - - void ClearConstants() { m_constants.clear(); } - -private: - Vector m_constants; - String m_creator; -}; - -// Structs -struct CTHeader -{ - U32 Size; - U32 Creator; - U32 Version; - U32 Constants; - U32 ConstantInfo; - U32 Flags; - U32 Target; -}; - -struct CTInfo -{ - U32 Name; - U16 RegisterSet; - U16 RegisterIndex; - U16 RegisterCount; - U16 Reserved; - U32 TypeInfo; - U32 DefaultValue; -}; - -struct CTType -{ - U16 Class; - U16 Type; - U16 Rows; - U16 Columns; - U16 Elements; - U16 StructMembers; - U32 StructMemberInfo; -}; - -// Shader instruction opcodes -const U32 SIO_COMMENT = 0x0000FFFE; -const U32 SIO_END = 0x0000FFFF; -const U32 SI_OPCODE_MASK = 0x0000FFFF; -const U32 SI_COMMENTSIZE_MASK = 0x7FFF0000; -const U32 CTAB_CONSTANT = 0x42415443; - -// Member functions -inline bool ConstantTable::Create(const void* data) -{ - const U32* ptr = static_cast(data); - while(*++ptr != SIO_END) + inline void addSlot(U32 slot) { - if((*ptr & SI_OPCODE_MASK) == SIO_COMMENT) - { - // Check for CTAB comment - U32 comment_size = (*ptr & SI_COMMENTSIZE_MASK) >> 16; - if(*(ptr+1) != CTAB_CONSTANT) - { - ptr += comment_size; - continue; - } - - // Read header - const char* ctab = reinterpret_cast(ptr+2); - size_t ctab_size = (comment_size-1)*4; - - const CTHeader* header = reinterpret_cast(ctab); - if(ctab_size < sizeof(*header) || header->Size != sizeof(*header)) - return false; - m_creator = ctab + header->Creator; - - // Read constants - m_constants.reserve(header->Constants); - const CTInfo* info = reinterpret_cast(ctab + header->ConstantInfo); - for(U32 i = 0; i < header->Constants; ++i) - { - const CTType* type = reinterpret_cast(ctab + info[i].TypeInfo); - - // Fill struct - ConstantDesc desc; - desc.Name = ctab + info[i].Name; - desc.RegisterSet = static_cast(info[i].RegisterSet); - desc.RegisterIndex = info[i].RegisterIndex; - desc.RegisterCount = info[i].RegisterCount; - desc.Rows = type->Rows; - desc.Class = static_cast(type->Class); - desc.Type = static_cast(type->Type); - desc.Columns = type->Columns; - desc.Elements = type->Elements; - desc.StructMembers = type->StructMembers; - desc.Bytes = 4 * desc.Elements * desc.Rows * desc.Columns; - m_constants.push_back(desc); - } - - return true; - } + mBufMin = getMin(mBufMin, slot); + mBufMax = getMax(mBufMax, slot); } - return false; -} -inline const ConstantDesc* ConstantTable::GetConstantByName(const String& name) const + inline bool isValid() const { return mBufMin <= mBufMax; } +}; + +struct ConstantBuffer { - Vector::const_iterator it; - for(it = m_constants.begin(); it != m_constants.end(); ++it) - { - if(it->Name == name) - return &(*it); - } - return NULL; -} - -/////////////////// Constant Buffers ///////////////////////////// - -// Maximum number of CBuffers ($Globals & $Params) -const U32 CBUFFER_MAX = 2; - -struct ConstSubBufferDesc -{ - U32 start; + U8* data; U32 size; - - ConstSubBufferDesc() : start(0), size(0){} -}; - -class GFXD3D11ConstBufferLayout : public GenericConstBufferLayout -{ -public: - GFXD3D11ConstBufferLayout(); - /// Get our constant sub buffer data - Vector &getSubBufferDesc(){ return mSubBuffers; } - - /// We need to manually set the size due to D3D11 alignment - void setSize(U32 size){ mBufferSize = size;} - - /// Set a parameter, given a base pointer - virtual bool set(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer); - -protected: - /// Set a matrix, given a base pointer - virtual bool setMatrix(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer); - - Vector mSubBuffers; + bool isDirty; }; class GFXD3D11ShaderConstHandle : public GFXShaderConstHandle { -public: + friend class GFXD3D11Shader; +public: + typedef Map DescMap; - // GFXShaderConstHandle - const String& getName() const; - GFXShaderConstType getType() const; - U32 getArraySize() const; + GFXD3D11ShaderConstHandle(GFXD3D11Shader* shader); + GFXD3D11ShaderConstHandle(GFXD3D11Shader* shader, + const GFXShaderConstDesc& desc); - WeakRefPtr mShader; + virtual ~GFXD3D11ShaderConstHandle(); + void addDesc(GFXShaderStage stage, const GFXShaderConstDesc& desc); + const GFXShaderConstDesc getDesc(GFXShaderStage stage); + const String& getName() const { return mDesc.name; } + GFXShaderConstType getType() const { return mDesc.constType; } + U32 getArraySize() const { return mDesc.arraySize; } - bool mVertexConstant; - GenericConstBufferLayout::ParamDesc mVertexHandle; - bool mPixelConstant; - GenericConstBufferLayout::ParamDesc mPixelHandle; - - /// Is true if this constant is for hardware mesh instancing. - /// - /// Note: We currently store its settings in mPixelHandle. - /// - bool mInstancingConstant; - - void setValid( bool valid ) { mValid = valid; } - S32 getSamplerRegister() const; + U32 getSize() const { return mDesc.size; } + void setValid(bool valid) { mValid = valid; } + /// @warning This will always return the value assigned when the shader was + /// initialized. If the value is later changed this method won't reflect that. + S32 getSamplerRegister() const { return (!isSampler() || !mValid) ? -1 : mDesc.samplerReg; } // Returns true if this is a handle to a sampler register. - bool isSampler() const + bool isSampler() const { - return ( mPixelConstant && mPixelHandle.constType >= GFXSCT_Sampler ) || ( mVertexConstant && mVertexHandle.constType >= GFXSCT_Sampler ); + return (getType() >= GFXSCT_Sampler); } /// Restore to uninitialized state. void clear() { mShader = NULL; - mVertexConstant = false; - mPixelConstant = false; mInstancingConstant = false; - mVertexHandle.clear(); - mPixelHandle.clear(); mValid = false; } - GFXD3D11ShaderConstHandle(); + GFXShaderConstDesc mDesc; + GFXD3D11Shader* mShader; + DescMap mDescMap; + U32 mStageFlags; + bool mInstancingConstant; }; /// The D3D11 implementation of a shader constant buffer. class GFXD3D11ShaderConstBuffer : public GFXShaderConstBuffer { - friend class GFXD3D11Shader; // Cache device context ID3D11DeviceContext* mDeviceContext; public: + typedef Map BufferMap; - GFXD3D11ShaderConstBuffer(GFXD3D11Shader* shader, - GFXD3D11ConstBufferLayout* vertexLayout, - GFXD3D11ConstBufferLayout* pixelLayout); + GFXD3D11ShaderConstBuffer(GFXD3D11Shader* shader); virtual ~GFXD3D11ShaderConstBuffer(); @@ -312,8 +117,7 @@ public: /// @param mPrevShaderBuffer The previously active buffer void activate(GFXD3D11ShaderConstBuffer *prevShaderBuffer); - /// Used internally by GXD3D11ShaderConstBuffer to determine if it's dirty. - bool isDirty(); + void addBuffer(const GFXShaderConstDesc desc); /// Called from GFXD3D11Shader when constants have changed and need /// to be the shader this buffer references is reloaded. @@ -344,33 +148,20 @@ public: // GFXResource virtual const String describeSelf() const; - virtual void zombify(); - virtual void resurrect(); + virtual void zombify() {} + virtual void resurrect() {} protected: - - void _createBuffers(); - - template - inline void SET_CONSTANT(GFXShaderConstHandle* handle, - const T& fv, - GenericConstBuffer *vBuffer, - GenericConstBuffer *pBuffer); - - // Constant buffers, VSSetConstantBuffers1 has issues on win 7. So unfortunately for now we have multiple constant buffers - ID3D11Buffer* mConstantBuffersV[CBUFFER_MAX]; - ID3D11Buffer* mConstantBuffersP[CBUFFER_MAX]; - - /// We keep a weak reference to the shader + friend class GFXD3D11Shader; + /// We keep a weak reference to the shader /// because it will often be deleted. WeakRefPtr mShader; + BufferMap mBufferMap; - //vertex - GFXD3D11ConstBufferLayout* mVertexConstBufferLayout; - GenericConstBuffer* mVertexConstBuffer; - //pixel - GFXD3D11ConstBufferLayout* mPixelConstBufferLayout; - GenericConstBuffer* mPixelConstBuffer; + void setMatrix(const GFXShaderConstDesc& handle, const U32 inSize, const void* data, U8* basePointer); + void internalSet(GFXShaderConstHandle* handle, const U32 inSize, const void* data); + + ID3D11Buffer* mBoundBuffers[6][16]; }; class gfxD3D11Include; @@ -385,17 +176,17 @@ class GFXD3D11Shader : public GFXShader public: typedef Map HandleMap; + typedef Map BufferMap; GFXD3D11Shader(); - virtual ~GFXD3D11Shader(); + virtual ~GFXD3D11Shader(); // GFXShader virtual GFXShaderConstBufferRef allocConstBuffer(); virtual const Vector& getShaderConstDesc() const; - virtual GFXShaderConstHandle* getShaderConstHandle(const String& name); + virtual GFXShaderConstHandle* getShaderConstHandle(const String& name); virtual GFXShaderConstHandle* findShaderConstHandle(const String& name); virtual U32 getAlignmentValue(const GFXShaderConstType constType) const; - virtual bool getDisassembly( String &outStr ) const; // GFXResource virtual void zombify(); @@ -403,71 +194,36 @@ public: protected: - virtual bool _init(); - - static const U32 smCompiledShaderTag; - - ConstantTable table; + virtual bool _init(); ID3D11VertexShader *mVertShader; ID3D11PixelShader *mPixShader; - - GFXD3D11ConstBufferLayout* mVertexConstBufferLayout; - GFXD3D11ConstBufferLayout* mPixelConstBufferLayout; + ID3D11GeometryShader *mGeoShader; static gfxD3DIncludeRef smD3DInclude; HandleMap mHandles; - - /// The shader disassembly from DX when this shader is compiled. - /// We only store this data in non-release builds. - String mDissasembly; - - /// Vector of sampler type descriptions consolidated from _compileShader. - Vector mSamplerDescriptions; + BufferMap mBuffers; /// Vector of descriptions (consolidated for the getShaderConstDesc call) Vector mShaderConsts; - + Vector mSamplerDescriptions; + // These two functions are used when compiling shaders from hlsl - virtual bool _compileShader( const Torque::Path &filePath, - const String &target, - const D3D_SHADER_MACRO *defines, - GenericConstBufferLayout *bufferLayout, - Vector &samplerDescriptions ); + virtual bool _compileShader( const Torque::Path &filePath, + GFXShaderStage shaderStage, + const D3D_SHADER_MACRO *defines); - void _getShaderConstants( ID3D11ShaderReflection* refTable, - GenericConstBufferLayout *bufferLayout, - Vector &samplerDescriptions ); + void _getShaderConstants( ID3D11ShaderReflection* refTable, + GFXShaderStage shaderStage); - bool _convertShaderVariable(const D3D11_SHADER_TYPE_DESC &typeDesc, GFXShaderConstDesc &desc); - - - bool _saveCompiledOutput( const Torque::Path &filePath, - ID3DBlob *buffer, - GenericConstBufferLayout *bufferLayout, - Vector &samplerDescriptions ); - - // Loads precompiled shaders - bool _loadCompiledOutput( const Torque::Path &filePath, - const String &target, - GenericConstBufferLayout *bufferLayoutF, - Vector &samplerDescriptions ); - // This is used in both cases - virtual void _buildShaderConstantHandles(GenericConstBufferLayout *layout, bool vertexConst); - - virtual void _buildSamplerShaderConstantHandles( Vector &samplerDescriptions ); - - /// Used to build the instancing shader constants from - /// the instancing vertex format. + virtual void _buildShaderConstantHandles(); void _buildInstancingShaderConstantHandles(); + + GFXShaderConstType convertConstType(D3D11_SHADER_TYPE_DESC typeDesc); + }; -inline bool GFXD3D11Shader::getDisassembly(String &outStr) const -{ - outStr = mDissasembly; - return (outStr.isNotEmpty()); -} #endif diff --git a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp index 6eb79895c..d4a6455b4 100644 --- a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp +++ b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp @@ -34,6 +34,9 @@ #define STBIWDEF static inline #endif +#pragma warning( push ) +#pragma warning( disable : 4505 ) // unreferenced function removed. + #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_STATIC #include "stb_image.h" @@ -42,6 +45,8 @@ #define STB_IMAGE_WRITE_STATIC #include "stb_image_write.h" +#pragma warning(pop) + static bool sReadSTB(const Torque::Path& path, GBitmap* bitmap); static bool sReadStreamSTB(Stream& stream, GBitmap* bitmap, U32 len); @@ -147,7 +152,7 @@ bool sReadSTB(const Torque::Path& path, GBitmap* bitmap) U32 buffSize = readIes->getStreamSize(); char* buffer = new char[buffSize]; readIes->read(buffSize, buffer); - + IESFileInfo info; IESLoadHelper IESLoader; @@ -399,8 +404,6 @@ bool sWriteSTB(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel) String ext = path.getExtension(); - - U32 stride = width * bytes; // we always have at least 1 U32 comp = 1; @@ -554,7 +557,6 @@ void DeferredPNGWriter::append(GBitmap* bitmap, U32 rows) mData->channels = bitmap->getBytesPerPixel(); } - const U32 height = getMin(bitmap->getHeight(), rows); const dsize_t dataChuckSize = bitmap->getByteSize(); const U8* pSrcData = bitmap->getBits(); diff --git a/Engine/source/gfx/genericConstBuffer.cpp b/Engine/source/gfx/genericConstBuffer.cpp deleted file mode 100644 index 185150720..000000000 --- a/Engine/source/gfx/genericConstBuffer.cpp +++ /dev/null @@ -1,289 +0,0 @@ -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- - -#include "platform/platform.h" -#include "gfx/genericConstBuffer.h" - -#include "platform/profiler.h" -#include "core/stream/stream.h" - - -GenericConstBufferLayout::GenericConstBufferLayout() -{ - VECTOR_SET_ASSOCIATION( mParams ); - - mBufferSize = 0; - mCurrentIndex = 0; - mTimesCleared = 0; -} - -void GenericConstBufferLayout::addParameter(const String& name, const GFXShaderConstType constType, const U32 offset, const U32 size, const U32 arraySize, const U32 alignValue) -{ -#ifdef TORQUE_DEBUG - // Make sure we don't have overlapping parameters - S32 start = offset; - S32 end = offset + size; - for (Params::iterator i = mParams.begin(); i != mParams.end(); i++) - { - const ParamDesc& dp = *i; - S32 pstart = dp.offset; - S32 pend = pstart + dp.size; - pstart -= start; - pend -= end; - // This is like a minkowski sum for two line segments, if the newly formed line contains - // the origin, then they intersect - bool intersect = ((pstart >= 0 && 0 >= pend) || ((pend >= 0 && 0 >= pstart))); - AssertFatal(!intersect, "Overlapping shader parameter!"); - } -#endif - ParamDesc desc; - desc.name = name; - desc.constType = constType; - desc.offset = offset; - desc.size = size; - desc.arraySize = arraySize; - desc.alignValue = alignValue; - desc.index = mCurrentIndex++; - mParams.push_back(desc); - mBufferSize = getMax(desc.offset + desc.size, mBufferSize); - AssertFatal(mBufferSize, "Empty constant buffer!"); -} - -bool GenericConstBufferLayout::set(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer) -{ - PROFILE_SCOPE(GenericConstBufferLayout_set); - - // Shader compilers like to optimize float4x4 uniforms into float3x3s. - // So long as the real paramater is a matrix of-some-type and the data - // passed in is a MatrixF ( which is will be ), we DO NOT have a - // mismatched const type. - AssertFatal( pd.constType == constType || - ( - ( pd.constType == GFXSCT_Float2x2 || - pd.constType == GFXSCT_Float3x3 || - pd.constType == GFXSCT_Float3x4 || - pd.constType == GFXSCT_Float4x3 || - pd.constType == GFXSCT_Float4x4 ) && - ( constType == GFXSCT_Float2x2 || - constType == GFXSCT_Float3x3 || - constType == GFXSCT_Float3x4 || - constType == GFXSCT_Float4x3 || - constType == GFXSCT_Float4x4 ) - ), "Mismatched const type!" ); - - // This "cute" bit of code allows us to support 2x3 and 3x3 matrices in shader constants but use our MatrixF class. Yes, a hack. -BTR - switch (pd.constType) - { - case GFXSCT_Float2x2 : - case GFXSCT_Float3x3 : - case GFXSCT_Float4x3 : - case GFXSCT_Float4x4 : - return setMatrix(pd, constType, size, data, basePointer); - break; - default : - break; - } - - AssertFatal(pd.size >= size, "Not enough room in the buffer for this data!"); - - // Ok, we only set data if it's different than the data we already have, this maybe more expensive than just setting the data, but - // we'll have to do some timings to see. For example, the lighting shader constants rarely change, but we can't assume that at the - // renderInstMgr level, but we can check down here. -BTR - if (dMemcmp(basePointer+pd.offset, data, size) != 0) - { - dMemcpy(basePointer+pd.offset, data, size); - return true; - } - return false; -} - -bool GenericConstBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer) -{ - PROFILE_SCOPE(GenericConstBufferLayout_setMatrix); - - // We're generic, so just copy the full MatrixF in - AssertFatal(pd.size >= size, "Not enough room in the buffer for this data!"); - - // Matrices are an annoying case because of the alignment issues. There are alignment issues in the matrix itself, and then potential inter matrices alignment issues. - // So GL and DX will need to derive their own GenericConstBufferLayout classes and override this method to deal with that stuff. For GenericConstBuffer, copy the whole - // 4x4 matrix regardless of the target case. - - if (dMemcmp(basePointer+pd.offset, data, size) != 0) - { - dMemcpy(basePointer+pd.offset, data, size); - return true; - } - - return false; -} - -bool GenericConstBufferLayout::getDesc(const String& name, ParamDesc& param) const -{ - for (U32 i = 0; i < mParams.size(); i++) - { - if (mParams[i].name.equal(name)) - { - param = mParams[i]; - return true; - } - } - return false; -} - -bool GenericConstBufferLayout::getDesc(const U32 index, ParamDesc& param) const -{ - if ( index < mParams.size() ) - { - param = mParams[index]; - return true; - } - - return false; -} - -bool GenericConstBufferLayout::write(Stream* s) -{ - // Write out the size of the ParamDesc structure as a sanity check. - if (!s->write((U32) sizeof(ParamDesc))) - return false; - // Next, write out the number of elements we've got. - if (!s->write(mParams.size())) - return false; - for (U32 i = 0; i < mParams.size(); i++) - { - s->write(mParams[i].name); - - if (!s->write(mParams[i].offset)) - return false; - if (!s->write(mParams[i].size)) - return false; - U32 t = (U32) mParams[i].constType; - if (!s->write(t)) - return false; - if (!s->write(mParams[i].arraySize)) - return false; - if (!s->write(mParams[i].alignValue)) - return false; - if (!s->write(mParams[i].index)) - return false; - } - return true; -} - -/// Load this layout from a stream -bool GenericConstBufferLayout::read(Stream* s) -{ - U32 structSize; - if (!s->read(&structSize)) - return false; - if (structSize != sizeof(ParamDesc)) - { - AssertFatal(false, "Invalid shader layout structure size!"); - return false; - } - U32 numParams; - if (!s->read(&numParams)) - return false; - mParams.setSize(numParams); - mBufferSize = 0; - mCurrentIndex = 0; - for (U32 i = 0; i < mParams.size(); i++) - { - s->read(&mParams[i].name); - if (!s->read(&mParams[i].offset)) - return false; - if (!s->read(&mParams[i].size)) - return false; - U32 t; - if (!s->read(&t)) - return false; - mParams[i].constType = (GFXShaderConstType) t; - if (!s->read(&mParams[i].arraySize)) - return false; - if (!s->read(&mParams[i].alignValue)) - return false; - if (!s->read(&mParams[i].index)) - return false; - mBufferSize = getMax(mParams[i].offset + mParams[i].size, mBufferSize); - mCurrentIndex = getMax(mParams[i].index, mCurrentIndex); - } - mCurrentIndex++; - return true; -} - -void GenericConstBufferLayout::clear() -{ - mParams.clear(); - mBufferSize = 0; - mCurrentIndex = 0; - mTimesCleared++; -} - - -GenericConstBuffer::GenericConstBuffer(GenericConstBufferLayout* layout) - : mLayout( layout ), - mBuffer( NULL ), - mDirtyStart( U32_MAX ), - mDirtyEnd( 0 ) -{ - if ( layout && layout->getBufferSize() > 0 ) - { - mBuffer = new U8[mLayout->getBufferSize()]; - - // Always set a default value, that way our isEqual checks - // will work in release as well. - dMemset( mBuffer, 0xFFFF, mLayout->getBufferSize() ); - - #ifdef TORQUE_DEBUG - - // Clear the debug assignment tracking. - mWasAssigned.setSize( layout->getParameterCount() ); - dMemset( mWasAssigned.address(), 0, mWasAssigned.memSize() ); - - #endif - } -} - -GenericConstBuffer::~GenericConstBuffer() -{ - delete [] mBuffer; -} - -#ifdef TORQUE_DEBUG - -void GenericConstBuffer::assertUnassignedConstants( const char *shaderName ) -{ - for ( U32 i=0; i < mWasAssigned.size(); i++ ) - { - if ( mWasAssigned[i] ) - continue; - - GenericConstBufferLayout::ParamDesc pd; - mLayout->getDesc( i, pd ); - - // Assert on the unassigned constant. - //AssertFatal( false, avar( "The '%s' shader constant in shader '%s' was unassigned!", - // pd.name.c_str(), shaderName ) ); - } -} - -#endif diff --git a/Engine/source/gfx/genericConstBuffer.h b/Engine/source/gfx/genericConstBuffer.h deleted file mode 100644 index afa097be7..000000000 --- a/Engine/source/gfx/genericConstBuffer.h +++ /dev/null @@ -1,374 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 _GENERICCONSTBUFFER_H_ -#define _GENERICCONSTBUFFER_H_ - -#ifndef _TORQUE_STRING_H_ -#include "core/util/str.h" -#endif -#ifndef _TDICTIONARY_H_ -#include "core/util/tDictionary.h" -#endif -#ifndef _TVECTOR_H_ -#include "core/util/tVector.h" -#endif -#ifndef _ALIGNEDARRAY_H_ -#include "core/util/tAlignedArray.h" -#endif -#ifndef _COLOR_H_ -#include "core/color.h" -#endif -#ifndef _MMATRIX_H_ -#include "math/mMatrix.h" -#endif -#ifndef _MPOINT2_H_ -#include "math/mPoint2.h" -#endif -#ifndef _GFXENUMS_H_ -#include "gfx/gfxEnums.h" -#endif - -class Stream; - - -/// This class defines the memory layout for a GenericConstBuffer. -class GenericConstBufferLayout -{ -public: - /// Describes the parameters we contain - struct ParamDesc - { - ParamDesc() - : name(), - offset( 0 ), - size( 0 ), - constType( GFXSCT_Float ), - arraySize( 0 ), - alignValue( 0 ), - index( 0 ) - { - } - - void clear() - { - name = String::EmptyString; - offset = 0; - size = 0; - constType = GFXSCT_Float; - arraySize = 0; - alignValue = 0; - index = 0; - } - - /// Parameter name - String name; - - /// Offset into the memory block - U32 offset; - - /// Size of the block - U32 size; - - /// Type of data - GFXShaderConstType constType; - - // For arrays, how many elements - U32 arraySize; - - // Array element alignment value - U32 alignValue; - - /// 0 based index of this param, in order of addParameter calls. - U32 index; - }; - - GenericConstBufferLayout(); - virtual ~GenericConstBufferLayout() {} - - /// Add a parameter to the buffer - virtual void addParameter(const String& name, const GFXShaderConstType constType, const U32 offset, const U32 size, const U32 arraySize, const U32 alignValue); - - /// Get the size of the buffer - inline U32 getBufferSize() const { return mBufferSize; } - - /// Get the number of parameters - inline U32 getParameterCount() const { return mParams.size(); } - - /// Returns the ParamDesc of a parameter - bool getDesc(const String& name, ParamDesc& param) const; - - /// Returns the ParamDesc of a parameter - bool getDesc(const U32 index, ParamDesc& param) const; - - /// Set a parameter, given a base pointer - virtual bool set(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer); - - /// Save this layout to a stream - bool write(Stream* s); - - /// Load this layout from a stream - bool read(Stream* s); - - /// Restore to initial state. - void clear(); - -protected: - - /// Set a matrix, given a base pointer. - virtual bool setMatrix(const ParamDesc& pd, const GFXShaderConstType constType, const U32 size, const void* data, U8* basePointer); - - /// Vector of parameter descriptions. - typedef Vector Params; - - /// Vector of parameter descriptions. - Params mParams; - U32 mBufferSize; - U32 mCurrentIndex; - - // This if for debugging shader reloading and can be removed later. - U32 mTimesCleared; -}; - - -/// This class manages shader constant data in a system memory buffer. It is -/// used by device specific classes for batching together many constant changes -/// which are then copied to the device thru a single API call. -/// -/// @see GenericConstBufferLayout -/// -class GenericConstBuffer -{ -public: - GenericConstBuffer(GenericConstBufferLayout* layout); - ~GenericConstBuffer(); - - /// @name Set shader constant values - /// @{ - /// Actually set shader constant values - /// @param name Name of the constant, this should be a name contained in the array returned in getShaderConstDesc, - /// if an invalid name is used, its ignored, but it's not an error. - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const F32 f) { internalSet(pd, GFXSCT_Float, sizeof(F32), &f); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point2F& fv) { internalSet(pd, GFXSCT_Float2, sizeof(Point2F), &fv); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point3F& fv) { internalSet(pd, GFXSCT_Float3, sizeof(Point3F), &fv); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point4F& fv) { internalSet(pd, GFXSCT_Float4, sizeof(Point4F), &fv); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const PlaneF& fv) { internalSet(pd, GFXSCT_Float4, sizeof(PlaneF), &fv); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const LinearColorF& fv) { internalSet(pd, GFXSCT_Float4, sizeof(Point4F), &fv); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const S32 f) { internalSet(pd, GFXSCT_Int, sizeof(S32), &f); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point2I& fv) { internalSet(pd, GFXSCT_Int2, sizeof(Point2I), &fv); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point3I& fv) { internalSet(pd, GFXSCT_Int3, sizeof(Point3I), &fv); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const Point4I& fv) { internalSet(pd, GFXSCT_Int4, sizeof(Point4I), &fv); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray& fv) { internalSet(pd, GFXSCT_Float, fv.getElementSize() * fv.size(), fv.getBuffer()); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray& fv) { internalSet(pd, GFXSCT_Float2, fv.getElementSize() * fv.size(), fv.getBuffer()); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray& fv) { internalSet(pd, GFXSCT_Float3, fv.getElementSize() * fv.size(), fv.getBuffer()); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray& fv) { internalSet(pd, GFXSCT_Float4, fv.getElementSize() * fv.size(), fv.getBuffer()); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray& fv) { internalSet(pd, GFXSCT_Int, fv.getElementSize() * fv.size(), fv.getBuffer()); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray& fv) { internalSet(pd, GFXSCT_Int2, fv.getElementSize() * fv.size(), fv.getBuffer()); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray& fv) { internalSet(pd, GFXSCT_Int3, fv.getElementSize() * fv.size(), fv.getBuffer()); } - inline void set(const GenericConstBufferLayout::ParamDesc& pd, const AlignedArray& fv) { internalSet(pd, GFXSCT_Int4, fv.getElementSize() * fv.size(), fv.getBuffer()); } - - inline void set( const GenericConstBufferLayout::ParamDesc& pd, const MatrixF& mat, const GFXShaderConstType matrixType ) - { - AssertFatal( matrixType == GFXSCT_Float2x2 || - matrixType == GFXSCT_Float3x3 || - matrixType == GFXSCT_Float3x4 || - matrixType == GFXSCT_Float4x3 || - matrixType == GFXSCT_Float4x4, - "GenericConstBuffer::set() - Invalid matrix type!" ); - - internalSet( pd, matrixType, sizeof(MatrixF), &mat ); - } - - inline void set( const GenericConstBufferLayout::ParamDesc& pd, const MatrixF* mat, const U32 arraySize, const GFXShaderConstType matrixType ) - { - AssertFatal( matrixType == GFXSCT_Float2x2 || - matrixType == GFXSCT_Float3x3 || - matrixType == GFXSCT_Float3x4 || - matrixType == GFXSCT_Float4x3 || - matrixType == GFXSCT_Float4x4, - "GenericConstBuffer::set() - Invalid matrix type!" ); - - internalSet( pd, matrixType, sizeof(MatrixF)*arraySize, mat ); - } - - /// Gets the dirty buffer range and clears the dirty - /// state at the same time. - inline const U8* getDirtyBuffer( U32 *start, U32 *size ); - - /// Gets the entire buffer ignoring dirty range - inline const U8* getEntireBuffer(); - - /// Sets the entire buffer as dirty or clears the dirty state. - inline void setDirty( bool dirty ); - - /// Returns true if the buffer has been modified since the - /// last call to getDirtyBuffer or setDirty. The buffer is - /// not dirty on initial creation. - /// - /// @see getDirtyBuffer - /// @see setDirty - inline bool isDirty() const { return mDirtyEnd != 0; } - - /// Returns true if have the same layout and hold the same - /// data as the input buffer. - inline bool isEqual( const GenericConstBuffer *buffer ) const; - - /// Returns our layout object. - inline GenericConstBufferLayout* getLayout() const { return mLayout; } - - #ifdef TORQUE_DEBUG - - /// Helper function used to assert on unset constants. - void assertUnassignedConstants( const char *shaderName ); - - #endif - -protected: - - /// Returns a pointer to the raw buffer - inline const U8* getBuffer() const { return mBuffer; } - - /// Called by the inlined set functions above to do the - /// real dirty work of copying the data to the right location - /// within the buffer. - inline void internalSet( const GenericConstBufferLayout::ParamDesc &pd, - const GFXShaderConstType constType, - const U32 size, - const void *data ); - - /// The buffer layout. - GenericConstBufferLayout *mLayout; - - /// The pointer to the contant store or - /// NULL if the layout is empty. - U8 *mBuffer; - - /// The byte offset to the start of the dirty - /// range within the buffer or U32_MAX if the - /// buffer is not dirty. - U32 mDirtyStart; - - /// The btye offset to the end of the dirty - /// range within the buffer or 0 if the buffer - /// is not dirty. - U32 mDirtyEnd; - - - #ifdef TORQUE_DEBUG - - /// A vector used to keep track if a constant - /// has beed assigned a value or not. - /// - /// @see assertUnassignedConstants - Vector mWasAssigned; - - #endif -}; - - -// NOTE: These inlines below are here to get the very best possible -// performance when setting the device shader constants and can be -// called 4000-8000 times per frame or more. -// -// You need a very good reason to consider changing them. - -inline void GenericConstBuffer::internalSet( const GenericConstBufferLayout::ParamDesc &pd, - const GFXShaderConstType constType, - const U32 size, - const void *data ) -{ - // NOTE: We should have never gotten here if the buffer - // was null as no valid shader constant could have been - // assigned. - // - // If this happens its a bug in another part of the code. - // - AssertFatal( mBuffer, "GenericConstBuffer::internalSet - The buffer is NULL!" ); - - if ( mLayout->set( pd, constType, size, data, mBuffer ) ) - { - #ifdef TORQUE_DEBUG - - // Update the debug assignment tracking. - mWasAssigned[ pd.index ] = true; - - #endif - - // Keep track of the dirty range so it can be queried - // later in GenericConstBuffer::getDirtyBuffer. - mDirtyStart = getMin( pd.offset, mDirtyStart ); - mDirtyEnd = getMax( pd.offset + pd.size, mDirtyEnd ); - } -} - -inline void GenericConstBuffer::setDirty( bool dirty ) -{ - if ( !mBuffer ) - return; - - if ( dirty ) - { - mDirtyStart = 0; - mDirtyEnd = mLayout->getBufferSize(); - } - else if ( !dirty ) - { - mDirtyStart = U32_MAX; - mDirtyEnd = 0; - } -} - -inline const U8* GenericConstBuffer::getDirtyBuffer( U32 *start, U32 *size ) -{ - AssertFatal( isDirty(), "GenericConstBuffer::getDirtyBuffer() - Buffer is not dirty!" ); - AssertFatal( mDirtyEnd > mDirtyStart, "GenericConstBuffer::getDirtyBuffer() - Dirty range is invalid!" ); - AssertFatal( mBuffer, "GenericConstBuffer::getDirtyBuffer() - Buffer is empty!" ); - - // Use the area we calculated during internalSet. - *size = mDirtyEnd - mDirtyStart; - *start = mDirtyStart; - const U8 *buffer = mBuffer + mDirtyStart; - - // Clear the dirty state while we're here. - mDirtyStart = U32_MAX; - mDirtyEnd = 0; - - return buffer; -} - -inline const U8* GenericConstBuffer::getEntireBuffer() -{ - AssertFatal(mBuffer, "GenericConstBuffer::getDirtyBuffer() - Buffer is empty!"); - - return mBuffer; -} - -inline bool GenericConstBuffer::isEqual( const GenericConstBuffer *buffer ) const -{ - U32 bsize = mLayout->getBufferSize(); - if ( bsize != buffer->mLayout->getBufferSize() ) - return false; - - return dMemcmp( mBuffer, buffer->getBuffer(), bsize ) == 0; -} - -#endif // _GENERICCONSTBUFFER_H_ diff --git a/Engine/source/gfx/gfxDrawUtil.cpp b/Engine/source/gfx/gfxDrawUtil.cpp index 1dd9f5fca..49de99d5e 100644 --- a/Engine/source/gfx/gfxDrawUtil.cpp +++ b/Engine/source/gfx/gfxDrawUtil.cpp @@ -34,7 +34,7 @@ #include "gfx/gfxPrimitiveBuffer.h" #include "gfx/primBuilder.h" #include "gfx/gfxDebugEvent.h" - +#include "materials/shaderData.h" #include "math/mPolyhedron.impl.h" @@ -45,7 +45,7 @@ GFXDrawUtil::GFXDrawUtil( GFXDevice * d) mTextAnchorColor.set(0xFF, 0xFF, 0xFF, 0xFF); mFontRenderBatcher = new FontRenderBatcher(); - _setupStateBlocks(); + _setupStateBlocks(); } GFXDrawUtil::~GFXDrawUtil() @@ -90,6 +90,33 @@ void GFXDrawUtil::_setupStateBlocks() rectFill.setZReadWrite(false); rectFill.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha); mRectFillSB = mDevice->createStateBlock(rectFill); + + // Find ShaderData + ShaderData* shaderData; + mRoundRectangleShader = Sim::findObject("RoundedRectangleGUI", shaderData) ? shaderData->getShader() : NULL; + if (!mRoundRectangleShader) + { + Con::errorf("GFXDrawUtil - could not find Rounded Rectangle shader"); + } + // Create ShaderConstBuffer and Handles + mRoundRectangleShaderConsts = mRoundRectangleShader->allocConstBuffer(); + + mCircleShader = Sim::findObject("CircularGUI", shaderData) ? shaderData->getShader() : NULL; + if (!mCircleShader) + { + Con::errorf("GFXDrawUtil - could not find circle shader"); + } + // Create ShaderConstBuffer and Handles + mCircleShaderConsts = mCircleShader->allocConstBuffer(); + + mThickLineShader = Sim::findObject("ThickLineGUI", shaderData) ? shaderData->getShader() : NULL; + if (!mThickLineShader) + { + Con::errorf("GFXDrawUtil - could not find Thick line shader"); + } + // Create ShaderConstBuffer and Handles + mThickLineShaderConsts = mThickLineShader->allocConstBuffer(); + } //----------------------------------------------------------------------------- @@ -118,13 +145,13 @@ void GFXDrawUtil::setTextAnchorColor( const ColorI &ancColor ) //----------------------------------------------------------------------------- // Draw Text //----------------------------------------------------------------------------- -U32 GFXDrawUtil::drawText( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, +U32 GFXDrawUtil::drawText( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, const ColorI *colorTable, const U32 maxColorIndex, F32 rot ) { return drawTextN( font, ptDraw, in_string, dStrlen(in_string), colorTable, maxColorIndex, rot ); } -U32 GFXDrawUtil::drawText( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, +U32 GFXDrawUtil::drawText( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, const ColorI *colorTable, const U32 maxColorIndex, F32 rot ) { return drawTextN( font, ptDraw, in_string, dStrlen(in_string), colorTable, maxColorIndex, rot ); @@ -154,7 +181,7 @@ U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF8 *in_s return drawTextN( font, ptDraw, ubuf, n, colorTable, maxColorIndex, rot ); } -U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, +U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, U32 n, const ColorI *colorTable, const U32 maxColorIndex, F32 rot ) { // return on zero length strings @@ -178,11 +205,11 @@ U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_ S32 ptX = 0; - // Queue everything for render. + // Queue everything for render. mFontRenderBatcher->init(font, n); U32 i; - UTF16 c; + UTF16 c; for (i = 0, c = in_string[i]; i < n && in_string[i]; i++, c = in_string[i]) { switch(c) @@ -193,25 +220,25 @@ U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_ case 14: { // Color code - if (colorTable) + if (colorTable) { - static U8 remap[15] = - { + static U8 remap[15] = + { 0x0, // 0 special null terminator 0x0, // 1 ascii start-of-heading?? - 0x1, - 0x2, - 0x3, - 0x4, - 0x5, - 0x6, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, 0x0, // 8 special backspace 0x0, // 9 special tab 0x0, // a special \n - 0x7, + 0x7, 0x8, 0x0, // a special \r - 0x9 + 0x9 }; U8 remapped = remap[c]; @@ -256,7 +283,7 @@ U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_ } // Tab character - case dT('\t'): + case dT('\t'): { if ( tabci == NULL ) tabci = &(font->getCharInfo( dT(' ') )); @@ -272,7 +299,7 @@ U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_ // Don't draw invalid characters. default: { - if( !font->isValidChar( c ) ) + if( !font->isValidChar( c ) ) continue; } } @@ -354,7 +381,7 @@ void GFXDrawUtil::drawBitmapStretchSR( GFXTextureObject* texture, const RectF &d { // Sanity if no texture is specified. if(!texture) - return; + return; GFXVertexBufferHandle verts(mDevice, 4, GFXBufferTypeVolatile ); verts.lock(); @@ -369,13 +396,13 @@ void GFXDrawUtil::drawBitmapStretchSR( GFXTextureObject* texture, const RectF &d F32 screenTop = dstRect.point.y; F32 screenBottom = (dstRect.point.y + dstRect.extent.y); - if( in_flip & GFXBitmapFlip_X ) + if( in_flip & GFXBitmapFlip_X ) { F32 temp = texLeft; texLeft = texRight; texRight = temp; } - if( in_flip & GFXBitmapFlip_Y ) + if( in_flip & GFXBitmapFlip_Y ) { F32 temp = texTop; texTop = texBottom; @@ -435,7 +462,7 @@ void GFXDrawUtil::drawBitmapStretchSR( GFXTextureObject* texture, const RectF &d AssertFatal(false, "No GFXDrawUtil state block defined for this filter type!"); mDevice->setStateBlock(mBitmapStretchSB); break; - } + } mDevice->setTexture( 0, texture ); mDevice->setupGenericShaders( GFXDevice::GSModColorTexture ); @@ -445,7 +472,7 @@ void GFXDrawUtil::drawBitmapStretchSR( GFXTextureObject* texture, const RectF &d //----------------------------------------------------------------------------- // Draw Rectangle //----------------------------------------------------------------------------- -void GFXDrawUtil::drawRect( const Point2I &upperLeft, const Point2I &lowerRight, const ColorI &color ) +void GFXDrawUtil::drawRect( const Point2I &upperLeft, const Point2I &lowerRight, const ColorI &color ) { drawRect( Point2F((F32)upperLeft.x,(F32)upperLeft.y),Point2F((F32)lowerRight.x,(F32)lowerRight.y),color); } @@ -513,57 +540,99 @@ void GFXDrawUtil::drawRect( const Point2F &upperLeft, const Point2F &lowerRight, //----------------------------------------------------------------------------- // Draw Rectangle Fill //----------------------------------------------------------------------------- -void GFXDrawUtil::drawRectFill( const RectF &rect, const ColorI &color ) +void GFXDrawUtil::drawRectFill(const RectF& rect, const ColorI& color, const F32& borderSize, const ColorI& borderColor) { - drawRectFill(rect.point, Point2F(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color ); + drawRoundedRect(0.0f, rect.point, Point2F(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color, borderSize, borderColor); } -void GFXDrawUtil::drawRectFill( const Point2I &upperLeft, const Point2I &lowerRight, const ColorI &color ) -{ - drawRectFill(Point2F((F32)upperLeft.x, (F32)upperLeft.y), Point2F((F32)lowerRight.x, (F32)lowerRight.y), color); +void GFXDrawUtil::drawRectFill(const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize, const ColorI& borderColor) +{ + drawRoundedRect(0.0f, Point2F((F32)upperLeft.x, (F32)upperLeft.y), Point2F((F32)lowerRight.x, (F32)lowerRight.y), color, borderSize, borderColor); } -void GFXDrawUtil::drawRectFill( const RectI &rect, const ColorI &color ) +void GFXDrawUtil::drawRectFill(const RectI& rect, const ColorI& color, const F32& borderSize, const ColorI& borderColor) { - drawRectFill(rect.point, Point2I(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color ); + drawRoundedRect(0.0f, rect.point, Point2I(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color, borderSize, borderColor); } -void GFXDrawUtil::drawRectFill( const Point2F &upperLeft, const Point2F &lowerRight, const ColorI &color ) +void GFXDrawUtil::drawRectFill(const Point2F& upperLeft, const Point2F& lowerRight, const ColorI& color, const F32& borderSize,const ColorI& borderColor) +{ + // draw a rounded rect with 0 radiuse. + drawRoundedRect(0.0f, upperLeft, lowerRight, color, borderSize, borderColor); +} + +void GFXDrawUtil::drawRoundedRect(const F32& cornerRadius, const RectI& rect, const ColorI& color, const F32& borderSize, const ColorI& borderColor) +{ + drawRoundedRect(cornerRadius, rect.point, Point2I(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color, borderSize, borderColor); +} + +void GFXDrawUtil::drawRoundedRect(const F32& cornerRadius, const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize, const ColorI& borderColor) +{ + drawRoundedRect(cornerRadius, Point2F((F32)upperLeft.x, (F32)upperLeft.y), Point2F((F32)lowerRight.x, (F32)lowerRight.y), color, borderSize, borderColor); +} + +void GFXDrawUtil::drawRoundedRect(const F32& cornerRadius, + const Point2F& upperLeft, + const Point2F& lowerRight, + const ColorI& color, + const F32& borderSize, + const ColorI& borderColor) { - // - // Convert Box a----------x - // | | - // x----------b - // Into Quad - // v0---------v1 - // | a x | - // | | - // | x b | - // v2---------v3 - // // NorthWest and NorthEast facing offset vectors - Point2F nw(-0.5,-0.5); /* \ */ - Point2F ne(0.5,-0.5); /* / */ + Point2F nw(-0.5, -0.5); /* \ */ + Point2F ne(0.5, -0.5); /* / */ GFXVertexBufferHandle verts(mDevice, 4, GFXBufferTypeVolatile); verts.lock(); F32 ulOffset = 0.5f - mDevice->getFillConventionOffset(); - - verts[0].point.set( upperLeft.x+nw.x + ulOffset, upperLeft.y+nw.y + ulOffset, 0.0f ); - verts[1].point.set( lowerRight.x + ne.x + ulOffset, upperLeft.y + ne.y + ulOffset, 0.0f); - verts[2].point.set( upperLeft.x - ne.x + ulOffset, lowerRight.y - ne.y + ulOffset, 0.0f); - verts[3].point.set( lowerRight.x - nw.x + ulOffset, lowerRight.y - nw.y + ulOffset, 0.0f); + + verts[0].point.set(upperLeft.x + nw.x + ulOffset, upperLeft.y + nw.y + ulOffset, 0.0f); + verts[1].point.set(lowerRight.x + ne.x + ulOffset, upperLeft.y + ne.y + ulOffset, 0.0f); + verts[2].point.set(upperLeft.x - ne.x + ulOffset, lowerRight.y - ne.y + ulOffset, 0.0f); + verts[3].point.set(lowerRight.x - nw.x + ulOffset, lowerRight.y - nw.y + ulOffset, 0.0f); for (S32 i = 0; i < 4; i++) verts[i].color = color; verts.unlock(); + mDevice->setVertexBuffer(verts); mDevice->setStateBlock(mRectFillSB); - mDevice->setVertexBuffer( verts ); - mDevice->setupGenericShaders(); - mDevice->drawPrimitive( GFXTriangleStrip, 0, 2 ); + + Point2F topLeftCorner(upperLeft.x + nw.x + ulOffset, upperLeft.y + nw.y + ulOffset); + Point2F bottomRightCorner(lowerRight.x - nw.x + ulOffset, lowerRight.y - nw.y + ulOffset); + + /*mDevice->setupGenericShaders();*/ + GFX->setShader(mRoundRectangleShader); + GFX->setShaderConstBuffer(mRoundRectangleShaderConsts); + + MatrixF tempMatrix = GFX->getProjectionMatrix() * GFX->getViewMatrix() * GFX->getWorldMatrix(); + Point2F size((F32)(bottomRightCorner.x - topLeftCorner.x), (F32)(bottomRightCorner.y - topLeftCorner.y)); + + F32 minExtent = mMin(size.x, size.y); + + F32 radius = cornerRadius; + if ((minExtent * 0.5) < radius) + { + radius = mClampF(radius, 0.0f, (minExtent * 0.5)); + } + + mRoundRectangleShaderConsts->set(mRoundRectangleShader->getShaderConstHandle("$modelView"), tempMatrix, GFXSCT_Float4x4); + mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$radius"), radius); + mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$sizeUni"), size); + mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$borderSize"), borderSize); + mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$borderCol"), borderColor); + + Point2F rectCenter((F32)(topLeftCorner.x + (size.x / 2.0)), (F32)(topLeftCorner.y + (size.y / 2.0))); + mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$rectCenter"), rectCenter); + + const Point2I& resolution = GFX->getActiveRenderTarget()->getSize(); + Point2F TargetSize(1.0 / (F32)resolution.x, 1.0 / (F32)resolution.y); + + mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$oneOverViewport"), TargetSize); + + mDevice->drawPrimitive(GFXTriangleStrip, 0, 2); } void GFXDrawUtil::draw2DSquare( const Point2F &screenPoint, F32 width, F32 spinAngle ) @@ -608,7 +677,73 @@ void GFXDrawUtil::draw2DSquare( const Point2F &screenPoint, F32 width, F32 spinA } //----------------------------------------------------------------------------- -// Draw Line +// Draw Circle : FILL +//----------------------------------------------------------------------------- +void GFXDrawUtil::drawCircleFill(const RectI& rect, const ColorI& color, F32 radius, const F32& borderSize, const ColorI& borderColor) +{ + drawCircleFill(rect.point, Point2I(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color, radius, borderSize, borderColor); +} + +void GFXDrawUtil::drawCircleFill(const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, F32 radius, const F32& borderSize, const ColorI& borderColor) +{ + drawCircleFill(Point2F((F32)upperLeft.x, (F32)upperLeft.y), Point2F((F32)lowerRight.x, (F32)lowerRight.y), color, radius, borderSize, borderColor); +} + +void GFXDrawUtil::drawCircleFill(const Point2F& upperLeft, const Point2F& lowerRight, const ColorI& color, F32 radius, const F32& borderSize, const ColorI& borderColor) +{ + // NorthWest and NorthEast facing offset vectors + Point2F nw(-0.5, -0.5); /* \ */ + Point2F ne(0.5, -0.5); /* / */ + + GFXVertexBufferHandle verts(mDevice, 4, GFXBufferTypeVolatile); + verts.lock(); + + F32 ulOffset = 0.5f - mDevice->getFillConventionOffset(); + + verts[0].point.set(upperLeft.x + nw.x + ulOffset, upperLeft.y + nw.y + ulOffset, 0.0f); + verts[1].point.set(lowerRight.x + ne.x + ulOffset, upperLeft.y + ne.y + ulOffset, 0.0f); + verts[2].point.set(upperLeft.x - ne.x + ulOffset, lowerRight.y - ne.y + ulOffset, 0.0f); + verts[3].point.set(lowerRight.x - nw.x + ulOffset, lowerRight.y - nw.y + ulOffset, 0.0f); + for (S32 i = 0; i < 4; i++) + verts[i].color = color; + + verts.unlock(); + mDevice->setVertexBuffer(verts); + + mDevice->setStateBlock(mRectFillSB); + + Point2F topLeftCorner(upperLeft.x + nw.x + ulOffset, upperLeft.y + nw.y + ulOffset); + Point2F bottomRightCorner(lowerRight.x - nw.x + ulOffset, lowerRight.y - nw.y + ulOffset); + + /*mDevice->setupGenericShaders();*/ + GFX->setShader(mCircleShader); + GFX->setShaderConstBuffer(mCircleShaderConsts); + + MatrixF tempMatrix = GFX->getProjectionMatrix() * GFX->getViewMatrix() * GFX->getWorldMatrix(); + Point2F size((F32)(bottomRightCorner.x - topLeftCorner.x), (F32)(bottomRightCorner.y - topLeftCorner.y)); + + Point2F rectCenter((F32)(topLeftCorner.x + (size.x / 2.0)), (F32)(topLeftCorner.y + (size.y / 2.0))); + mCircleShaderConsts->setSafe(mCircleShader->getShaderConstHandle("$rectCenter"), rectCenter); + + F32 minExtent = mMin(size.x, size.y); + F32 shaderRadius = radius; + + if ((minExtent * 0.5) < shaderRadius) + { + shaderRadius = mClampF(radius, 0.0f, (minExtent * 0.5)); + } + + mCircleShaderConsts->set(mCircleShader->getShaderConstHandle("$modelView"), tempMatrix, GFXSCT_Float4x4); + mCircleShaderConsts->setSafe(mCircleShader->getShaderConstHandle("$radius"), shaderRadius); + mCircleShaderConsts->setSafe(mCircleShader->getShaderConstHandle("$sizeUni"), size); + mCircleShaderConsts->setSafe(mCircleShader->getShaderConstHandle("$borderSize"), borderSize); + mCircleShaderConsts->setSafe(mCircleShader->getShaderConstHandle("$borderCol"), borderColor); + + mDevice->drawPrimitive(GFXTriangleStrip, 0, 2); +} + +//----------------------------------------------------------------------------- +// Draw Lines : Single Pixel //----------------------------------------------------------------------------- void GFXDrawUtil::drawLine( const Point3F &startPt, const Point3F &endPt, const ColorI &color ) { @@ -648,6 +783,55 @@ void GFXDrawUtil::drawLine( F32 x1, F32 y1, F32 z1, F32 x2, F32 y2, F32 z2, cons mDevice->drawPrimitive( GFXLineList, 0, 1 ); } +//----------------------------------------------------------------------------- +// Draw Lines : Thick +//----------------------------------------------------------------------------- +void GFXDrawUtil::drawThickLine(const Point2I& startPt, const Point2I& endPt, const ColorI& color, const F32& thickness) +{ + drawThickLine(startPt.x, startPt.y, 0.0f, endPt.x, endPt.y, 0.0f, color, thickness); +} + +void GFXDrawUtil::drawThickLine(const Point2F& startPt, const Point2F& endPt, const ColorI& color, const F32& thickness) +{ + drawThickLine(startPt.x, startPt.y, 0.0f, endPt.x, endPt.y, 0.0f, color, thickness); +} + +void GFXDrawUtil::drawThickLine(F32 x1, F32 y1, F32 z1, F32 x2, F32 y2, F32 z2, const ColorI& color, const F32& thickness) +{ + // less than 2 just draw an ordinary line... why you ever here.... + if (thickness < 2.0f) + { + drawLine(x1, y1, z1, x2, y2, z2, color); + return; + } + + GFXVertexBufferHandle verts(mDevice, 2, GFXBufferTypeVolatile); + verts.lock(); + + verts[0].point.set(x1, y1, z1); + verts[1].point.set(x2, y2, z2); + verts[0].color = color; + verts[1].color = color; + + verts.unlock(); + + mDevice->setVertexBuffer(verts); + mDevice->setStateBlock(mRectFillSB); + GFX->setShader(mThickLineShader); + GFX->setShaderConstBuffer(mThickLineShaderConsts); + + MatrixF tempMatrix = GFX->getProjectionMatrix() * GFX->getViewMatrix() * GFX->getWorldMatrix(); + mThickLineShaderConsts->set(mThickLineShader->getShaderConstHandle("$modelView"), tempMatrix, GFXSCT_Float4x4); + mThickLineShaderConsts->setSafe(mThickLineShader->getShaderConstHandle("$thickness"), thickness); + + const Point2I& resolution = GFX->getActiveRenderTarget()->getSize(); + Point2F TargetSize(1.0 / (F32)resolution.x, 1.0 / (F32)resolution.y); + + mThickLineShaderConsts->setSafe(mThickLineShader->getShaderConstHandle("$oneOverViewport"), TargetSize); + + mDevice->drawPrimitive(GFXLineList, 0, 1); +} + //----------------------------------------------------------------------------- // 3D World Draw Misc //----------------------------------------------------------------------------- @@ -713,13 +897,13 @@ void GFXDrawUtil::drawSphere( const GFXStateBlockDesc &desc, F32 radius, const P //----------------------------------------------------------------------------- -static const Point3F cubePoints[8] = +static const Point3F cubePoints[8] = { Point3F(-1, -1, -1), Point3F(-1, -1, 1), Point3F(-1, 1, -1), Point3F(-1, 1, 1), Point3F( 1, -1, -1), Point3F( 1, -1, 1), Point3F( 1, 1, -1), Point3F( 1, 1, 1) }; -static const U32 cubeFaces[6][4] = +static const U32 cubeFaces[6][4] = { { 0, 4, 6, 2 }, { 0, 2, 3, 1 }, { 0, 1, 5, 4 }, { 3, 2, 6, 7 }, { 7, 6, 4, 5 }, { 3, 7, 5, 1 } @@ -812,7 +996,7 @@ void GFXDrawUtil::drawPolygon( const GFXStateBlockDesc& desc, const Point3F* poi for( U32 i = 0; i < numPoints; ++ i ) xfm->mulP( verts[ i ].point ); } - + if( isWireframe ) { verts[ numVerts - 1 ].point = verts[ 0 ].point; @@ -899,7 +1083,7 @@ void GFXDrawUtil::_drawSolidCube( const GFXStateBlockDesc &desc, const Point3F & for(S32 i = 0; i < 6; i++) { idx = cubeFaces[i][0]; - verts[vertexIndex].point = cubePoints[idx] * halfSize; + verts[vertexIndex].point = cubePoints[idx] * halfSize; verts[vertexIndex].color = color; vertexIndex++; @@ -1110,13 +1294,13 @@ void GFXDrawUtil::drawObjectBox( const GFXStateBlockDesc &desc, const Point3F &s Point3F cubePts[8]; for (U32 i = 0; i < 8; i++) { - cubePts[i] = cubePoints[i]/2; + cubePts[i] = cubePoints[i]/2; } - // 8 corner points of the box + // 8 corner points of the box for ( U32 i = 0; i < 8; i++ ) { - //const Point3F &start = cubePoints[i]; + //const Point3F &start = cubePoints[i]; // 3 lines per corner point for ( U32 j = 0; j < 3; j++ ) @@ -1128,7 +1312,7 @@ void GFXDrawUtil::drawObjectBox( const GFXStateBlockDesc &desc, const Point3F &s scaledObjMat.mulP(start); PrimBuild::vertex3fv(start); scaledObjMat.mulP(end); - PrimBuild::vertex3fv(end); + PrimBuild::vertex3fv(end); } } @@ -1164,10 +1348,10 @@ void GFXDrawUtil::drawCapsule( const GFXStateBlockDesc &desc, const Point3F &cen } void GFXDrawUtil::_drawSolidCapsule( const GFXStateBlockDesc &desc, const Point3F ¢er, F32 radius, F32 height, const ColorI &color, const MatrixF *xfm ) -{ +{ MatrixF mat; if ( xfm ) - mat = *xfm; + mat = *xfm; else mat = MatrixF::Identity; @@ -1176,7 +1360,7 @@ void GFXDrawUtil::_drawSolidCapsule( const GFXStateBlockDesc &desc, const Point3 verts.lock(); for (S32 i=0; i 0 ) vSteps = size.y / step.y + 0.5 + 1; - + if( uSteps <= 1 || vSteps <= 1 ) return; - + const U32 numVertices = uSteps * 2 + vSteps * 2; const U32 numLines = uSteps + vSteps; - + Point3F origin; switch( plane ) { @@ -1552,14 +1736,14 @@ void GFXDrawUtil::drawPlaneGrid( const GFXStateBlockDesc &desc, const Point3F &p verts[vertCount].point = Point3F( start + step.x * i, origin.y + size.y, origin.z ); else verts[vertCount].point = Point3F( start + step.x * i, origin.y, origin.z + size.y ); - + verts[vertCount].color = color; ++vertCount; } } if( plane == PlaneXY || plane == PlaneYZ ) - { + { U32 num; F32 stp; if( plane == PlaneXY ) @@ -1574,7 +1758,7 @@ void GFXDrawUtil::drawPlaneGrid( const GFXStateBlockDesc &desc, const Point3F &p } F32 start = mFloor( origin.y / stp + 0.5f ) * stp; - + for ( U32 i = 0; i < num; i++ ) { verts[vertCount].point = Point3F( origin.x, start + stp * i, origin.z ); @@ -1585,7 +1769,7 @@ void GFXDrawUtil::drawPlaneGrid( const GFXStateBlockDesc &desc, const Point3F &p verts[vertCount].point = Point3F( origin.x + size.x, start + stp * i, origin.z ); else verts[vertCount].point = Point3F( origin.x, start + stp * i, origin.z + size.x ); - + verts[vertCount].color = color; ++vertCount; } @@ -1604,7 +1788,7 @@ void GFXDrawUtil::drawPlaneGrid( const GFXStateBlockDesc &desc, const Point3F &p verts[vertCount].point = Point3F( origin.x + size.x, origin.y, start + step.y * i ); else verts[vertCount].point = Point3F( origin.x, origin.y + size.x, start + step.y * i ); - + verts[vertCount].color = color; ++vertCount; } @@ -1629,7 +1813,7 @@ void GFXDrawUtil::drawTransform( const GFXStateBlockDesc &desc, const MatrixF &m GFXVertexBufferHandle verts( mDevice, 6, GFXBufferTypeVolatile ); verts.lock(); - const static ColorI defColors[3] = + const static ColorI defColors[3] = { ColorI::RED, ColorI::GREEN, @@ -1655,7 +1839,7 @@ void GFXDrawUtil::drawTransform( const GFXStateBlockDesc &desc, const MatrixF &m { verts[1].point *= *scale; verts[3].point *= *scale; - verts[5].point *= *scale; + verts[5].point *= *scale; } verts.unlock(); diff --git a/Engine/source/gfx/gfxDrawUtil.h b/Engine/source/gfx/gfxDrawUtil.h index 7c74e1d9d..7a641fb64 100644 --- a/Engine/source/gfx/gfxDrawUtil.h +++ b/Engine/source/gfx/gfxDrawUtil.h @@ -31,12 +31,12 @@ #include "math/mPolyhedron.h" #endif - - class FontRenderBatcher; class Frustum; + + /// Helper class containing utility functions for useful drawing routines /// (line, box, rect, billboard, text). class GFXDrawUtil @@ -46,22 +46,36 @@ public: ~GFXDrawUtil(); //----------------------------------------------------------------------------- - // Draw Rectangles + // Draw Rectangles : OUTLINE //----------------------------------------------------------------------------- - void drawRect( const Point2F &upperLeft, const Point2F &lowerRight, const ColorI &color ); - void drawRect( const RectF &rect, const ColorI &color ); - void drawRect( const Point2I &upperLeft, const Point2I &lowerRight, const ColorI &color ); - void drawRect( const RectI &rect, const ColorI &color ); - - void drawRectFill( const Point2F &upperL, const Point2F &lowerR, const ColorI &color ); - void drawRectFill( const RectF &rect, const ColorI &color ); - void drawRectFill( const Point2I &upperLeft, const Point2I &lowerRight, const ColorI &color ); - void drawRectFill( const RectI &rect, const ColorI &color ); - - void draw2DSquare( const Point2F &screenPoint, F32 width, F32 spinAngle = 0.0f ); + void drawRect(const Point2F& upperLeft, const Point2F& lowerRight, const ColorI& color); + void drawRect(const RectF& rect, const ColorI& color); + void drawRect(const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color); + void drawRect(const RectI& rect, const ColorI& color); //----------------------------------------------------------------------------- - // Draw Lines + // Draw Rectangles : FILL + //----------------------------------------------------------------------------- + + void drawRectFill(const Point2F& upperL, const Point2F& lowerR, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); + void drawRectFill(const RectF& rect, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); + void drawRectFill(const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); + void drawRectFill(const RectI& rect, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); + void drawRoundedRect(const F32& cornerRadius, const RectI& rect, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); + void drawRoundedRect(const F32& cornerRadius, const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); + void drawRoundedRect(const F32& cornerRadius, const Point2F& upperLeft, const Point2F& lowerRight, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); + + void draw2DSquare(const Point2F& screenPoint, F32 width, F32 spinAngle = 0.0f); + + //----------------------------------------------------------------------------- + // Draw Circle : FILL + //----------------------------------------------------------------------------- + void drawCircleFill(const RectI& rect, const ColorI& color, F32 radius, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); + void drawCircleFill(const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, F32 radius, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); + void drawCircleFill(const Point2F& upperLeft, const Point2F& lowerRight, const ColorI& color, F32 radius, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); + + //----------------------------------------------------------------------------- + // Draw Lines : Single Pixel //----------------------------------------------------------------------------- void drawLine( const Point3F &startPt, const Point3F &endPt, const ColorI &color ); void drawLine( const Point2F &startPt, const Point2F &endPt, const ColorI &color ); @@ -69,6 +83,13 @@ public: void drawLine( F32 x1, F32 y1, F32 x2, F32 y2, const ColorI &color ); void drawLine( F32 x1, F32 y1, F32 z1, F32 x2, F32 y2, F32 z2, const ColorI &color ); + //----------------------------------------------------------------------------- + // Draw Lines : Thick + //----------------------------------------------------------------------------- + void drawThickLine(const Point2I& startPt, const Point2I& endPt, const ColorI& color, const F32& thickness); + void drawThickLine(const Point2F& startPt, const Point2F& endPt, const ColorI& color, const F32& thickness); + void drawThickLine(F32 x1, F32 y1, F32 z1, F32 x2, F32 y2, F32 z2, const ColorI& color, const F32& thickness); + //----------------------------------------------------------------------------- // Draw Text //----------------------------------------------------------------------------- @@ -92,7 +113,7 @@ public: //----------------------------------------------------------------------------- // Draw Bitmaps - //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- void drawBitmap( GFXTextureObject*texture, const Point2F &in_rAt, const GFXBitmapFlip in_flip = GFXBitmapFlip_None, const GFXTextureFilterType filter = GFXTextureFilterPoint , bool in_wrap = true, F32 angle = 0.0f); void drawBitmapSR( GFXTextureObject*texture, const Point2F &in_rAt, const RectF &srcRect, const GFXBitmapFlip in_flip = GFXBitmapFlip_None, const GFXTextureFilterType filter = GFXTextureFilterPoint , bool in_wrap = true, F32 angle = 0.0f); void drawBitmapStretch( GFXTextureObject*texture, const RectF &dstRect, const GFXBitmapFlip in_flip = GFXBitmapFlip_None, const GFXTextureFilterType filter = GFXTextureFilterPoint , bool in_wrap = true, F32 angle = 0.0f); @@ -108,15 +129,15 @@ public: //----------------------------------------------------------------------------- void drawTriangle( const GFXStateBlockDesc &desc, const Point3F &p0, const Point3F &p1, const Point3F &p2, const ColorI &color, const MatrixF *xfm = NULL ); void drawPolygon( const GFXStateBlockDesc& desc, const Point3F* points, U32 numPoints, const ColorI& color, const MatrixF* xfm = NULL ); - void drawCube( const GFXStateBlockDesc &desc, const Point3F &size, const Point3F &pos, const ColorI &color, const MatrixF *xfm = NULL ); - void drawCube( const GFXStateBlockDesc &desc, const Box3F &box, const ColorI &color, const MatrixF *xfm = NULL ); - void drawObjectBox( const GFXStateBlockDesc &desc, const Point3F &size, const Point3F &pos, const MatrixF &objMat, const ColorI &color ); - void drawSphere( const GFXStateBlockDesc &desc, F32 radius, const Point3F &pos, const ColorI &color, bool drawTop = true, bool drawBottom = true, const MatrixF *xfm = NULL ); + void drawCube( const GFXStateBlockDesc &desc, const Point3F &size, const Point3F &pos, const ColorI &color, const MatrixF *xfm = NULL ); + void drawCube( const GFXStateBlockDesc &desc, const Box3F &box, const ColorI &color, const MatrixF *xfm = NULL ); + void drawObjectBox( const GFXStateBlockDesc &desc, const Point3F &size, const Point3F &pos, const MatrixF &objMat, const ColorI &color ); + void drawSphere( const GFXStateBlockDesc &desc, F32 radius, const Point3F &pos, const ColorI &color, bool drawTop = true, bool drawBottom = true, const MatrixF *xfm = NULL ); void drawCapsule( const GFXStateBlockDesc &desc, const Point3F ¢er, F32 radius, F32 height, const ColorI &color, const MatrixF *xfm = NULL ); - void drawCone( const GFXStateBlockDesc &desc, const Point3F &basePnt, const Point3F &tipPnt, F32 baseRadius, const ColorI &color ); - void drawCylinder( const GFXStateBlockDesc &desc, const Point3F &basePnt, const Point3F &tipPnt, F32 baseRadius, const ColorI &color ); + void drawCone( const GFXStateBlockDesc &desc, const Point3F &basePnt, const Point3F &tipPnt, F32 baseRadius, const ColorI &color ); + void drawCylinder( const GFXStateBlockDesc &desc, const Point3F &basePnt, const Point3F &tipPnt, F32 baseRadius, const ColorI &color ); void drawArrow( const GFXStateBlockDesc &desc, const Point3F &start, const Point3F &end, const ColorI &color, F32 baseRad = 0.0f); - void drawFrustum( const Frustum& f, const ColorI &color ); + void drawFrustum( const Frustum& f, const ColorI &color ); /// Draw a solid or wireframe (depending on fill mode of @a desc) polyhedron with the given color. /// @@ -128,7 +149,7 @@ public: /// Draws a solid XY plane centered on the point with the specified dimensions. void drawSolidPlane( const GFXStateBlockDesc &desc, const Point3F &pos, const Point2F &size, const ColorI &color ); - + enum Plane { PlaneXY, @@ -142,7 +163,7 @@ public: /// Draws axis lines representing the passed matrix. /// If scale is NULL axes will be drawn the length they exist within the MatrixF. /// If colors is NULL the default colors are RED, GREEEN, BLUE ( x, y, z ). - void drawTransform( const GFXStateBlockDesc &desc, const MatrixF &mat, const Point3F *scale = NULL, const ColorI colors[3] = NULL ); + void drawTransform( const GFXStateBlockDesc &desc, const MatrixF &mat, const Point3F *scale = NULL, const ColorI colors[3] = NULL ); protected: @@ -174,8 +195,21 @@ protected: GFXStateBlockRef mBitmapStretchWrapSB; GFXStateBlockRef mBitmapStretchWrapLinearSB; GFXStateBlockRef mRectFillSB; - + FontRenderBatcher* mFontRenderBatcher; + + // Expanded shaders + // rounded rectangle. + GFXShaderRef mRoundRectangleShader; + GFXShaderConstBufferRef mRoundRectangleShaderConsts; + + // thick line. + GFXShaderRef mCircleShader; + GFXShaderConstBufferRef mCircleShaderConsts; + + // thick line. + GFXShaderRef mThickLineShader; + GFXShaderConstBufferRef mThickLineShaderConsts; }; #endif // _GFX_GFXDRAWER_H_ diff --git a/Engine/source/gfx/gfxEnums.h b/Engine/source/gfx/gfxEnums.h index 7a0572d40..cc670f6a6 100644 --- a/Engine/source/gfx/gfxEnums.h +++ b/Engine/source/gfx/gfxEnums.h @@ -64,7 +64,7 @@ enum GFXTexCallbackCode GFXResurrect, }; -enum GFXPrimitiveType +enum GFXPrimitiveType { GFXPT_FIRST = 0, GFXPointList = 0, @@ -75,7 +75,7 @@ enum GFXPrimitiveType GFXPT_COUNT }; -enum GFXBitmapFlip +enum GFXBitmapFlip { GFXBitmapFlip_None = 0, GFXBitmapFlip_X = 1 << 0, @@ -83,7 +83,7 @@ enum GFXBitmapFlip GFXBitmapFlip_XY = GFXBitmapFlip_X | GFXBitmapFlip_Y }; -enum GFXTextureAddressMode +enum GFXTextureAddressMode { GFXAddress_FIRST = 0, GFXAddressWrap = 0, @@ -94,7 +94,7 @@ enum GFXTextureAddressMode GFXAddress_COUNT }; -enum GFXTextureFilterType +enum GFXTextureFilterType { GFXTextureFilter_FIRST = 0, GFXTextureFilterNone = 0, @@ -104,7 +104,7 @@ enum GFXTextureFilterType GFXTextureFilter_COUNT }; -enum GFXFillMode +enum GFXFillMode { GFXFill_FIRST = 1, GFXFillPoint = 1, @@ -113,7 +113,7 @@ enum GFXFillMode GFXFill_COUNT }; -enum GFXFormat +enum GFXFormat { // when adding formats make sure to place // them in the correct group! @@ -152,7 +152,7 @@ enum GFXFormat GFXFormatR11G11B10, GFXFormatD32, GFXFormatD24X8, - GFXFormatD24S8, + GFXFormatD24S8, GFXFormatD24FS8, // Guaranteed RGBA8 (for apis which really dont like bgr) @@ -172,7 +172,7 @@ enum GFXFormat GFXFormatBC3, //dxt4/5 GFXFormatBC4, //3dc+ / ati1 GFXFormatBC5, //3dc / ati2 - // compressed sRGB formats + // compressed sRGB formats GFXFormatBC1_SRGB, GFXFormatBC2_SRGB, GFXFormatBC3_SRGB, @@ -191,7 +191,7 @@ enum GFXFormat /// Returns the byte size of the pixel for non-compressed formats. inline U32 GFXFormat_getByteSize( GFXFormat format ) { - AssertFatal( format < GFXFormat_UNKNOWNSIZE, + AssertFatal( format < GFXFormat_UNKNOWNSIZE, "GFXDevice::formatByteSize - Cannot size a compressed format!" ); if ( format < GFXFormat_16BIT ) @@ -205,12 +205,12 @@ inline U32 GFXFormat_getByteSize( GFXFormat format ) else if ( format < GFXFormat_128BIT ) return 8;// 64 bit... - // This should be 128bits... else its a DDS and + // This should be 128bits... else its a DDS and // the assert should have gone off above. return 16; } -enum GFXClearFlags +enum GFXClearFlags { GFXClearTarget = 1 << 0, GFXClearZBuffer = 1 << 1, @@ -218,7 +218,7 @@ enum GFXClearFlags }; /// The supported blend modes. -enum GFXBlend +enum GFXBlend { GFXBlend_FIRST = 0, GFXBlendZero = 0, /// (0, 0, 0, 0) @@ -238,7 +238,7 @@ enum GFXBlend /// Constants that name each GFXDevice type. Any new GFXDevice subclass must be /// added to this enum. A string representing its name must also be added to /// GFXInit::getAdapterNameFromType(). -enum GFXAdapterType +enum GFXAdapterType { OpenGL = 0, Direct3D11, @@ -255,7 +255,7 @@ enum GFXCullMode GFXCull_COUNT }; -enum GFXCmpFunc +enum GFXCmpFunc { GFXCmp_FIRST = 0, GFXCmpNever = 0, @@ -269,7 +269,7 @@ enum GFXCmpFunc GFXCmp_COUNT }; -enum GFXStencilOp +enum GFXStencilOp { GFXStencilOp_FIRST = 0, GFXStencilOpKeep = 0, @@ -283,8 +283,8 @@ enum GFXStencilOp GFXStencilOp_COUNT }; -enum GFXBlendOp -{ +enum GFXBlendOp +{ GFXBlendOp_FIRST = 0, GFXBlendOpAdd = 0, GFXBlendOpSubtract, @@ -294,7 +294,7 @@ enum GFXBlendOp GFXBlendOp_COUNT }; -enum GFXMatrixType +enum GFXMatrixType { GFXMatrixWorld = 256, GFXMatrixView = 2, @@ -312,25 +312,39 @@ enum GFXMatrixType enum GFXShaderConstType { + GFXSCT_Uknown, /// GFX"S"hader"C"onstant"T"ype + GFXSCT_ConstBuffer, // Scalar - GFXSCT_Float, + GFXSCT_Float, // Vectors - GFXSCT_Float2, - GFXSCT_Float3, - GFXSCT_Float4, + GFXSCT_Float2, + GFXSCT_Float3, + GFXSCT_Float4, // Matrices - GFXSCT_Float2x2, + GFXSCT_Float2x2, GFXSCT_Float3x3, GFXSCT_Float3x4, GFXSCT_Float4x3, - GFXSCT_Float4x4, + GFXSCT_Float4x4, // Scalar - GFXSCT_Int, + GFXSCT_Int, // Vectors - GFXSCT_Int2, - GFXSCT_Int3, - GFXSCT_Int4, + GFXSCT_Int2, + GFXSCT_Int3, + GFXSCT_Int4, + // Scalar + GFXSCT_UInt, + // Vectors + GFXSCT_UInt2, + GFXSCT_UInt3, + GFXSCT_UInt4, + // Scalar + GFXSCT_Bool, + // Vectors + GFXSCT_Bool2, + GFXSCT_Bool3, + GFXSCT_Bool4, // Samplers GFXSCT_Sampler, GFXSCT_SamplerCube, @@ -352,7 +366,7 @@ enum GFXDeclType /// @see Point2F GFXDeclType_Float2, - /// A three-component F32. + /// A three-component F32. /// @see Point3F GFXDeclType_Float3, diff --git a/Engine/source/gfx/gfxShader.cpp b/Engine/source/gfx/gfxShader.cpp index 1fc35a995..62f6aff96 100644 --- a/Engine/source/gfx/gfxShader.cpp +++ b/Engine/source/gfx/gfxShader.cpp @@ -49,9 +49,9 @@ GFXShader::~GFXShader() } #ifndef TORQUE_OPENGL -bool GFXShader::init( const Torque::Path &vertFile, - const Torque::Path &pixFile, - F32 pixVersion, +bool GFXShader::init( const Torque::Path &vertFile, + const Torque::Path &pixFile, + F32 pixVersion, const Vector ¯os ) { Vector samplerNames; @@ -59,13 +59,18 @@ bool GFXShader::init( const Torque::Path &vertFile, } #endif -bool GFXShader::init( const Torque::Path &vertFile, - const Torque::Path &pixFile, - F32 pixVersion, +bool GFXShader::init( F32 pixVersion, const Vector ¯os, const Vector &samplerNames, GFXVertexFormat *instanceFormat) { + // early out. + if (mVertexFile.isEmpty() && mPixelFile.isEmpty() && mGeometryFile.isEmpty()) + { + Con::errorf("Shader files empty, please call setShaderStageFile from shaderData"); + return false; + } + // Take care of instancing if (instanceFormat) { @@ -74,8 +79,6 @@ bool GFXShader::init( const Torque::Path &vertFile, } // Store the inputs for use in reloading. - mVertexFile = vertFile; - mPixelFile = pixFile; mPixVersion = pixVersion; mMacros = macros; mSamplerNamesOrdered = samplerNames; @@ -91,8 +94,12 @@ bool GFXShader::init( const Torque::Path &vertFile, _updateDesc(); // Add file change notifications for reloads. - Torque::FS::AddChangeNotification( mVertexFile, this, &GFXShader::_onFileChanged ); - Torque::FS::AddChangeNotification( mPixelFile, this, &GFXShader::_onFileChanged ); + if(!mVertexFile.isEmpty()) + Torque::FS::AddChangeNotification( mVertexFile, this, &GFXShader::_onFileChanged ); + if(!mPixelFile.isEmpty()) + Torque::FS::AddChangeNotification( mPixelFile, this, &GFXShader::_onFileChanged ); + if(!mGeometryFile.isEmpty()) + Torque::FS::AddChangeNotification( mGeometryFile, this, &GFXShader::_onFileChanged); return true; } @@ -119,11 +126,11 @@ bool GFXShader::reload() void GFXShader::_updateDesc() { - mDescription = String::ToString( "Files: %s, %s Pix Version: %0.2f\nMacros: ", + mDescription = String::ToString( "Files: %s, %s Pix Version: %0.2f\nMacros: ", mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), mPixVersion ); GFXShaderMacro::stringize( smGlobalMacros, &mDescription ); - GFXShaderMacro::stringize( mMacros, &mDescription ); + GFXShaderMacro::stringize( mMacros, &mDescription ); } void GFXShader::addGlobalMacro( const String &name, const String &value ) @@ -161,8 +168,26 @@ bool GFXShader::removeGlobalMacro( const String &name ) return false; } +void GFXShader::setShaderStageFile(const GFXShaderStage stage, const Torque::Path& filePath) +{ + switch (stage) + { + case GFXShaderStage::VERTEX_SHADER: + mVertexFile = filePath; + break; + case GFXShaderStage::PIXEL_SHADER: + mPixelFile = filePath; + break; + case GFXShaderStage::GEOMETRY_SHADER: + mGeometryFile = filePath; + break; + default: + break; + } +} + void GFXShader::_unlinkBuffer( GFXShaderConstBuffer *buf ) -{ +{ Vector::iterator iter = mActiveBuffers.begin(); for ( ; iter != mActiveBuffers.end(); iter++ ) { @@ -177,7 +202,7 @@ void GFXShader::_unlinkBuffer( GFXShaderConstBuffer *buf ) } -DefineEngineFunction( addGlobalShaderMacro, void, +DefineEngineFunction( addGlobalShaderMacro, void, ( const char *name, const char *value ), ( nullAsType() ), "Adds a global shader macro which will be merged with the script defined " "macros on every shader. The macro will replace the value of an existing " @@ -189,7 +214,7 @@ DefineEngineFunction( addGlobalShaderMacro, void, GFXShader::addGlobalMacro( name, value ); } -DefineEngineFunction( removeGlobalShaderMacro, void, ( const char *name ),, +DefineEngineFunction( removeGlobalShaderMacro, void, ( const char *name ),, "Removes an existing global macro by name.\n" "@see addGlobalShaderMacro\n" "@ingroup Rendering\n" ) diff --git a/Engine/source/gfx/gfxShader.h b/Engine/source/gfx/gfxShader.h index 473412728..4edcdce7d 100644 --- a/Engine/source/gfx/gfxShader.h +++ b/Engine/source/gfx/gfxShader.h @@ -65,19 +65,34 @@ class GFXShader; class GFXVertexFormat; +enum GFXShaderStage +{ + VERTEX_SHADER = BIT(0), + PIXEL_SHADER = BIT(1), + GEOMETRY_SHADER = BIT(2), + DOMAIN_SHADER = BIT(3), + HULL_SHADER = BIT(4), + COMPUTE_SHADER = BIT(5) +}; + /// Instances of this struct are returned GFXShaderConstBuffer -struct GFXShaderConstDesc +struct GFXShaderConstDesc { public: - String name; - GFXShaderConstType constType; - U32 arraySize; // > 1 means it is an array! + String name = String::EmptyString; + GFXShaderConstType constType = GFXSCT_Uknown; + U32 arraySize = 0; // > 1 means it is an array! + S32 bindPoint = -1; // bind point used for ubo/cb + S32 samplerReg = -1; // sampler register. + U32 offset = 0; // offset for vars + U32 size = 0; // size of buffer/type + GFXShaderStage shaderStage = VERTEX_SHADER; // only used dx side.not wasting a bit for an unknown? }; /// This is an opaque handle used by GFXShaderConstBuffer clients to set individual shader constants. /// Derived classes can put whatever info they need into here, these handles are owned by the shader constant buffer /// (or shader). Client code should not free these. -class GFXShaderConstHandle +class GFXShaderConstHandle { public: @@ -86,8 +101,8 @@ public: /// Returns true if this constant is valid and can /// be set on the shader. - bool isValid() const { return mValid; } - + bool isValid() const { return mValid; } + /// Returns the name of the constant handle. virtual const String& getName() const = 0; @@ -95,7 +110,7 @@ public: virtual GFXShaderConstType getType() const = 0; virtual U32 getArraySize() const = 0; - + /// Returns -1 if this handle does not point to a Sampler. virtual S32 getSamplerRegister() const = 0; @@ -104,7 +119,7 @@ protected: /// The state of the constant which is /// set from the derived class. bool mValid; - + }; @@ -128,7 +143,7 @@ protected: /// @see wasLost bool mWasLost; - GFXShaderConstBuffer() + GFXShaderConstBuffer() : mWasLost( true ), mInstPtr( NULL ) { @@ -140,16 +155,16 @@ public: virtual GFXShader* getShader() = 0; /// The content of the buffer is in the lost state when - /// first created or when the shader is reloaded. When + /// first created or when the shader is reloaded. When /// the content is lost you must refill the buffer /// with all the constants used by your shader. /// - /// Use this property to avoid setting constants which do + /// Use this property to avoid setting constants which do /// not changefrom one frame to the next. /// bool wasLost() const { return mWasLost; } - /// An inline helper which ensures the handle is valid + /// An inline helper which ensures the handle is valid /// before the virtual set method is called. /// /// You should prefer using this method unless your sure the @@ -168,7 +183,7 @@ public: /// /// Perfer using setSafe unless you can check the handle /// validity yourself and skip a significat amount of work. - /// + /// /// @see GFXShaderConstHandle::isValid() /// virtual void set(GFXShaderConstHandle* handle, const F32 f) = 0; @@ -189,19 +204,19 @@ public: virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv) = 0; virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv) = 0; virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv) = 0; - - /// Set a variable sized matrix shader constant. - virtual void set( GFXShaderConstHandle* handle, - const MatrixF& mat, + + /// Set a variable sized matrix shader constant. + virtual void set( GFXShaderConstHandle* handle, + const MatrixF& mat, const GFXShaderConstType matrixType = GFXSCT_Float4x4 ) = 0; - + /// Set a variable sized matrix shader constant from - /// an array of matricies. - virtual void set( GFXShaderConstHandle* handle, - const MatrixF* mat, - const U32 arraySize, + /// an array of matricies. + virtual void set( GFXShaderConstHandle* handle, + const MatrixF* mat, + const U32 arraySize, const GFXShaderConstType matrixType = GFXSCT_Float4x4 ) = 0; - + // TODO: Make this protected and put a real API around it. U8 *mInstPtr; }; @@ -217,8 +232,8 @@ class GFXShader : public StrongRefBase, public GFXResource friend class GFXShaderConstBuffer; protected: - - /// These are system wide shader macros which are + + /// These are system wide shader macros which are /// merged with shader specific macros at creation. static Vector smGlobalMacros; @@ -229,19 +244,22 @@ protected: static bool smLogWarnings; /// The vertex shader file. - Torque::Path mVertexFile; + Torque::Path mVertexFile; /// The pixel shader file. - Torque::Path mPixelFile; + Torque::Path mPixelFile; - /// The macros to be passed to the shader. + // the geometry shader file. + Torque::Path mGeometryFile; + + /// The macros to be passed to the shader. Vector mMacros; /// Ordered SamplerNames /// We need to store a list of sampler for allow OpenGL to /// assign correct location for each sampler. /// GLSL 150 not allow explicit uniform location. - /// Only used on OpenGL + /// Only used on OpenGL Vector mSamplerNamesOrdered; /// The pixel version this is compiled for. @@ -256,7 +274,7 @@ protected: Signal mReloadSignal; /// Vector of buffers that reference this shader. - /// It is the responsibility of the derived shader class to populate this + /// It is the responsibility of the derived shader class to populate this /// vector and to notify them when this shader is reloaded. Classes /// derived from GFXShaderConstBuffer should call _unlinkBuffer from /// their destructor. @@ -267,7 +285,7 @@ protected: /// A protected constructor so it cannot be instantiated. GFXShader(); -public: +public: /// Adds a global shader macro which will be merged with /// the script defined macros on every shader reload. @@ -288,9 +306,9 @@ public: /// Toggle logging for shader errors. static void setLogging( bool logErrors, - bool logWarning ) + bool logWarning ) { - smLogErrors = logErrors; + smLogErrors = logErrors; smLogWarnings = logWarning; } @@ -300,16 +318,14 @@ public: /// /// Deprecated. Remove on T3D 4.0 #ifndef TORQUE_OPENGL - bool init( const Torque::Path &vertFile, - const Torque::Path &pixFile, - F32 pixVersion, + bool init( const Torque::Path &vertFile, + const Torque::Path &pixFile, + F32 pixVersion, const Vector ¯os ); #endif /// - bool init( const Torque::Path &vertFile, - const Torque::Path &pixFile, - F32 pixVersion, + bool init( F32 pixVersion, const Vector ¯os, const Vector &samplerNames, GFXVertexFormat *instanceFormat = NULL ); @@ -320,23 +336,23 @@ public: Signal getReloadSignal() { return mReloadSignal; } /// Allocate a constant buffer - virtual GFXShaderConstBufferRef allocConstBuffer() = 0; + virtual GFXShaderConstBufferRef allocConstBuffer() = 0; /// Returns our list of shader constants, the material can get this and just set the constants it knows about virtual const Vector& getShaderConstDesc() const = 0; /// Returns a shader constant handle for the name constant. /// - /// Since shaders can reload and later have handles that didn't + /// Since shaders can reload and later have handles that didn't /// exist originally this will return a handle in an invalid state /// if the constant doesn't exist at this time. - virtual GFXShaderConstHandle* getShaderConstHandle( const String& name ) = 0; + virtual GFXShaderConstHandle* getShaderConstHandle( const String& name ) = 0; /// Returns a shader constant handle for the name constant, if the variable doesn't exist NULL is returned. virtual GFXShaderConstHandle* findShaderConstHandle( const String& name ) = 0; /// Returns the alignment value for constType - virtual U32 getAlignmentValue(const GFXShaderConstType constType) const = 0; + virtual U32 getAlignmentValue(const GFXShaderConstType constType) const = 0; /// Returns the required vertex format for this shader. /// Returns the pixel shader version. @@ -349,6 +365,8 @@ public: /// the shader disassembly. virtual bool getDisassembly( String &outStr ) const { return false; } + void setShaderStageFile(const GFXShaderStage stage, const Torque::Path& filePath); + /// Returns the vertex shader file path. const String& getVertexShaderFile() const { return mVertexFile.getFullPath(); } diff --git a/Engine/source/gfx/gl/gfxGLDevice.cpp b/Engine/source/gfx/gl/gfxGLDevice.cpp index 07dfcb10d..148a68648 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.cpp +++ b/Engine/source/gfx/gl/gfxGLDevice.cpp @@ -57,7 +57,7 @@ #include "gfx/gl/tGL/tXGL.h" #endif -GFXAdapter::CreateDeviceInstanceDelegate GFXGLDevice::mCreateDeviceInstance(GFXGLDevice::createInstance); +GFXAdapter::CreateDeviceInstanceDelegate GFXGLDevice::mCreateDeviceInstance(GFXGLDevice::createInstance); GFXDevice *GFXGLDevice::createInstance( U32 adapterIndex ) { @@ -76,7 +76,7 @@ void loadGLCore() if(coreLoaded) return; coreLoaded = true; - + // Make sure we've got our GL bindings. GL::gglPerformBinds(); } @@ -87,11 +87,11 @@ void loadGLExtensions(void *context) if(extensionsLoaded) return; extensionsLoaded = true; - + GL::gglPerformExtensionBinds(context); } -void STDCALL glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, +void STDCALL glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) { // JTH [11/24/2016]: This is a temporary fix so that we do not get spammed for redundant fbo changes. @@ -118,24 +118,24 @@ void STDCALL glAmdDebugCallback(GLuint id, GLenum category, GLenum severity, GLs } void GFXGLDevice::initGLState() -{ +{ // We don't currently need to sync device state with a known good place because we are // going to set everything in GFXGLStateBlock, but if we change our GFXGLStateBlock strategy, this may // need to happen. - + // Deal with the card profiler here when we know we have a valid context. mCardProfiler = new GFXGLCardProfiler(); - mCardProfiler->init(); + mCardProfiler->init(); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, (GLint*)&mMaxShaderTextures); // JTH: Needs removed, ffp //glGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint*)&mMaxFFTextures); glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, (GLint*)&mMaxTRColors); mMaxTRColors = getMin( mMaxTRColors, (U32)(GFXTextureTarget::MaxRenderSlotId-1) ); - + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - + // [JTH 5/6/2016] GLSL 1.50 is really SM 4.0 - // Setting mPixelShaderVersion to 3.0 will allow Advanced Lighting to run. + // Setting mPixelShaderVersion to 3.0 will allow Advanced Lighting to run. mPixelShaderVersion = 3.0; // Set capability extensions. @@ -150,7 +150,7 @@ void GFXGLDevice::initGLState() String vendorStr = (const char*)glGetString( GL_VENDOR ); if( vendorStr.find("NVIDIA", 0, String::NoCase | String::Left) != String::NPos) mUseGlMap = false; - + // Workaround for all Mac's, has a problem using glMap* with volatile buffers #ifdef TORQUE_OS_MAC mUseGlMap = false; @@ -173,7 +173,7 @@ void GFXGLDevice::initGLState() else if(gglHasExtension(AMD_debug_output)) { glEnable(GL_DEBUG_OUTPUT); - glDebugMessageCallbackAMD(glAmdDebugCallback, NULL); + glDebugMessageCallbackAMD(glAmdDebugCallback, NULL); //glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); GLuint unusedIds = 0; glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0,&unusedIds, GL_TRUE); @@ -258,16 +258,17 @@ GFXGLDevice::GFXGLDevice(U32 adapterIndex) : mModelViewProjSC[i] = NULL; mOpenglStateCache = new GFXGLStateCache; + mCurrentConstBuffer = NULL; } GFXGLDevice::~GFXGLDevice() { mCurrentStateBlock = NULL; - for(int i = 0; i < VERTEX_STREAM_COUNT; ++i) + for(int i = 0; i < VERTEX_STREAM_COUNT; ++i) mCurrentVB[i] = NULL; mCurrentPB = NULL; - + for(U32 i = 0; i < mVolatileVBs.size(); i++) mVolatileVBs[i] = NULL; for(U32 i = 0; i < mVolatilePBs.size(); i++) @@ -291,13 +292,18 @@ GFXGLDevice::~GFXGLDevice() mTextureManager->kill(); } + // Free device buffers + DeviceBufferMap::Iterator bufferIter = mDeviceBufferMap.begin(); + for (; bufferIter != mDeviceBufferMap.end(); ++bufferIter) + glDeleteBuffers(1, &bufferIter->value); + GFXResource* walk = mResourceListHead; while(walk) { walk->zombify(); walk = walk->getNextResource(); } - + if( mCardProfiler ) SAFE_DELETE( mCardProfiler ); @@ -306,16 +312,33 @@ GFXGLDevice::~GFXGLDevice() SAFE_DELETE( mOpenglStateCache ); } +GLuint GFXGLDevice::getDeviceBuffer(const GFXShaderConstDesc desc) +{ + String name(desc.name + "_" + String::ToString(desc.size)); + DeviceBufferMap::Iterator buf = mDeviceBufferMap.find(name); + if (buf != mDeviceBufferMap.end()) + { + return mDeviceBufferMap[name]; + } + + GLuint uboHandle; + glGenBuffers(1, &uboHandle); + + mDeviceBufferMap[name] = uboHandle; + + return uboHandle; +} + void GFXGLDevice::zombify() { mTextureManager->zombify(); - for(int i = 0; i < VERTEX_STREAM_COUNT; ++i) + for(int i = 0; i < VERTEX_STREAM_COUNT; ++i) if(mCurrentVB[i]) mCurrentVB[i]->finish(); if(mCurrentPB) mCurrentPB->finish(); - + //mVolatileVBs.clear(); //mVolatilePBs.clear(); GFXResource* walk = mResourceListHead; @@ -334,12 +357,12 @@ void GFXGLDevice::resurrect() walk->resurrect(); walk = walk->getNextResource(); } - for(int i = 0; i < VERTEX_STREAM_COUNT; ++i) + for(int i = 0; i < VERTEX_STREAM_COUNT; ++i) if(mCurrentVB[i]) mCurrentVB[i]->prepare(); if(mCurrentPB) mCurrentPB->prepare(); - + mTextureManager->resurrect(); } @@ -366,7 +389,7 @@ GFXPrimitiveBuffer* GFXGLDevice::findVolatilePBO(U32 numIndices, U32 numPrimitiv for(U32 i = 0; i < mVolatilePBs.size(); i++) if((mVolatilePBs[i]->mIndexCount >= numIndices) && (mVolatilePBs[i]->getRefCount() == 1)) return mVolatilePBs[i]; - + // No existing PB, so create one StrongRefPtr buf(new GFXGLPrimitiveBuffer(GFX, numIndices, numPrimitives, GFXBufferTypeVolatile)); buf->registerResourceWithDevice(this); @@ -374,18 +397,18 @@ GFXPrimitiveBuffer* GFXGLDevice::findVolatilePBO(U32 numIndices, U32 numPrimitiv return buf.getPointer(); } -GFXVertexBuffer *GFXGLDevice::allocVertexBuffer( U32 numVerts, - const GFXVertexFormat *vertexFormat, - U32 vertSize, +GFXVertexBuffer *GFXGLDevice::allocVertexBuffer( U32 numVerts, + const GFXVertexFormat *vertexFormat, + U32 vertSize, GFXBufferType bufferType, - void* data ) + void* data ) { PROFILE_SCOPE(GFXGLDevice_allocVertexBuffer); if(bufferType == GFXBufferTypeVolatile) return findVolatileVBO(numVerts, vertexFormat, vertSize); - + GFXGLVertexBuffer* buf = new GFXGLVertexBuffer( GFX, numVerts, vertexFormat, vertSize, bufferType ); - buf->registerResourceWithDevice(this); + buf->registerResourceWithDevice(this); if(data) { @@ -398,10 +421,10 @@ GFXVertexBuffer *GFXGLDevice::allocVertexBuffer( U32 numVerts, return buf; } -GFXPrimitiveBuffer *GFXGLDevice::allocPrimitiveBuffer( U32 numIndices, U32 numPrimitives, GFXBufferType bufferType, void* data ) +GFXPrimitiveBuffer *GFXGLDevice::allocPrimitiveBuffer( U32 numIndices, U32 numPrimitives, GFXBufferType bufferType, void* data ) { GFXPrimitiveBuffer* buf; - + if(bufferType == GFXBufferTypeVolatile) { buf = findVolatilePBO(numIndices, numPrimitives); @@ -411,7 +434,7 @@ GFXPrimitiveBuffer *GFXGLDevice::allocPrimitiveBuffer( U32 numIndices, U32 numPr buf = new GFXGLPrimitiveBuffer(GFX, numIndices, numPrimitives, bufferType); buf->registerResourceWithDevice(this); } - + if(data) { void* dest; @@ -430,7 +453,7 @@ void GFXGLDevice::setVertexStream( U32 stream, GFXVertexBuffer *buffer ) { // Reset the state the old VB required, then set the state the new VB requires. if( mCurrentVB[stream] ) - { + { mCurrentVB[stream]->finish(); } @@ -460,10 +483,10 @@ void GFXGLDevice::setVertexStreamFrequency( U32 stream, U32 frequency ) } GFXCubemap* GFXGLDevice::createCubemap() -{ +{ GFXGLCubemap* cube = new GFXGLCubemap(); cube->registerResourceWithDevice(this); - return cube; + return cube; }; GFXCubemapArray *GFXGLDevice::createCubemapArray() @@ -480,7 +503,7 @@ GFXTextureArray* GFXGLDevice::createTextureArray() return textureArray; } -void GFXGLDevice::endSceneInternal() +void GFXGLDevice::endSceneInternal() { // nothing to do for opengl mCanCurrentlyRender = false; @@ -556,9 +579,9 @@ void GFXGLDevice::clear(U32 flags, const LinearColorF& color, F32 z, U32 stencil { // Make sure we have flushed our render target state. _updateRenderTargets(); - + bool writeAllColors = true; - bool zwrite = true; + bool zwrite = true; bool writeAllStencil = true; const GFXStateBlockDesc *desc = NULL; if (mCurrentGLStateBlock) @@ -568,7 +591,7 @@ void GFXGLDevice::clear(U32 flags, const LinearColorF& color, F32 z, U32 stencil writeAllColors = desc->colorWriteRed && desc->colorWriteGreen && desc->colorWriteBlue && desc->colorWriteAlpha; writeAllStencil = desc->stencilWriteMask == 0xFFFFFFFF; } - + glColorMask(true, true, true, true); glDepthMask(true); glStencilMask(0xFFFFFFFF); @@ -585,7 +608,7 @@ void GFXGLDevice::clear(U32 flags, const LinearColorF& color, F32 z, U32 stencil if(!writeAllColors) glColorMask(desc->colorWriteRed, desc->colorWriteGreen, desc->colorWriteBlue, desc->colorWriteAlpha); - + if(!zwrite) glDepthMask(false); @@ -623,20 +646,20 @@ inline GLsizei GFXGLDevice::primCountToIndexCount(GFXPrimitiveType primType, U32 AssertFatal(false, "GFXGLDevice::primCountToIndexCount - unrecognized prim type"); break; } - + return 0; } -GFXVertexDecl* GFXGLDevice::allocVertexDecl( const GFXVertexFormat *vertexFormat ) +GFXVertexDecl* GFXGLDevice::allocVertexDecl( const GFXVertexFormat *vertexFormat ) { PROFILE_SCOPE(GFXGLDevice_allocVertexDecl); typedef Map GFXGLVertexDeclMap; - static GFXGLVertexDeclMap declMap; + static GFXGLVertexDeclMap declMap; GFXGLVertexDeclMap::Iterator itr = declMap.find( (void*)vertexFormat->getDescription().c_str() ); // description string are interned, safe to use c_str() if(itr != declMap.end()) return &itr->value; - GFXGLVertexDecl &decl = declMap[(void*)vertexFormat->getDescription().c_str()]; + GFXGLVertexDecl &decl = declMap[(void*)vertexFormat->getDescription().c_str()]; decl.init(vertexFormat); return &decl; } @@ -652,7 +675,7 @@ inline void GFXGLDevice::preDrawPrimitive() { updateStates(); } - + if(mCurrentShaderConstBuffer) setShaderConstBufferInternal(mCurrentShaderConstBuffer); @@ -660,18 +683,18 @@ inline void GFXGLDevice::preDrawPrimitive() { AssertFatal(mCurrVertexDecl, ""); const GFXGLVertexDecl* decl = static_cast(mCurrVertexDecl); - + for(int i = 0; i < getNumVertexStreams(); ++i) { if(mCurrentVB[i]) { - mCurrentVB[i]->prepare(i, mCurrentVB_Divisor[i]); // GL_ARB_vertex_attrib_binding + mCurrentVB[i]->prepare(i, mCurrentVB_Divisor[i]); // GL_ARB_vertex_attrib_binding decl->prepareBuffer_old( i, mCurrentVB[i]->mBuffer, mCurrentVB_Divisor[i] ); // old vertex buffer/format } } - decl->updateActiveVertexAttrib( GFXGL->getOpenglCache()->getCacheVertexAttribActive() ); - } + decl->updateActiveVertexAttrib( GFXGL->getOpenglCache()->getCacheVertexAttribActive() ); + } mNeedUpdateVertexAttrib = false; } @@ -682,26 +705,26 @@ inline void GFXGLDevice::postDrawPrimitive(U32 primitiveCount) mDeviceStatistics.mPolyCount += primitiveCount; } -void GFXGLDevice::drawPrimitive( GFXPrimitiveType primType, U32 vertexStart, U32 primitiveCount ) +void GFXGLDevice::drawPrimitive( GFXPrimitiveType primType, U32 vertexStart, U32 primitiveCount ) { preDrawPrimitive(); - + if(mCurrentVB[0]) vertexStart += mCurrentVB[0]->mBufferVertexOffset; if(mDrawInstancesCount) glDrawArraysInstanced(GFXGLPrimType[primType], vertexStart, primCountToIndexCount(primType, primitiveCount), mDrawInstancesCount); else - glDrawArrays(GFXGLPrimType[primType], vertexStart, primCountToIndexCount(primType, primitiveCount)); + glDrawArrays(GFXGLPrimType[primType], vertexStart, primCountToIndexCount(primType, primitiveCount)); postDrawPrimitive(primitiveCount); } -void GFXGLDevice::drawIndexedPrimitive( GFXPrimitiveType primType, - U32 startVertex, - U32 minIndex, - U32 numVerts, - U32 startIndex, +void GFXGLDevice::drawIndexedPrimitive( GFXPrimitiveType primType, + U32 startVertex, + U32 minIndex, + U32 numVerts, + U32 startIndex, U32 primitiveCount ) { preDrawPrimitive(); @@ -732,7 +755,7 @@ void GFXGLDevice::setTextureInternal(U32 textureUnit, const GFXTextureObject*tex { mActiveTextureType[textureUnit] = tex->getBinding(); tex->bind(textureUnit); - } + } else if(mActiveTextureType[textureUnit] != GL_ZERO) { glActiveTexture(GL_TEXTURE0 + textureUnit); @@ -805,21 +828,21 @@ void GFXGLDevice::setClipRect( const RectI &inRect ) F32 r = F32(mClip.point.x + mClip.extent.x); F32 b = F32(mClip.point.y + mClip.extent.y); F32 t = F32(mClip.point.y); - - // Set up projection matrix, + + // Set up projection matrix, //static Point4F pt; pt.set(2.0f / (r - l), 0.0f, 0.0f, 0.0f); mProjectionMatrix.setColumn(0, pt); - + pt.set(0.0f, 2.0f / (t - b), 0.0f, 0.0f); mProjectionMatrix.setColumn(1, pt); - + pt.set(0.0f, 0.0f, 1.0f, 0.0f); mProjectionMatrix.setColumn(2, pt); - + pt.set((l + r) / (l - r), (t + b) / (b - t), 1.0f, 1.0f); mProjectionMatrix.setColumn(3, pt); - + MatrixF mTempMatrix(true); setViewMatrix( mTempMatrix ); setWorldMatrix( mTempMatrix ); @@ -844,7 +867,7 @@ void GFXGLDevice::setStateBlockInternal(GFXStateBlock* block, bool force) GFXGLStateBlock* glCurrent = static_cast(mCurrentStateBlock.getPointer()); if (force) glCurrent = NULL; - + glBlock->activate(glCurrent); // Doesn't use current yet. mCurrentGLStateBlock = glBlock; } @@ -863,19 +886,19 @@ GFXFence * GFXGLDevice::createFence() GFXFence* fence = _createPlatformSpecificFence(); if(!fence) fence = new GFXGeneralFence( this ); - + fence->registerResourceWithDevice(this); return fence; } GFXOcclusionQuery* GFXGLDevice::createOcclusionQuery() -{ +{ GFXOcclusionQuery *query = new GFXGLOcclusionQuery( this ); query->registerResourceWithDevice(this); return query; } -void GFXGLDevice::setupGenericShaders( GenericShaderType type ) +void GFXGLDevice::setupGenericShaders( GenericShaderType type ) { AssertFatal(type != GSTargetRestore, ""); @@ -927,7 +950,7 @@ void GFXGLDevice::setupGenericShaders( GenericShaderType type ) Sim::getRootGroup()->addObject(shaderData); } - MatrixF tempMatrix = mProjectionMatrix * mViewMatrix * mWorldMatrix[mWorldStackSize]; + MatrixF tempMatrix = mProjectionMatrix * mViewMatrix * mWorldMatrix[mWorldStackSize]; mGenericShaderBuffer[type]->setSafe(mModelViewProjSC[type], tempMatrix); setShader( mGenericShader[type] ); @@ -959,8 +982,19 @@ void GFXGLDevice::setShader(GFXShader *shader, bool force) void GFXGLDevice::setShaderConstBufferInternal(GFXShaderConstBuffer* buffer) { - PROFILE_SCOPE(GFXGLDevice_setShaderConstBufferInternal); - static_cast(buffer)->activate(); + if (buffer) + { + PROFILE_SCOPE(GFXGLDevice_setShaderConstBufferInternal); + AssertFatal(static_cast(buffer), "Incorrect shader const buffer type for this device!"); + GFXGLShaderConstBuffer* oglBuffer = static_cast(buffer); + + oglBuffer->activate(mCurrentConstBuffer); + mCurrentConstBuffer = oglBuffer; + } + else + { + mCurrentConstBuffer = NULL; + } } U32 GFXGLDevice::getNumSamplers() const @@ -968,7 +1002,7 @@ U32 GFXGLDevice::getNumSamplers() const return getMin((U32)GFX_TEXTURE_STAGE_COUNT,mPixelShaderVersion > 0.001f ? mMaxShaderTextures : mMaxFFTextures); } -GFXTextureObject* GFXGLDevice::getDefaultDepthTex() const +GFXTextureObject* GFXGLDevice::getDefaultDepthTex() const { if(mWindowRT && mWindowRT->getPointer()) return static_cast( mWindowRT->getPointer() )->mBackBufferDepthTex.getPointer(); @@ -976,9 +1010,9 @@ GFXTextureObject* GFXGLDevice::getDefaultDepthTex() const return NULL; } -U32 GFXGLDevice::getNumRenderTargets() const -{ - return mMaxTRColors; +U32 GFXGLDevice::getNumRenderTargets() const +{ + return mMaxTRColors; } void GFXGLDevice::_updateRenderTargets() @@ -988,9 +1022,9 @@ void GFXGLDevice::_updateRenderTargets() if ( mRTDeactivate ) { mRTDeactivate->deactivate(); - mRTDeactivate = NULL; + mRTDeactivate = NULL; } - + // NOTE: The render target changes is not really accurate // as the GFXTextureTarget supports MRT internally. So when // we activate a GFXTarget it could result in multiple calls @@ -1006,31 +1040,31 @@ void GFXGLDevice::_updateRenderTargets() else { GFXGLWindowTarget *win = dynamic_cast( mCurrentRT.getPointer() ); - AssertFatal( win != NULL, + AssertFatal( win != NULL, "GFXGLDevice::_updateRenderTargets() - invalid target subclass passed!" ); - + win->makeActive(); - + if( win->mContext != static_cast(GFX)->mContext ) { mRTDirty = false; GFX->updateStates(true); } } - + mRTDirty = false; } - + if ( mViewportDirty ) { - glViewport( mViewport.point.x, mViewport.point.y, mViewport.extent.x, mViewport.extent.y ); + glViewport( mViewport.point.x, mViewport.point.y, mViewport.extent.x, mViewport.extent.y ); mViewportDirty = false; } } -GFXFormat GFXGLDevice::selectSupportedFormat( GFXTextureProfile* profile, - const Vector& formats, - bool texture, +GFXFormat GFXGLDevice::selectSupportedFormat( GFXTextureProfile* profile, + const Vector& formats, + bool texture, bool mustblend, bool mustfilter ) { @@ -1041,10 +1075,10 @@ GFXFormat GFXGLDevice::selectSupportedFormat( GFXTextureProfile* profile, continue; if(GFXGLTextureInternalFormat[formats[i]] == GL_ZERO) continue; - + return formats[i]; } - + return GFXFormatR8G8B8A8; } @@ -1055,7 +1089,7 @@ U32 GFXGLDevice::getTotalVideoMemory_GL_EXT() { GLint mem[4] = {0}; glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, mem); // Retrieve the texture pool - + /* With mem[0] i get only the total memory free in the pool in KB * * mem[0] - total memory free in the pool @@ -1066,7 +1100,7 @@ U32 GFXGLDevice::getTotalVideoMemory_GL_EXT() return mem[0] / 1024; } - + //source http://www.opengl.org/registry/specs/NVX/gpu_memory_info.txt else if( gglHasExtension(NVX_gpu_memory_info) ) { diff --git a/Engine/source/gfx/gl/gfxGLDevice.h b/Engine/source/gfx/gl/gfxGLDevice.h index 3a42db9d6..981aff662 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.h +++ b/Engine/source/gfx/gl/gfxGLDevice.h @@ -43,9 +43,11 @@ class GFXGLCubemap; class GFXGLCubemapArray; class GFXGLStateCache; class GFXGLVertexDecl; +class GFXGLShaderConstBuffer; class GFXGLDevice : public GFXDevice { + public: struct GLCapabilities { @@ -59,6 +61,11 @@ public: }; GLCapabilities mCapabilities; + // UBO map + typedef Map DeviceBufferMap; + // grab device buffer. + GLuint getDeviceBuffer(const GFXShaderConstDesc desc); + void zombify(); void resurrect(); GFXGLDevice(U32 adapterIndex); @@ -105,13 +112,13 @@ public: /// @{ virtual F32 getPixelShaderVersion() const { return mPixelShaderVersion; } virtual void setPixelShaderVersion( F32 version ) { mPixelShaderVersion = version; } - + virtual void setShader(GFXShader *shader, bool force = false); - + /// @attention GL cannot check if the given format supports blending or filtering! virtual GFXFormat selectSupportedFormat(GFXTextureProfile *profile, const Vector &formats, bool texture, bool mustblend, bool mustfilter); - + /// Returns the number of texture samplers that can be used in a shader rendering pass virtual U32 getNumSamplers() const; @@ -128,11 +135,11 @@ public: virtual void drawPrimitive( GFXPrimitiveType primType, U32 vertexStart, U32 primitiveCount ); - virtual void drawIndexedPrimitive( GFXPrimitiveType primType, - U32 startVertex, - U32 minIndex, - U32 numVerts, - U32 startIndex, + virtual void drawIndexedPrimitive( GFXPrimitiveType primType, + U32 startVertex, + U32 minIndex, + U32 numVerts, + U32 startIndex, U32 primitiveCount ); virtual void setClipRect( const RectI &rect ); @@ -142,15 +149,15 @@ public: virtual U32 getMaxDynamicVerts() { return GFX_MAX_DYNAMIC_VERTS; } virtual U32 getMaxDynamicIndices() { return GFX_MAX_DYNAMIC_INDICES; } - + GFXFence *createFence(); - + GFXOcclusionQuery* createOcclusionQuery(); GFXGLStateBlockRef getCurrentStateBlock() { return mCurrentGLStateBlock; } - + virtual void setupGenericShaders( GenericShaderType type = GSColor ); - + /// bool supportsAnisotropic() const { return mCapabilities.anisotropicFiltering; } @@ -158,16 +165,16 @@ public: GFXTextureObject* getDefaultDepthTex() const; - /// Returns the number of vertex streams supported by the device. + /// Returns the number of vertex streams supported by the device. const U32 getNumVertexStreams() const { return mNumVertexStream; } - bool glUseMap() const { return mUseGlMap; } + bool glUseMap() const { return mUseGlMap; } const char* interpretDebugResult(long result) { return "Not Implemented"; }; -protected: +protected: /// Called by GFXDevice to create a device specific stateblock virtual GFXStateBlockRef createStateBlockInternal(const GFXStateBlockDesc& desc); /// Called by GFXDevice to actually set a stateblock. - virtual void setStateBlockInternal(GFXStateBlock* block, bool force); + virtual void setStateBlockInternal(GFXStateBlock* block, bool force); /// Called by base GFXDevice to actually set a const buffer virtual void setShaderConstBufferInternal(GFXShaderConstBuffer* buffer); @@ -184,13 +191,13 @@ protected: /// is created. virtual void initStates() { } - virtual GFXVertexBuffer *allocVertexBuffer( U32 numVerts, + virtual GFXVertexBuffer *allocVertexBuffer( U32 numVerts, const GFXVertexFormat *vertexFormat, - U32 vertSize, + U32 vertSize, GFXBufferType bufferType, void* data = NULL); virtual GFXPrimitiveBuffer *allocPrimitiveBuffer( U32 numIndices, U32 numPrimitives, GFXBufferType bufferType, void* data = NULL ); - + // NOTE: The GL device doesn't need a vertex declaration at // this time, but we need to return something to keep the system // from retrying to allocate one on every call. @@ -199,11 +206,13 @@ protected: virtual void setVertexDecl( const GFXVertexDecl *decl ); virtual void setVertexStream( U32 stream, GFXVertexBuffer *buffer ); - virtual void setVertexStreamFrequency( U32 stream, U32 frequency ); + virtual void setVertexStreamFrequency( U32 stream, U32 frequency ); + StrongRefPtr mCurrentConstBuffer; + DeviceBufferMap mDeviceBufferMap; private: typedef GFXDevice Parent; - + friend class GFXGLTextureObject; friend class GFXGLCubemap; friend class GFXGLCubemapArray; @@ -215,18 +224,18 @@ private: static GFXAdapter::CreateDeviceInstanceDelegate mCreateDeviceInstance; U32 mAdapterIndex; - + StrongRefPtr mCurrentVB[VERTEX_STREAM_COUNT]; U32 mCurrentVB_Divisor[VERTEX_STREAM_COUNT]; bool mNeedUpdateVertexAttrib; StrongRefPtr mCurrentPB; U32 mDrawInstancesCount; - + GFXShader* mCurrentShader; GFXShaderRef mGenericShader[GS_COUNT]; GFXShaderConstBufferRef mGenericShaderBuffer[GS_COUNT]; GFXShaderConstHandle *mModelViewProjSC[GS_COUNT]; - + /// Since GL does not have separate world and view matrices we need to track them MatrixF m_mCurrentWorld; MatrixF m_mCurrentView; @@ -237,34 +246,34 @@ private: F32 mPixelShaderVersion; U32 mNumVertexStream; - + U32 mMaxShaderTextures; U32 mMaxFFTextures; U32 mMaxTRColors; RectI mClip; - + GFXGLStateBlockRef mCurrentGLStateBlock; - + GLenum mActiveTextureType[GFX_TEXTURE_STAGE_COUNT]; - + Vector< StrongRefPtr > mVolatileVBs; ///< Pool of existing volatile VBs so we can reuse previously created ones Vector< StrongRefPtr > mVolatilePBs; ///< Pool of existing volatile PBs so we can reuse previously created ones GLsizei primCountToIndexCount(GFXPrimitiveType primType, U32 primitiveCount); void preDrawPrimitive(); - void postDrawPrimitive(U32 primitiveCount); - + void postDrawPrimitive(U32 primitiveCount); + GFXVertexBuffer* findVolatileVBO(U32 numVerts, const GFXVertexFormat *vertexFormat, U32 vertSize); ///< Returns an existing volatile VB which has >= numVerts and the same vert flags/size, or creates a new VB if necessary GFXPrimitiveBuffer* findVolatilePBO(U32 numIndices, U32 numPrimitives); ///< Returns an existing volatile PB which has >= numIndices, or creates a new PB if necessary void vsyncCallback(); ///< Vsync callback - + void initGLState(); ///< Guaranteed to be called after all extensions have been loaded, use to init card profiler, shader version, max samplers, etc. - + GFXFence* _createPlatformSpecificFence(); ///< If our platform (e.g. OS X) supports a fence extenstion (e.g. GL_APPLE_fence) this will create one, otherwise returns NULL - + void setPB(GFXGLPrimitiveBuffer* pb); ///< Sets mCurrentPB GFXGLStateCache *mOpenglStateCache; diff --git a/Engine/source/gfx/gl/gfxGLShader.cpp b/Engine/source/gfx/gl/gfxGLShader.cpp index c8366ed56..e13ff1a52 100644 --- a/Engine/source/gfx/gl/gfxGLShader.cpp +++ b/Engine/source/gfx/gl/gfxGLShader.cpp @@ -34,51 +34,51 @@ #define CHECK_AARG(pos, name) static StringTableEntry attr_##name = StringTable->insert(#name); if (argName == attr_##name) { glBindAttribLocation(mProgram, pos, attr_##name); continue; } - -class GFXGLShaderConstHandle : public GFXShaderConstHandle -{ - friend class GFXGLShader; - -public: - - GFXGLShaderConstHandle( GFXGLShader *shader ); - GFXGLShaderConstHandle( GFXGLShader *shader, const GFXShaderConstDesc &desc, GLuint loc, S32 samplerNum ); - virtual ~GFXGLShaderConstHandle(); - - void reinit( const GFXShaderConstDesc &desc, GLuint loc, S32 samplerNum ); - - const String& getName() const { return mDesc.name; } - GFXShaderConstType getType() const { return mDesc.constType; } - U32 getArraySize() const { return mDesc.arraySize; } - - U32 getSize() const; - void setValid( bool valid ) { mValid = valid; } - /// @warning This will always return the value assigned when the shader was - /// initialized. If the value is later changed this method won't reflect that. - S32 getSamplerRegister() const { return mSamplerNum; } - - GFXShaderConstDesc mDesc; - GFXGLShader* mShader; - GLuint mLocation; - U32 mOffset; - U32 mSize; - S32 mSamplerNum; - bool mInstancingConstant; -}; - -GFXGLShaderConstHandle::GFXGLShaderConstHandle( GFXGLShader *shader ) - : mShader( shader ), mLocation(0), mOffset(0), mSize(0), mSamplerNum(-1), mInstancingConstant(false) +GFXGLShaderConstHandle::GFXGLShaderConstHandle(GFXGLShader* shader) + : mShader(shader), + mUBOUniform(false), + mInstancingConstant(false) { dMemset(&mDesc, 0, sizeof(mDesc)); mValid = false; } +GFXGLShaderConstHandle::GFXGLShaderConstHandle(GFXGLShader* shader, + const GFXShaderConstDesc& desc) + : mShader(shader), + mDesc(desc), + mUBOUniform(false), + mInstancingConstant(false) +{ + if (desc.constType == GFXSCT_ConstBuffer) + mValid = false; + else + mValid = true; +} + +void GFXGLShaderConstHandle::reinit(const GFXShaderConstDesc& desc) +{ + mDesc = desc; + mValid = true; +} + +GFXGLShaderConstHandle::~GFXGLShaderConstHandle() +{ +} + +const GFXShaderConstDesc GFXGLShaderConstHandle::getDesc() +{ + return mDesc; +} + static U32 shaderConstTypeSize(GFXShaderConstType type) { - switch(type) + switch (type) { case GFXSCT_Float: case GFXSCT_Int: + case GFXSCT_UInt: + case GFXSCT_Bool: case GFXSCT_Sampler: case GFXSCT_SamplerCube: case GFXSCT_SamplerCubeArray: @@ -86,12 +86,18 @@ static U32 shaderConstTypeSize(GFXShaderConstType type) return 4; case GFXSCT_Float2: case GFXSCT_Int2: + case GFXSCT_UInt2: + case GFXSCT_Bool2: return 8; case GFXSCT_Float3: case GFXSCT_Int3: + case GFXSCT_UInt3: + case GFXSCT_Bool3: return 12; case GFXSCT_Float4: case GFXSCT_Int4: + case GFXSCT_UInt4: + case GFXSCT_Bool4: return 16; case GFXSCT_Float2x2: return 16; @@ -102,79 +108,56 @@ static U32 shaderConstTypeSize(GFXShaderConstType type) case GFXSCT_Float4x4: return 64; default: - AssertFatal(false,"shaderConstTypeSize - Unrecognized constant type"); + AssertFatal(false, "shaderConstTypeSize - Unrecognized constant type"); return 0; } } -GFXGLShaderConstHandle::GFXGLShaderConstHandle( GFXGLShader *shader, const GFXShaderConstDesc &desc, GLuint loc, S32 samplerNum ) - : mShader(shader), mInstancingConstant(false) -{ - reinit(desc, loc, samplerNum); -} - -void GFXGLShaderConstHandle::reinit( const GFXShaderConstDesc& desc, GLuint loc, S32 samplerNum ) -{ - mDesc = desc; - mLocation = loc; - mSamplerNum = samplerNum; - mOffset = 0; - mInstancingConstant = false; - - U32 elemSize = shaderConstTypeSize(mDesc.constType); - AssertFatal(elemSize, "GFXGLShaderConst::GFXGLShaderConst - elemSize is 0"); - mSize = mDesc.arraySize * elemSize; - mValid = true; -} - - -U32 GFXGLShaderConstHandle::getSize() const -{ - return mSize; -} - -GFXGLShaderConstHandle::~GFXGLShaderConstHandle() -{ -} - -GFXGLShaderConstBuffer::GFXGLShaderConstBuffer(GFXGLShader* shader, U32 bufSize, U8* existingConstants) +GFXGLShaderConstBuffer::GFXGLShaderConstBuffer(GFXGLShader* shader) { mShader = shader; - mBuffer = new U8[bufSize]; mWasLost = true; - - // Copy the existing constant buffer to preserve sampler numbers - /// @warning This preserves a lot more than sampler numbers, obviously. If there - /// is any code that assumes a new constant buffer will have everything set to - /// 0, it will break. - dMemcpy(mBuffer, existingConstants, bufSize); } GFXGLShaderConstBuffer::~GFXGLShaderConstBuffer() { - delete[] mBuffer; - - if ( mShader ) - mShader->_unlinkBuffer( this ); + if (mShader) + mShader->_unlinkBuffer(this); } template void GFXGLShaderConstBuffer::internalSet(GFXShaderConstHandle* handle, const ConstType& param) { - AssertFatal(handle, "GFXGLShaderConstBuffer::internalSet - Handle is NULL!" ); - AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::internalSet - Handle is not valid!" ); + AssertFatal(handle, "GFXGLShaderConstBuffer::internalSet - Handle is NULL!"); + AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::internalSet - Handle is not valid!"); AssertFatal(dynamic_cast(handle), "GFXGLShaderConstBuffer::set - Incorrect const buffer type"); GFXGLShaderConstHandle* _glHandle = static_cast(handle); AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); - U8 *buf = mBuffer + _glHandle->mOffset; - if(_glHandle->mInstancingConstant) - buf = mInstPtr + _glHandle->mOffset; + U8* basePointer; + if (!_glHandle->mUBOUniform) + { + basePointer = mBufferMap[-1].data; + } + else + { + basePointer = mBufferMap[_glHandle->mDesc.bindPoint].data; + } + + U8* buf = basePointer + _glHandle->mDesc.offset; + + if (_glHandle->mInstancingConstant) + buf = mInstPtr + _glHandle->mDesc.offset; dMemcpy(buf, ¶m, sizeof(ConstType)); } +GFXShader* GFXGLShaderConstBuffer::getShader() +{ + return mShader; +} + void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const F32 fv) { internalSet(handle, fv); @@ -204,7 +187,7 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const LinearColor { internalSet(handle, fv); } - + void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const S32 fv) { internalSet(handle, fv); @@ -228,17 +211,28 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const Point4I& fv template void GFXGLShaderConstBuffer::internalSet(GFXShaderConstHandle* handle, const AlignedArray& fv) { - AssertFatal(handle, "GFXGLShaderConstBuffer::internalSet - Handle is NULL!" ); - AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::internalSet - Handle is not valid!" ); + AssertFatal(handle, "GFXGLShaderConstBuffer::internalSet - Handle is NULL!"); + AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::internalSet - Handle is not valid!"); AssertFatal(dynamic_cast(handle), "GFXGLShaderConstBuffer::set - Incorrect const buffer type"); GFXGLShaderConstHandle* _glHandle = static_cast(handle); AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); AssertFatal(!_glHandle->mInstancingConstant, "GFXGLShaderConstBuffer::set - Instancing not supported for array"); - const U8* fvBuffer = static_cast(fv.getBuffer()); - for(U32 i = 0; i < fv.size(); ++i) + + U8* basePointer; + if (!_glHandle->mUBOUniform) { - dMemcpy(mBuffer + _glHandle->mOffset + i * sizeof(ConstType), fvBuffer, sizeof(ConstType)); + basePointer = mBufferMap[-1].data; + } + else + { + basePointer = mBufferMap[_glHandle->mDesc.bindPoint].data; + } + + const U8* fvBuffer = static_cast(fv.getBuffer()); + for (U32 i = 0; i < fv.size(); ++i) + { + dMemcpy(basePointer + _glHandle->mDesc.offset + i * sizeof(ConstType), fvBuffer, sizeof(ConstType)); fvBuffer += fv.getElementSize(); } } @@ -258,7 +252,7 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArra internalSet(handle, fv); } -void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray& fv) +void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArray& fv) { internalSet(handle, fv); } @@ -285,47 +279,57 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const AlignedArra void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& mat, const GFXShaderConstType matType) { - AssertFatal(handle, "GFXGLShaderConstBuffer::set - Handle is NULL!" ); - AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::set - Handle is not valid!" ); + AssertFatal(handle, "GFXGLShaderConstBuffer::set - Handle is NULL!"); + AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::set - Handle is not valid!"); AssertFatal(dynamic_cast(handle), "GFXGLShaderConstBuffer::set - Incorrect const buffer type"); GFXGLShaderConstHandle* _glHandle = static_cast(handle); AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); AssertFatal(!_glHandle->mInstancingConstant || matType == GFXSCT_Float4x4, "GFXGLShaderConstBuffer::set - Only support GFXSCT_Float4x4 for instancing"); - - switch(matType) + + U8* basePointer; + if (!_glHandle->mUBOUniform) + { + basePointer = mBufferMap[-1].data; + } + else + { + basePointer = mBufferMap[_glHandle->mDesc.bindPoint].data; + } + + switch (matType) { case GFXSCT_Float2x2: - reinterpret_cast(mBuffer + _glHandle->mOffset)[0] = mat[0]; - reinterpret_cast(mBuffer + _glHandle->mOffset)[1] = mat[1]; - reinterpret_cast(mBuffer + _glHandle->mOffset)[2] = mat[4]; - reinterpret_cast(mBuffer + _glHandle->mOffset)[3] = mat[5]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[0] = mat[0]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[1] = mat[1]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[2] = mat[4]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[3] = mat[5]; break; case GFXSCT_Float3x3: - reinterpret_cast(mBuffer + _glHandle->mOffset)[0] = mat[0]; - reinterpret_cast(mBuffer + _glHandle->mOffset)[1] = mat[1]; - reinterpret_cast(mBuffer + _glHandle->mOffset)[2] = mat[2]; - reinterpret_cast(mBuffer + _glHandle->mOffset)[3] = mat[4]; - reinterpret_cast(mBuffer + _glHandle->mOffset)[4] = mat[5]; - reinterpret_cast(mBuffer + _glHandle->mOffset)[5] = mat[6]; - reinterpret_cast(mBuffer + _glHandle->mOffset)[6] = mat[8]; - reinterpret_cast(mBuffer + _glHandle->mOffset)[7] = mat[9]; - reinterpret_cast(mBuffer + _glHandle->mOffset)[8] = mat[10]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[0] = mat[0]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[1] = mat[1]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[2] = mat[2]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[3] = mat[4]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[4] = mat[5]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[5] = mat[6]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[6] = mat[8]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[7] = mat[9]; + reinterpret_cast(basePointer + _glHandle->mDesc.offset)[8] = mat[10]; break; case GFXSCT_Float4x3: - dMemcpy(mBuffer + _glHandle->mOffset, (const F32*)mat, (sizeof(F32) * 12));// matrix with end row chopped off + dMemcpy(basePointer + _glHandle->mDesc.offset, (const F32*)mat, (sizeof(F32) * 12));// matrix with end row chopped off break; case GFXSCT_Float4x4: - { - if(_glHandle->mInstancingConstant) + { + if (_glHandle->mInstancingConstant) { - MatrixF transposed; + MatrixF transposed; mat.transposeTo(transposed); - dMemcpy( mInstPtr + _glHandle->mOffset, (const F32*)transposed, sizeof(MatrixF) ); + dMemcpy(mInstPtr + _glHandle->mDesc.offset, (const F32*)transposed, sizeof(MatrixF)); return; } - - dMemcpy(mBuffer + _glHandle->mOffset, (const F32*)mat, sizeof(MatrixF)); + + dMemcpy(basePointer + _glHandle->mDesc.offset, (const F32*)mat, sizeof(MatrixF)); break; } default: @@ -336,69 +340,170 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& ma void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF* mat, const U32 arraySize, const GFXShaderConstType matrixType) { - AssertFatal(handle, "GFXGLShaderConstBuffer::set - Handle is NULL!" ); - AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::set - Handle is not valid!" ); + AssertFatal(handle, "GFXGLShaderConstBuffer::set - Handle is NULL!"); + AssertFatal(handle->isValid(), "GFXGLShaderConstBuffer::set - Handle is not valid!"); GFXGLShaderConstHandle* _glHandle = static_cast(handle); - AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); + AssertFatal(mShader == _glHandle->mShader, "GFXGLShaderConstBuffer::set - Should only set handles which are owned by our shader"); AssertFatal(!_glHandle->mInstancingConstant, "GFXGLShaderConstBuffer::set - Instancing not supported for matrix arrays"); + U8* basePointer; + if (!_glHandle->mUBOUniform) + { + basePointer = mBufferMap[-1].data; + } + else + { + basePointer = mBufferMap[_glHandle->mDesc.bindPoint].data; + } + switch (matrixType) { - case GFXSCT_Float4x3: - // Copy each item with the last row chopped off - for (int i = 0; imOffset + (i*(sizeof(F32) * 12)), (F32*)(mat + i), sizeof(F32) * 12); - } + case GFXSCT_Float4x3: + // Copy each item with the last row chopped off + for (int i = 0; i < arraySize; i++) + { + dMemcpy(basePointer + _glHandle->mDesc.offset + (i * (sizeof(F32) * 12)), (F32*)(mat + i), sizeof(F32) * 12); + } + break; + case GFXSCT_Float4x4: + dMemcpy(basePointer + _glHandle->mDesc.offset, (F32*)mat, _glHandle->getSize()); + break; + default: + AssertFatal(false, "GFXGLShaderConstBuffer::set - setting array of non 4x4 matrices!"); break; - case GFXSCT_Float4x4: - dMemcpy(mBuffer + _glHandle->mOffset, (F32*)mat, _glHandle->getSize()); - break; - default: - AssertFatal(false, "GFXGLShaderConstBuffer::set - setting array of non 4x4 matrices!"); - break; } } -void GFXGLShaderConstBuffer::activate() +void GFXGLShaderConstBuffer::activate(GFXGLShaderConstBuffer* prevShaderBuffer) { PROFILE_SCOPE(GFXGLShaderConstBuffer_activate); - mShader->setConstantsFromBuffer(this); + + for (BufferMap::Iterator i = mBufferMap.begin(); i != mBufferMap.end(); ++i) + { + const S32 thisBufferDesc = i->key; + + // set the global buffer differently + if (thisBufferDesc == -1) + { + mShader->setConstantsFromBuffer(mBufferMap[-1].data); + continue; + } + + ConstantBuffer thisBuff = i->value; + + if (prevShaderBuffer && prevShaderBuffer != this) + { + const ConstantBuffer prevBuffer = prevShaderBuffer->mBufferMap[i->key]; + + if (prevBuffer.data && !prevBuffer.isDirty) + { + if (prevBuffer.size != thisBuff.size) + { + thisBuff.isDirty = true; + } + else + { + if (dMemcmp(prevBuffer.data, thisBuff.data, thisBuff.size) != 0) + { + thisBuff.isDirty = true; + } + else + { + thisBuff.isDirty = false; + } + } + } + else + { + thisBuff.isDirty = true; + } + } + else + { + thisBuff.isDirty = true; + } + + if (thisBuff.data && thisBuff.isDirty) + { + glBindBuffer(GL_UNIFORM_BUFFER, thisBuff.bufHandle); + glBufferData(GL_UNIFORM_BUFFER, thisBuff.size, thisBuff.data, GL_DYNAMIC_DRAW); + glBindBufferBase(GL_UNIFORM_BUFFER, thisBufferDesc, thisBuff.bufHandle); + } + } + mWasLost = false; } +void GFXGLShaderConstBuffer::addBuffer(const GFXShaderConstDesc desc) +{ + // if this is the global buffer set it to the highest. + if (desc.bindPoint == -1) + { + // we dont create a bufferhandle for this one. + U8* buf = new U8[desc.size]; + dMemset(buf, 0, desc.size); + mBufferMap[-1].data = buf; + mBufferMap[-1].size = desc.size; + mBufferMap[-1].isDirty = true; + } + else + { + U8* buf = new U8[desc.size]; + dMemset(buf, 0, desc.size); + mBufferMap[desc.bindPoint].data = buf; + mBufferMap[desc.bindPoint].size = desc.size; + mBufferMap[desc.bindPoint].isDirty = true; + + mBufferMap[desc.bindPoint].bufHandle = GFXGL->getDeviceBuffer(desc); + } +} + const String GFXGLShaderConstBuffer::describeSelf() const { return String(); } -void GFXGLShaderConstBuffer::onShaderReload( GFXGLShader *shader ) +void GFXGLShaderConstBuffer::onShaderReload(GFXGLShader* shader) { - AssertFatal( shader == mShader, "GFXGLShaderConstBuffer::onShaderReload, mismatched shaders!" ); + AssertFatal(shader == mShader, "GFXGLShaderConstBuffer::onShaderReload, mismatched shaders!"); + + for (auto& pair : mBufferMap) { + delete[] pair.value.data; + } + mBufferMap.clear(); // Clear the map + + for (GFXGLShader::BufferMap::Iterator i = shader->mBuffers.begin(); i != shader->mBuffers.end(); ++i) + { + // add our buffer descriptions to the full const buffer. + this->addBuffer(i->value); + } - delete[] mBuffer; - mBuffer = new U8[mShader->mConstBufferSize]; - dMemset(mBuffer, 0, mShader->mConstBufferSize); mWasLost = true; } GFXGLShader::GFXGLShader(GFXGLDevice* device) : mVertexShader(0), mPixelShader(0), + mGeometryShader(0), mProgram(0), mDevice(device), - mConstBufferSize(0), - mConstBuffer(NULL) + mGlobalConstBuffer(NULL) { } GFXGLShader::~GFXGLShader() { clearShaders(); - for(HandleMap::Iterator i = mHandles.begin(); i != mHandles.end(); i++) - delete i->value; - - delete[] mConstBuffer; + for (auto& pair : mHandles) { + if (pair.value != nullptr) { + delete pair.value; + pair.value = nullptr; + } + } + mHandles.clear(); + + if (mGlobalConstBuffer) + delete[] mGlobalConstBuffer; } void GFXGLShader::clearShaders() @@ -406,259 +511,379 @@ void GFXGLShader::clearShaders() glDeleteProgram(mProgram); glDeleteShader(mVertexShader); glDeleteShader(mPixelShader); - + glDeleteShader(mGeometryShader); + mProgram = 0; mVertexShader = 0; mPixelShader = 0; + mGeometryShader = 0; } bool GFXGLShader::_init() { PROFILE_SCOPE(GFXGLShader_Init); // Don't initialize empty shaders. - if ( mVertexFile.isEmpty() && mPixelFile.isEmpty() ) + if (mVertexFile.isEmpty() && mPixelFile.isEmpty()) return false; clearShaders(); mProgram = glCreateProgram(); - + // Set the macros and add the global ones. Vector macros; - macros.merge( mMacros ); - macros.merge( smGlobalMacros ); - + macros.merge(mMacros); + macros.merge(smGlobalMacros); + macros.increment(); macros.last().name = "TORQUE_SM"; macros.last().value = 40; macros.increment(); macros.last().name = "TORQUE_VERTEX_SHADER"; macros.last().value = ""; - + // Default to true so we're "successful" if a vertex/pixel shader wasn't specified. bool compiledVertexShader = true; bool compiledPixelShader = true; - - // Compile the vertex and pixel shaders if specified. - if(!mVertexFile.isEmpty()) - compiledVertexShader = initShader(mVertexFile, true, macros); + bool compiledGeometryShader = true; + + // Compile the vertex and pixel shaders if specified. + if (!mVertexFile.isEmpty()) + { + compiledVertexShader = initShader(mVertexFile, GFXShaderStage::VERTEX_SHADER, macros); + if (!compiledVertexShader) + return false; + } + + if (!mPixelFile.isEmpty()) + { + macros.last().name = "TORQUE_PIXEL_SHADER"; + compiledPixelShader = initShader(mPixelFile, GFXShaderStage::PIXEL_SHADER, macros); + if (!compiledPixelShader) + return false; + } + + if (!mGeometryFile.isEmpty()) + { + macros.last().name = "TORQUE_GEOMETRY_SHADER"; + compiledGeometryShader = initShader(mGeometryFile, GFXShaderStage::GEOMETRY_SHADER, macros); + if (!compiledGeometryShader) + return false; + } - macros.last().name = "TORQUE_PIXEL_SHADER"; - if(!mPixelFile.isEmpty()) - compiledPixelShader = initShader(mPixelFile, false, macros); - - // If either shader was present and failed to compile, bail. - if(!compiledVertexShader || !compiledPixelShader) - return false; - // Link it! - glLinkProgram( mProgram ); - - GLint activeAttribs = 0; - glGetProgramiv(mProgram, GL_ACTIVE_ATTRIBUTES, &activeAttribs ); - + glLinkProgram(mProgram); + + GLint activeAttribs = 0; + glGetProgramiv(mProgram, GL_ACTIVE_ATTRIBUTES, &activeAttribs); + GLint maxLength; glGetProgramiv(mProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength); - - FrameTemp tempData(maxLength+1); + + FrameTemp tempData(maxLength + 1); *tempData.address() = '\0'; // Check atributes - for (U32 i=0; iinsert(tempData.address()); - - CHECK_AARG(Torque::GL_VertexAttrib_Position, vPosition); - CHECK_AARG(Torque::GL_VertexAttrib_Normal, vNormal); - CHECK_AARG(Torque::GL_VertexAttrib_Color, vColor); - CHECK_AARG(Torque::GL_VertexAttrib_Tangent, vTangent); - CHECK_AARG(Torque::GL_VertexAttrib_TangentW, vTangentW); - CHECK_AARG(Torque::GL_VertexAttrib_Binormal, vBinormal); - CHECK_AARG(Torque::GL_VertexAttrib_TexCoord0, vTexCoord0); - CHECK_AARG(Torque::GL_VertexAttrib_TexCoord1, vTexCoord1); - CHECK_AARG(Torque::GL_VertexAttrib_TexCoord2, vTexCoord2); - CHECK_AARG(Torque::GL_VertexAttrib_TexCoord3, vTexCoord3); - CHECK_AARG(Torque::GL_VertexAttrib_TexCoord4, vTexCoord4); - CHECK_AARG(Torque::GL_VertexAttrib_TexCoord5, vTexCoord5); - CHECK_AARG(Torque::GL_VertexAttrib_TexCoord6, vTexCoord6); - CHECK_AARG(Torque::GL_VertexAttrib_TexCoord7, vTexCoord7); - CHECK_AARG(Torque::GL_VertexAttrib_TexCoord8, vTexCoord8); - CHECK_AARG(Torque::GL_VertexAttrib_TexCoord9, vTexCoord9); + + CHECK_AARG(Torque::GL_VertexAttrib_Position, vPosition); + CHECK_AARG(Torque::GL_VertexAttrib_Normal, vNormal); + CHECK_AARG(Torque::GL_VertexAttrib_Color, vColor); + CHECK_AARG(Torque::GL_VertexAttrib_Tangent, vTangent); + CHECK_AARG(Torque::GL_VertexAttrib_TangentW, vTangentW); + CHECK_AARG(Torque::GL_VertexAttrib_Binormal, vBinormal); + CHECK_AARG(Torque::GL_VertexAttrib_TexCoord0, vTexCoord0); + CHECK_AARG(Torque::GL_VertexAttrib_TexCoord1, vTexCoord1); + CHECK_AARG(Torque::GL_VertexAttrib_TexCoord2, vTexCoord2); + CHECK_AARG(Torque::GL_VertexAttrib_TexCoord3, vTexCoord3); + CHECK_AARG(Torque::GL_VertexAttrib_TexCoord4, vTexCoord4); + CHECK_AARG(Torque::GL_VertexAttrib_TexCoord5, vTexCoord5); + CHECK_AARG(Torque::GL_VertexAttrib_TexCoord6, vTexCoord6); + CHECK_AARG(Torque::GL_VertexAttrib_TexCoord7, vTexCoord7); + CHECK_AARG(Torque::GL_VertexAttrib_TexCoord8, vTexCoord8); + CHECK_AARG(Torque::GL_VertexAttrib_TexCoord9, vTexCoord9); } //always have OUT_col glBindFragDataLocation(mProgram, 0, "OUT_col"); // Check OUT_colN - for(U32 i=1;i<4;i++) + for (U32 i = 1; i < 4; i++) { char buffer[10]; - dSprintf(buffer, sizeof(buffer), "OUT_col%u",i); + dSprintf(buffer, sizeof(buffer), "OUT_col%u", i); GLint location = glGetFragDataLocation(mProgram, buffer); - if(location>0) + if (location > 0) glBindFragDataLocation(mProgram, i, buffer); } - + // Link it again! - glLinkProgram( mProgram ); - + glLinkProgram(mProgram); + GLint linkStatus; - glGetProgramiv( mProgram, GL_LINK_STATUS, &linkStatus ); - + glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus); + // Dump the info log to the console U32 logLength = 0; glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, (GLint*)&logLength); - if ( logLength ) + if (logLength) { FrameAllocatorMarker fam; - char* log = (char*)fam.alloc( logLength ); - glGetProgramInfoLog( mProgram, logLength, NULL, log ); - - if ( linkStatus == GL_FALSE ) + char* log = (char*)fam.alloc(logLength); + glGetProgramInfoLog(mProgram, logLength, NULL, log); + + if (linkStatus == GL_FALSE) { - if ( smLogErrors ) + if (smLogErrors) { - Con::errorf( "GFXGLShader::init - Error linking shader!" ); - Con::errorf( "Program %s / %s: %s", + Con::errorf("GFXGLShader::init - Error linking shader!"); + Con::errorf("Program %s / %s: %s", mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log); } } - else if ( smLogWarnings ) + else if (smLogWarnings) { - Con::warnf( "Program %s / %s: %s", + Con::warnf("Program %s / %s: %s", mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log); } } // If we failed to link, bail. - if ( linkStatus == GL_FALSE ) + if (linkStatus == GL_FALSE) return false; - initConstantDescs(); + initConstantDescs(); initHandles(); - - // Notify Buffers we might have changed in size. - // If this was our first init then we won't have any activeBuffers + + // Notify Buffers we might have changed in size. + // If this was our first init then we won't have any activeBuffers // to worry about unnecessarily calling. Vector::iterator biter = mActiveBuffers.begin(); - for ( ; biter != mActiveBuffers.end(); biter++ ) - ((GFXGLShaderConstBuffer*)(*biter))->onShaderReload( this ); - + for (; biter != mActiveBuffers.end(); biter++) + ((GFXGLShaderConstBuffer*)(*biter))->onShaderReload(this); + return true; } void GFXGLShader::initConstantDescs() { - mConstants.clear(); - GLint numUniforms; - glGetProgramiv(mProgram, GL_ACTIVE_UNIFORMS, &numUniforms); + // clear our vectors. + mShaderConsts.clear(); + GLint maxNameLength; glGetProgramiv(mProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); - if(!maxNameLength) + if (!maxNameLength) return; maxNameLength++; FrameTemp uniformName(maxNameLength); - - for(U32 i = 0; i < numUniforms; i++) + + // parse ubos first and add them to our table, same as in dx + // this is required so that in the other uniform loop we dont add + // a uniform that exists in a ubo again. + GLint numUBOS; + glGetProgramiv(mProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numUBOS); + for (U32 i = 0; i < numUBOS; i++) { + GFXShaderConstDesc desc; + GLint uboNameLen; + glGetActiveUniformBlockiv(mProgram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &uboNameLen); + if (!uboNameLen) + return; + uboNameLen++; + + // get the name of the ubo for getting required data. + FrameTemp uboName(uboNameLen); + glGetActiveUniformBlockName(mProgram, i, uboNameLen, NULL, uboName); + GLint uboBinding; + glGetActiveUniformBlockiv(mProgram, i, GL_UNIFORM_BLOCK_BINDING, &uboBinding); + GLint uboSize; + glGetActiveUniformBlockiv(mProgram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &uboSize); + GLint numUboUniforms; + glGetActiveUniformBlockiv(mProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numUboUniforms); + GLint* indices = new GLint[numUboUniforms]; + glGetActiveUniformBlockiv(mProgram, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices); + + // fill out ubo desc. + desc.name = String((char*)uboName); + desc.bindPoint = uboBinding; + desc.size = uboSize; + desc.constType = GFXSCT_ConstBuffer; + desc.samplerReg = -1; + + mBuffers[desc.name] = desc; + + // loop uniforms in the ubo. + for (U32 j = 0; j < numUboUniforms; j++) + { + GFXShaderConstDesc varDesc; + + GLint uniformIndex = indices[j]; + GLint size; + GLenum type; + GLint offset; + glGetActiveUniformsiv(mProgram, 1, (const GLuint*)&uniformIndex, GL_UNIFORM_OFFSET, &offset); + glGetActiveUniform(mProgram, uniformIndex, maxNameLength, NULL, &size, &type, uniformName); + + varDesc.name = String((char*)uniformName); + // remove array brackets. + varDesc.name = varDesc.name.substr(0, varDesc.name.find('[')); + // Insert $ to match D3D behavior of having a $ prepended to parameters to main. + varDesc.name.insert(0, '$'); + varDesc.bindPoint = desc.bindPoint; // just set to the buffer bindpoint for uniforms in a ubo. + varDesc.offset = offset; + varDesc.arraySize = size; + varDesc.constType = convertConstType(type); + varDesc.size = shaderConstTypeSize(varDesc.constType) * size; + varDesc.samplerReg = -1; + +#ifdef OPENGL_DEBUG_SPEW + Con::printf("Variable Name %s:, offset: %d, size: %d, constantDesc.Elements: %d", varDesc.name.c_str(), varDesc.offset, varDesc.size, varDesc.arraySize); +#endif + mShaderConsts.push_back(varDesc); + } + } + + GLint numUniforms; + glGetProgramiv(mProgram, GL_ACTIVE_UNIFORMS, &numUniforms); + + for (U32 i = 0; i < numUniforms; i++) { + // skip if this uniform is inside a ubo. + GLint blk; + glGetActiveUniformsiv(mProgram, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &blk); + if (blk != -1) + { + continue; + } + GLint size; GLenum type; glGetActiveUniform(mProgram, i, maxNameLength, NULL, &size, &type, uniformName); + GFXShaderConstDesc desc; - desc.name = String((char*)uniformName); - // Remove array brackets from the name desc.name = desc.name.substr(0, desc.name.find('[')); - // Insert $ to match D3D behavior of having a $ prepended to parameters to main. desc.name.insert(0, '$'); + + desc.bindPoint = -1; desc.arraySize = size; - - switch(type) - { - case GL_FLOAT: - desc.constType = GFXSCT_Float; - break; - case GL_FLOAT_VEC2: - desc.constType = GFXSCT_Float2; - break; - case GL_FLOAT_VEC3: - desc.constType = GFXSCT_Float3; - break; - case GL_FLOAT_VEC4: - desc.constType = GFXSCT_Float4; - break; - case GL_INT: - desc.constType = GFXSCT_Int; - break; - case GL_INT_VEC2: - desc.constType = GFXSCT_Int2; - break; - case GL_INT_VEC3: - desc.constType = GFXSCT_Int3; - break; - case GL_INT_VEC4: - desc.constType = GFXSCT_Int4; - break; - case GL_FLOAT_MAT2: - desc.constType = GFXSCT_Float2x2; - break; - case GL_FLOAT_MAT3: - desc.constType = GFXSCT_Float3x3; - break; - case GL_FLOAT_MAT4: - desc.constType = GFXSCT_Float4x4; - break; - case GL_FLOAT_MAT4x3: // jamesu - columns, rows - desc.constType = GFXSCT_Float4x3; - break; - case GL_SAMPLER_1D: - case GL_SAMPLER_2D: - case GL_SAMPLER_3D: - case GL_SAMPLER_1D_SHADOW: - case GL_SAMPLER_2D_SHADOW: - desc.constType = GFXSCT_Sampler; - break; - case GL_SAMPLER_CUBE: - desc.constType = GFXSCT_SamplerCube; - break; - 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. - continue; - } - - mConstants.push_back(desc); + desc.constType = convertConstType(type); + desc.size = shaderConstTypeSize(desc.constType) * size; + desc.samplerReg = -1; + mShaderConsts.push_back(desc); } } +GFXShaderConstType GFXGLShader::convertConstType(GLenum constType) +{ + switch (constType) + { + case GL_FLOAT: + return GFXSCT_Float; + break; + case GL_FLOAT_VEC2: + return GFXSCT_Float2; + break; + case GL_FLOAT_VEC3: + return GFXSCT_Float3; + break; + case GL_FLOAT_VEC4: + return GFXSCT_Float4; + break; + case GL_INT: + return GFXSCT_Int; + break; + case GL_INT_VEC2: + return GFXSCT_Int2; + break; + case GL_INT_VEC3: + return GFXSCT_Int3; + break; + case GL_INT_VEC4: + return GFXSCT_Int4; + break; + case GL_UNSIGNED_INT: + return GFXSCT_UInt; + break; + case GL_UNSIGNED_INT_VEC2: + return GFXSCT_UInt2; + break; + case GL_UNSIGNED_INT_VEC3: + return GFXSCT_UInt3; + break; + case GL_UNSIGNED_INT_VEC4: + return GFXSCT_UInt4; + break; + case GL_BOOL: + return GFXSCT_Bool; + break; + case GL_BOOL_VEC2: + return GFXSCT_Bool2; + break; + case GL_BOOL_VEC3: + return GFXSCT_Bool3; + break; + case GL_BOOL_VEC4: + return GFXSCT_Bool4; + break; + case GL_FLOAT_MAT2: + return GFXSCT_Float2x2; + break; + case GL_FLOAT_MAT3: + return GFXSCT_Float3x3; + break; + case GL_FLOAT_MAT4: + return GFXSCT_Float4x4; + break; + case GL_FLOAT_MAT4x3: // jamesu - columns, rows + return GFXSCT_Float4x3; + break; + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + return GFXSCT_Sampler; + break; + case GL_SAMPLER_CUBE: + return GFXSCT_SamplerCube; + break; + case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: + return GFXSCT_SamplerCubeArray; + break; + case GL_SAMPLER_2D_ARRAY: + return GFXSCT_SamplerTextureArray; + break; + default: + AssertFatal(false, "Unknown shader constant class enum, maybe you could add it?"); + // If we don't recognize the constant don't add its description. + break; + } + + return GFXSCT_Uknown; +} + void GFXGLShader::initHandles() -{ +{ // Mark all existing handles as invalid. // Those that are found when parsing the descriptions will then be marked valid again. - for ( HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter ) - (iter->value)->setValid( false ); - mValidHandles.clear(); + for (HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter) + (iter->value)->setValid(false); - // Loop through all ConstantDescriptions, - // if they aren't in the HandleMap add them, if they are reinitialize them. - for ( U32 i = 0; i < mConstants.size(); i++ ) + // Loop through constants that exist in ubos. + for (U32 i = 0; i < mShaderConsts.size(); i++) { - GFXShaderConstDesc &desc = mConstants[i]; + GFXShaderConstDesc& desc = mShaderConsts[i]; // Index element 1 of the name to skip the '$' we inserted earier. GLint loc = glGetUniformLocation(mProgram, &desc.name.c_str()[1]); @@ -667,7 +892,7 @@ void GFXGLShader::initHandles() HandleMap::Iterator handle = mHandles.find(desc.name); S32 sampler = -1; - if(desc.constType == GFXSCT_Sampler || + if (desc.constType == GFXSCT_Sampler || desc.constType == GFXSCT_SamplerCube || desc.constType == GFXSCT_SamplerCubeArray || desc.constType == GFXSCT_SamplerTextureArray) @@ -675,38 +900,72 @@ void GFXGLShader::initHandles() S32 idx = mSamplerNamesOrdered.find_next(desc.name); AssertFatal(idx != -1, ""); sampler = idx; //assignedSamplerNum++; + desc.samplerReg = idx; } - if ( handle != mHandles.end() ) + + if (handle != mHandles.end()) { - handle->value->reinit( desc, loc, sampler ); - } - else + if (desc.bindPoint == -1) + { + desc.bindPoint = loc; + mHandles[desc.name]->mUBOUniform = false; + } + else + { + mHandles[desc.name]->mUBOUniform = true; + } + + handle->value->reinit(desc); + } + else { - mHandles[desc.name] = new GFXGLShaderConstHandle( this, desc, loc, sampler ); + if (desc.bindPoint == -1) + { + desc.bindPoint = loc; + mHandles[desc.name] = new GFXGLShaderConstHandle(this, desc); + mHandles[desc.name]->mUBOUniform = false; + } + else + { + mHandles[desc.name] = new GFXGLShaderConstHandle(this, desc); + mHandles[desc.name]->mUBOUniform = true; + } } } - // Loop through handles once more to set their offset and calculate our - // constBuffer size. - if ( mConstBuffer ) - delete[] mConstBuffer; - mConstBufferSize = 0; + // we have a global const buffer, set it up and add it. + U32 constBufferSize = 0; - for ( HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter ) + if (mGlobalConstBuffer) + delete[] mGlobalConstBuffer; + + for (HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter) { GFXGLShaderConstHandle* handle = iter->value; - if ( handle->isValid() ) + if (handle->isValid() && !handle->mUBOUniform) { - mValidHandles.push_back(handle); - handle->mOffset = mConstBufferSize; - mConstBufferSize += handle->getSize(); + handle->mDesc.offset = constBufferSize; + constBufferSize += handle->getSize(); } } - - mConstBuffer = new U8[mConstBufferSize]; - dMemset(mConstBuffer, 0, mConstBufferSize); - + + if (constBufferSize > 0) + { + GFXShaderConstDesc desc; + // fill out ubo desc. + desc.name = "Global"; + desc.bindPoint = -1; + desc.size = constBufferSize; + desc.constType = GFXSCT_ConstBuffer; + desc.samplerReg = -1; + + mBuffers[desc.name] = desc; + + mGlobalConstBuffer = new U8[constBufferSize]; + dMemset(mGlobalConstBuffer, 0, constBufferSize); + } + // Set our program so uniforms are assigned properly. mDevice->setShader(this, false); @@ -714,16 +973,16 @@ void GFXGLShader::initHandles() for (HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter) { GFXGLShaderConstHandle* handle = iter->value; - if(handle->isValid() && + 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); + glUniform1i(handle->mDesc.bindPoint, handle->mDesc.samplerReg); // Set sampler in constant buffer so it does not get unset later. - dMemcpy(mConstBuffer + handle->mOffset, &handle->mSamplerNum, handle->getSize()); + dMemcpy(mGlobalConstBuffer + handle->mDesc.offset, &handle->mDesc.samplerReg, handle->getSize()); } } @@ -733,23 +992,23 @@ void GFXGLShader::initHandles() U32 offset = 0; - for ( U32 i=0; i < mInstancingFormat->getElementCount(); i++ ) + for (U32 i = 0; i < mInstancingFormat->getElementCount(); i++) { - const GFXVertexElement &element = mInstancingFormat->getElement( i ); - - String constName = String::ToString( "$%s", element.getSemantic().c_str() ); + const GFXVertexElement& element = mInstancingFormat->getElement(i); - HandleMap::Iterator handle = mHandles.find(constName); - if ( handle != mHandles.end() ) - { + String constName = String::ToString("$%s", element.getSemantic().c_str()); + + HandleMap::Iterator handle = mHandles.find(constName); + if (handle != mHandles.end()) + { AssertFatal(0, ""); - } - else + } + else { GFXShaderConstDesc desc; desc.name = constName; desc.arraySize = 1; - switch(element.getType()) + switch (element.getType()) { case GFXDeclType_Float4: desc.constType = GFXSCT_Float4; @@ -759,27 +1018,28 @@ void GFXGLShader::initHandles() desc.constType = GFXSCT_Float; break; } - - GFXGLShaderConstHandle *h = new GFXGLShaderConstHandle( this, desc, -1, -1 ); + + GFXGLShaderConstHandle* h = new GFXGLShaderConstHandle(this, desc); h->mInstancingConstant = true; - h->mOffset = offset; - mHandles[constName] = h; + h->mDesc.offset = offset; + h->mUBOUniform = false; + mHandles[constName] = h; offset += element.getSizeInBytes(); ++i; // If this is a matrix we will have 2 or 3 more of these // semantics with the same name after it. - for ( ; i < mInstancingFormat->getElementCount(); i++ ) + for (; i < mInstancingFormat->getElementCount(); i++) { - const GFXVertexElement &nextElement = mInstancingFormat->getElement( i ); - if ( nextElement.getSemantic() != element.getSemantic() ) + const GFXVertexElement& nextElement = mInstancingFormat->getElement(i); + if (nextElement.getSemantic() != element.getSemantic()) { i--; break; } ++desc.arraySize; - if(desc.arraySize == 4 && desc.constType == GFXSCT_Float4) + if (desc.arraySize == 4 && desc.constType == GFXSCT_Float4) { desc.arraySize = 1; desc.constType = GFXSCT_Float4x4; @@ -794,13 +1054,14 @@ void GFXGLShader::initHandles() GFXShaderConstHandle* GFXGLShader::getShaderConstHandle(const String& name) { HandleMap::Iterator i = mHandles.find(name); - if(i != mHandles.end()) + if (i != mHandles.end()) return i->value; else { - GFXGLShaderConstHandle* handle = new GFXGLShaderConstHandle( this ); - mHandles[ name ] = handle; - + GFXGLShaderConstHandle* handle = new GFXGLShaderConstHandle(this); + handle->setValid(false); + mHandles[name] = handle; + return handle; } } @@ -808,7 +1069,7 @@ GFXShaderConstHandle* GFXGLShader::getShaderConstHandle(const String& name) GFXShaderConstHandle* GFXGLShader::findShaderConstHandle(const String& name) { HandleMap::Iterator i = mHandles.find(name); - if(i != mHandles.end()) + if (i != mHandles.end()) return i->value; else { @@ -816,79 +1077,92 @@ GFXShaderConstHandle* GFXGLShader::findShaderConstHandle(const String& name) } } -void GFXGLShader::setConstantsFromBuffer(GFXGLShaderConstBuffer* buffer) +void GFXGLShader::setConstantsFromBuffer(U8* buffer) { - for(Vector::iterator i = mValidHandles.begin(); i != mValidHandles.end(); ++i) + for (HandleMap::Iterator i = mHandles.begin(); i != mHandles.end(); ++i) { - GFXGLShaderConstHandle* handle = *i; + GFXGLShaderConstHandle* handle = i->value; AssertFatal(handle, "GFXGLShader::setConstantsFromBuffer - Null handle"); - - if(handle->mInstancingConstant) + // skip ubo uniforms. + if (handle->mUBOUniform || !handle->isValid()) continue; - + + if (handle->mInstancingConstant) + continue; + // Don't set if the value has not be changed. - if(dMemcmp(mConstBuffer + handle->mOffset, buffer->mBuffer + handle->mOffset, handle->getSize()) == 0) + if (dMemcmp(mGlobalConstBuffer + handle->mDesc.offset, buffer + handle->mDesc.offset, handle->getSize()) == 0) continue; - - // Copy new value into our const buffer and set in GL. - dMemcpy(mConstBuffer + handle->mOffset, buffer->mBuffer + handle->mOffset, handle->getSize()); - switch(handle->mDesc.constType) + // Copy new value into our const buffer and set in GL. + dMemcpy(mGlobalConstBuffer + handle->mDesc.offset, buffer + handle->mDesc.offset, handle->getSize()); + + switch (handle->mDesc.constType) { - case GFXSCT_Float: - glUniform1fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); - break; - case GFXSCT_Float2: - glUniform2fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); - break; - case GFXSCT_Float3: - glUniform3fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); - break; - case GFXSCT_Float4: - glUniform4fv(handle->mLocation, handle->mDesc.arraySize, (GLfloat*)(mConstBuffer + handle->mOffset)); - break; - case GFXSCT_Int: - 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: - glUniform2iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); - break; - case GFXSCT_Int3: - glUniform3iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); - break; - case GFXSCT_Int4: - glUniform4iv(handle->mLocation, handle->mDesc.arraySize, (GLint*)(mConstBuffer + handle->mOffset)); - break; - case GFXSCT_Float2x2: - glUniformMatrix2fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); - break; - case GFXSCT_Float3x3: - glUniformMatrix3fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); - break; - case GFXSCT_Float4x3: - // NOTE: To save a transpose here we could store the matrix transposed (i.e. column major) in the constant buffer. - // See _mesa_uniform_matrix in the mesa source for the correct transpose algorithm for a 4x3 matrix. - glUniformMatrix4x3fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); - break; - case GFXSCT_Float4x4: - glUniformMatrix4fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset)); - break; - default: - AssertFatal(0,""); - break; + case GFXSCT_Float: + glUniform1fv(handle->mDesc.bindPoint, handle->mDesc.arraySize, (GLfloat*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + case GFXSCT_Float2: + glUniform2fv(handle->mDesc.bindPoint, handle->mDesc.arraySize, (GLfloat*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + case GFXSCT_Float3: + glUniform3fv(handle->mDesc.bindPoint, handle->mDesc.arraySize, (GLfloat*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + case GFXSCT_Float4: + glUniform4fv(handle->mDesc.bindPoint, handle->mDesc.arraySize, (GLfloat*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + case GFXSCT_Sampler: + case GFXSCT_SamplerCube: + case GFXSCT_SamplerCubeArray: + case GFXSCT_SamplerTextureArray: + // Set sampler number on our program. + glUniform1i(handle->mDesc.bindPoint, handle->mDesc.samplerReg); + break; + case GFXSCT_Int: + glUniform1iv(handle->mDesc.bindPoint, handle->mDesc.arraySize, (GLint*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + case GFXSCT_Int2: + glUniform2iv(handle->mDesc.bindPoint, handle->mDesc.arraySize, (GLint*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + case GFXSCT_Int3: + glUniform3iv(handle->mDesc.bindPoint, handle->mDesc.arraySize, (GLint*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + case GFXSCT_Int4: + glUniform4iv(handle->mDesc.bindPoint, handle->mDesc.arraySize, (GLint*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + case GFXSCT_Float2x2: + glUniformMatrix2fv(handle->mDesc.bindPoint, handle->mDesc.arraySize, true, (GLfloat*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + case GFXSCT_Float3x3: + glUniformMatrix3fv(handle->mDesc.bindPoint, handle->mDesc.arraySize, true, (GLfloat*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + case GFXSCT_Float4x3: + // NOTE: To save a transpose here we could store the matrix transposed (i.e. column major) in the constant buffer. + // See _mesa_uniform_matrix in the mesa source for the correct transpose algorithm for a 4x3 matrix. + glUniformMatrix4x3fv(handle->mDesc.bindPoint, handle->mDesc.arraySize, true, (GLfloat*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + case GFXSCT_Float4x4: + glUniformMatrix4fv(handle->mDesc.bindPoint, handle->mDesc.arraySize, true, (GLfloat*)(mGlobalConstBuffer + handle->mDesc.offset)); + break; + default: + AssertFatal(0, ""); + break; } + } } GFXShaderConstBufferRef GFXGLShader::allocConstBuffer() { - GFXGLShaderConstBuffer* buffer = new GFXGLShaderConstBuffer(this, mConstBufferSize, mConstBuffer); + GFXGLShaderConstBuffer* buffer = new GFXGLShaderConstBuffer(this); + for (BufferMap::Iterator i = mBuffers.begin(); i != mBuffers.end(); ++i) + { + // add our buffer descriptions to the full const buffer. + buffer->addBuffer(i->value); + } + buffer->registerResourceWithDevice(getOwningDevice()); - mActiveBuffers.push_back( buffer ); + mActiveBuffers.push_back(buffer); return buffer; } @@ -900,10 +1174,9 @@ void GFXGLShader::useProgram() void GFXGLShader::zombify() { clearShaders(); - dMemset(mConstBuffer, 0, mConstBufferSize); } -char* GFXGLShader::_handleIncludes( const Torque::Path& path, FileStream *s ) +char* GFXGLShader::_handleIncludes(const Torque::Path& path, FileStream* s) { // TODO: The #line pragma on GLSL takes something called a // "source-string-number" which it then never explains. @@ -918,20 +1191,20 @@ char* GFXGLShader::_handleIncludes( const Torque::Path& path, FileStream *s ) //dStrncpy( buffer, linePragma.c_str(), linePragmaLen ); s->read(shaderLen, buffer); buffer[shaderLen] = 0; - + char* p = dStrstr(buffer, "#include"); - while(p) + while (p) { char* q = p; p += 8; - if(dIsspace(*p)) + if (dIsspace(*p)) { U32 n = 0; - while(dIsspace(*p)) ++p; + while (dIsspace(*p)) ++p; AssertFatal(*p == '"', "Bad #include directive"); ++p; static char includeFile[256]; - while(*p != '"') + while (*p != '"') { AssertFatal(*p != 0, "Bad #include directive"); includeFile[n++] = *p++; @@ -943,22 +1216,22 @@ char* GFXGLShader::_handleIncludes( const Torque::Path& path, FileStream *s ) // First try it as a local file. Torque::Path includePath = Torque::Path::Join(path.getPath(), '/', includeFile); includePath = Torque::Path::CompressPath(includePath); - + FileStream includeStream; - if ( !includeStream.open( includePath, Torque::FS::File::Read ) ) + if (!includeStream.open(includePath, Torque::FS::File::Read)) { - // Try again assuming the path is absolute + // Try again assuming the path is absolute // and/or relative. - includePath = String( includeFile ); + includePath = String(includeFile); includePath = Torque::Path::CompressPath(includePath); - if ( !includeStream.open( includePath, Torque::FS::File::Read ) ) + if (!includeStream.open(includePath, Torque::FS::File::Read)) { AssertISV(false, avar("failed to open include '%s'.", includePath.getFullPath().c_str())); - if ( smLogErrors ) - Con::errorf( "GFXGLShader::_handleIncludes - Failed to open include '%s'.", - includePath.getFullPath().c_str() ); + if (smLogErrors) + Con::errorf("GFXGLShader::_handleIncludes - Failed to open include '%s'.", + includePath.getFullPath().c_str()); // Fail... don't return the buffer. dFree(buffer); @@ -967,17 +1240,17 @@ char* GFXGLShader::_handleIncludes( const Torque::Path& path, FileStream *s ) } char* includedText = _handleIncludes(includePath, &includeStream); - + // If a sub-include fails... cleanup and return. - if ( !includedText ) + if (!includedText) { dFree(buffer); return NULL; } - + // TODO: Disabled till this is fixed correctly. // - // Count the number of lines in the file + // Count the number of lines in the file // before the include. /* U32 includeLine = 0; @@ -993,7 +1266,7 @@ char* GFXGLShader::_handleIncludes( const Torque::Path& path, FileStream *s ) */ String manip(buffer); - manip.erase(q-buffer, p-q); + manip.erase(q - buffer, p - q); String sItx(includedText); // TODO: Disabled till this is fixed correctly. @@ -1001,9 +1274,9 @@ char* GFXGLShader::_handleIncludes( const Torque::Path& path, FileStream *s ) // Add a new line pragma to restore the proper // file and line number after the include. //sItx += String::ToString( "\r\n#line %d \r\n", includeLine ); - + dFree(includedText); - manip.insert(q-buffer, sItx); + manip.insert(q - buffer, sItx); char* manipBuf = dStrdup(manip.c_str()); p = manipBuf + (q - buffer); dFree(buffer); @@ -1011,22 +1284,22 @@ char* GFXGLShader::_handleIncludes( const Torque::Path& path, FileStream *s ) } p = dStrstr(p, "#include"); } - + return buffer; } -bool GFXGLShader::_loadShaderFromStream( GLuint shader, - const Torque::Path &path, - FileStream *s, - const Vector ¯os ) +bool GFXGLShader::_loadShaderFromStream(GLuint shader, + const Torque::Path& path, + FileStream* s, + const Vector& macros) { Vector buffers; Vector lengths; - + // The GLSL version declaration must go first! - const char *versionDecl = "#version 330\n"; - buffers.push_back( dStrdup( versionDecl ) ); - lengths.push_back( dStrlen( versionDecl ) ); + const char* versionDecl = "#version 330\n"; + buffers.push_back(dStrdup(versionDecl)); + lengths.push_back(dStrlen(versionDecl)); //Required extensions. These are already checked when creating the GFX adapter, if we make it this far it's supported const char* cubeArrayExt = "#extension GL_ARB_texture_cube_map_array : enable\n"; @@ -1042,73 +1315,94 @@ bool GFXGLShader::_loadShaderFromStream( GLuint shader, lengths.push_back(dStrlen(newLine)); // Now add all the macros. - for( U32 i = 0; i < macros.size(); i++ ) + for (U32 i = 0; i < macros.size(); i++) { - if(macros[i].name.isEmpty()) // TODO OPENGL + if (macros[i].name.isEmpty()) // TODO OPENGL continue; - String define = String::ToString( "#define %s %s\n", macros[i].name.c_str(), macros[i].value.c_str() ); - buffers.push_back( dStrdup( define.c_str() ) ); - lengths.push_back( define.length() ); + String define = String::ToString("#define %s %s\n", macros[i].name.c_str(), macros[i].value.c_str()); + buffers.push_back(dStrdup(define.c_str())); + lengths.push_back(define.length()); } - + // Now finally add the shader source. U32 shaderLen = s->getStreamSize(); - char *buffer = _handleIncludes(path, s); - if ( !buffer ) + char* buffer = _handleIncludes(path, s); + if (!buffer) return false; - + buffers.push_back(buffer); lengths.push_back(shaderLen); - + glShaderSource(shader, buffers.size(), (const GLchar**)const_cast(buffers.address()), NULL); #if defined(TORQUE_DEBUG) && defined(TORQUE_DEBUG_GFX) FileStream stream; - if ( !stream.open( path.getFullPath()+"_DEBUG", Torque::FS::File::Write ) ) + if (!stream.open(path.getFullPath() + "_DEBUG", Torque::FS::File::Write)) { AssertISV(false, avar("GFXGLShader::initShader - failed to write debug shader '%s'.", path.getFullPath().c_str())); } - for(int i = 0; i < buffers.size(); ++i) - stream.writeText(buffers[i]); + for (int i = 0; i < buffers.size(); ++i) + stream.writeText(buffers[i]); #endif // Cleanup the shader source buffer. - for ( U32 i=0; i < buffers.size(); i++ ) - dFree( buffers[i] ); + for (U32 i = 0; i < buffers.size(); i++) + dFree(buffers[i]); glCompileShader(shader); return true; } -bool GFXGLShader::initShader( const Torque::Path &file, - bool isVertex, - const Vector ¯os ) +bool GFXGLShader::initShader(const Torque::Path& file, + GFXShaderStage stage, + const Vector& macros) { PROFILE_SCOPE(GFXGLShader_CompileShader); - GLuint activeShader = glCreateShader(isVertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER); - if(isVertex) + + GLuint activeShader = 0; + + switch (stage) + { + case VERTEX_SHADER: + activeShader = glCreateShader(GL_VERTEX_SHADER); mVertexShader = activeShader; - else + break; + case PIXEL_SHADER: + activeShader = glCreateShader(GL_FRAGMENT_SHADER); mPixelShader = activeShader; + break; + case GEOMETRY_SHADER: + activeShader = glCreateShader(GL_GEOMETRY_SHADER); + mGeometryShader = activeShader; + break; + case DOMAIN_SHADER: + break; + case HULL_SHADER: + break; + case COMPUTE_SHADER: + break; + default: + break; + } + glAttachShader(mProgram, activeShader); - - + // Ok it's not in the shader gen manager, so ask Torque for it FileStream stream; - if ( !stream.open( file, Torque::FS::File::Read ) ) + if (!stream.open(file, Torque::FS::File::Read)) { AssertISV(false, avar("GFXGLShader::initShader - failed to open shader '%s'.", file.getFullPath().c_str())); - if ( smLogErrors ) - Con::errorf( "GFXGLShader::initShader - Failed to open shader file '%s'.", - file.getFullPath().c_str() ); + if (smLogErrors) + Con::errorf("GFXGLShader::initShader - Failed to open shader file '%s'.", + file.getFullPath().c_str()); return false; } - + if (!_loadShaderFromStream(activeShader, file, &stream, macros)) { if (smLogErrors) @@ -1121,23 +1415,23 @@ bool GFXGLShader::initShader( const Torque::Path &file, // Dump the info log to the console U32 logLength = 0; glGetShaderiv(activeShader, GL_INFO_LOG_LENGTH, (GLint*)&logLength); - - if ( logLength ) + + if (logLength) { FrameAllocatorMarker fam; char* log = (char*)fam.alloc(logLength); glGetShaderInfoLog(activeShader, logLength, NULL, log); - if (compile == GL_FALSE ) + if (compile == GL_FALSE) { - if ( smLogErrors ) + if (smLogErrors) { - Con::errorf( "GFXGLShader::initShader - Error compiling shader!" ); - Con::errorf( "Program %s: %s", file.getFullPath().c_str(), log ); + Con::errorf("GFXGLShader::initShader - Error compiling shader!"); + Con::errorf("Program %s: %s", file.getFullPath().c_str(), log); } } - else if ( smLogWarnings ) - Con::warnf( "Program %s: %s", file.getFullPath().c_str(), log ); + else if (smLogWarnings) + Con::warnf("Program %s: %s", file.getFullPath().c_str(), log); } return compile != GL_FALSE; @@ -1147,7 +1441,7 @@ bool GFXGLShader::initShader( const Torque::Path &file, const Vector& GFXGLShader::getShaderConstDesc() const { PROFILE_SCOPE(GFXGLShader_GetShaderConstants); - return mConstants; + return mShaderConsts; } /// Returns the alignment value for constType @@ -1163,6 +1457,6 @@ const String GFXGLShader::describeSelf() const ret = String::ToString(" Program: %i", mProgram); ret += String::ToString(" Vertex Path: %s", mVertexFile.getFullPath().c_str()); ret += String::ToString(" Pixel Path: %s", mPixelFile.getFullPath().c_str()); - + return ret; } diff --git a/Engine/source/gfx/gl/gfxGLShader.h b/Engine/source/gfx/gl/gfxGLShader.h index e3d3bb69c..1ca420b9e 100644 --- a/Engine/source/gfx/gl/gfxGLShader.h +++ b/Engine/source/gfx/gl/gfxGLShader.h @@ -29,15 +29,143 @@ #include "core/util/tSignal.h" #include "core/util/tDictionary.h" -class GFXGLShaderConstHandle; class FileStream; -class GFXGLShaderConstBuffer; class GFXGLDevice; +class GFXGLShader; + +struct BufferRange +{ + U32 mBufMin = U32_MAX; + U32 mBufMax = 0; + + inline void addSlot(U32 slot) + { + mBufMin = getMin(mBufMin, slot); + mBufMax = getMax(mBufMax, slot); + } + + inline bool isValid() const { return mBufMin <= mBufMax; } +}; + +struct ConstantBuffer +{ + GLuint bufHandle; + U8* data; + U32 size; + bool isDirty; +}; + +class GFXGLShaderConstHandle : public GFXShaderConstHandle +{ + friend class GFXGLShader; + +public: + // DX side needs the description map as the same uniform can exist across stages. for gl it is program wide. + GFXGLShaderConstHandle(GFXGLShader* shader); + GFXGLShaderConstHandle(GFXGLShader* shader, + const GFXShaderConstDesc& desc); + + void reinit(const GFXShaderConstDesc& desc); + + virtual ~GFXGLShaderConstHandle(); + const GFXShaderConstDesc getDesc(); + const String& getName() const { return mDesc.name; } + GFXShaderConstType getType() const { return mDesc.constType; } + U32 getArraySize() const { return mDesc.arraySize; } + + U32 getSize() const { return mDesc.size; } + void setValid(bool valid) { mValid = valid; } + /// @warning This will always return the value assigned when the shader was + /// initialized. If the value is later changed this method won't reflect that. + S32 getSamplerRegister() const { return (!isSampler() || !mValid) ? -1 : mDesc.samplerReg; } + + // Returns true if this is a handle to a sampler register. + bool isSampler() const + { + return (getType() >= GFXSCT_Sampler); + } + + /// Restore to uninitialized state. + void clear() + { + mShader = NULL; + mInstancingConstant = false; + mValid = false; + } + + GFXShaderConstDesc mDesc; + GFXGLShader* mShader; + bool mUBOUniform; + bool mInstancingConstant; +}; + +class GFXGLShaderConstBuffer : public GFXShaderConstBuffer +{ +public: + // -1 is the global buffer. + typedef Map BufferMap; + + GFXGLShaderConstBuffer(GFXGLShader* shader); + ~GFXGLShaderConstBuffer(); + + /// Called by GFXGLDevice to activate this buffer. + void activate(GFXGLShaderConstBuffer* prevShaderBuffer); + + void addBuffer(const GFXShaderConstDesc desc); + + /// Called when the shader this buffer references is reloaded. + void onShaderReload(GFXGLShader* shader); + + // GFXShaderConstBuffer + virtual GFXShader* getShader(); + virtual void set(GFXShaderConstHandle* handle, const F32 fv); + virtual void set(GFXShaderConstHandle* handle, const Point2F& fv); + virtual void set(GFXShaderConstHandle* handle, const Point3F& fv); + virtual void set(GFXShaderConstHandle* handle, const Point4F& fv); + virtual void set(GFXShaderConstHandle* handle, const PlaneF& fv); + virtual void set(GFXShaderConstHandle* handle, const LinearColorF& fv); + virtual void set(GFXShaderConstHandle* handle, const S32 f); + virtual void set(GFXShaderConstHandle* handle, const Point2I& fv); + virtual void set(GFXShaderConstHandle* handle, const Point3I& fv); + virtual void set(GFXShaderConstHandle* handle, const Point4I& fv); + virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); + virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); + virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); + virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); + virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); + virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); + virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); + virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); + virtual void set(GFXShaderConstHandle* handle, const MatrixF& mat, const GFXShaderConstType matType = GFXSCT_Float4x4); + virtual void set(GFXShaderConstHandle* handle, const MatrixF* mat, const U32 arraySize, const GFXShaderConstType matrixType = GFXSCT_Float4x4); + + // GFXResource + virtual const String describeSelf() const; + virtual void zombify() {} + virtual void resurrect() {} + +private: + + friend class GFXGLShader; + + WeakRefPtr mShader; + BufferMap mBufferMap; + + template + void internalSet(GFXShaderConstHandle* handle, const ConstType& param); + + template + void internalSet(GFXShaderConstHandle* handle, const AlignedArray& fv); +}; class GFXGLShader : public GFXShader { - typedef Map HandleMap; + friend class GFXGLShaderConstBuffer; + friend class GFXGLShaderConstHandle; public: + typedef Map HandleMap; + typedef Map BufferMap; + GFXGLShader(GFXGLDevice* device); virtual ~GFXGLShader(); @@ -50,111 +178,60 @@ public: virtual const Vector& getShaderConstDesc() const; /// Returns the alignment value for constType - virtual U32 getAlignmentValue(const GFXShaderConstType constType) const; + virtual U32 getAlignmentValue(const GFXShaderConstType constType) const; virtual GFXShaderConstBufferRef allocConstBuffer(); /// @} - + /// @name GFXResource interface /// @{ virtual void zombify(); virtual void resurrect() { reload(); } virtual const String describeSelf() const; - /// @} + /// @} /// Activates this shader in the GL context. void useProgram(); - + protected: + virtual bool _init(); - friend class GFXGLShaderConstBuffer; - friend class GFXGLShaderConstHandle; - - virtual bool _init(); - - bool initShader( const Torque::Path &file, - bool isVertex, - const Vector ¯os ); + bool initShader(const Torque::Path& file, + GFXShaderStage stage, + const Vector& macros); void clearShaders(); + void initConstantDescs(); void initHandles(); - void setConstantsFromBuffer(GFXGLShaderConstBuffer* buffer); - - static char* _handleIncludes( const Torque::Path &path, FileStream *s ); + void setConstantsFromBuffer(U8* buffer); - static bool _loadShaderFromStream( GLuint shader, - const Torque::Path& path, - FileStream* s, - const Vector& macros ); + static char* _handleIncludes(const Torque::Path& path, FileStream* s); + + static bool _loadShaderFromStream(GLuint shader, + const Torque::Path& path, + FileStream* s, + const Vector& macros); /// @name Internal GL handles /// @{ GLuint mVertexShader; GLuint mPixelShader; + GLuint mGeometryShader; GLuint mProgram; /// @} - - Vector mConstants; - U32 mConstBufferSize; - U8* mConstBuffer; + + U8* mGlobalConstBuffer; + + Vector mShaderConsts; + HandleMap mHandles; + BufferMap mBuffers; + GFXGLDevice* mDevice; - Vector mValidHandles; + + GFXShaderConstType convertConstType(GLenum constType); }; -class GFXGLShaderConstBuffer : public GFXShaderConstBuffer -{ -public: - GFXGLShaderConstBuffer(GFXGLShader* shader, U32 bufSize, U8* existingConstants); - ~GFXGLShaderConstBuffer(); - - /// Called by GFXGLDevice to activate this buffer. - void activate(); - - /// Called when the shader this buffer references is reloaded. - void onShaderReload( GFXGLShader *shader ); - - // GFXShaderConstBuffer - virtual GFXShader* getShader() { return mShader; } - virtual void set(GFXShaderConstHandle* handle, const F32 fv); - virtual void set(GFXShaderConstHandle* handle, const Point2F& fv); - virtual void set(GFXShaderConstHandle* handle, const Point3F& fv); - virtual void set(GFXShaderConstHandle* handle, const Point4F& fv); - virtual void set(GFXShaderConstHandle* handle, const PlaneF& fv); - virtual void set(GFXShaderConstHandle* handle, const LinearColorF& fv); - virtual void set(GFXShaderConstHandle* handle, const S32 f); - virtual void set(GFXShaderConstHandle* handle, const Point2I& fv); - virtual void set(GFXShaderConstHandle* handle, const Point3I& fv); - virtual void set(GFXShaderConstHandle* handle, const Point4I& fv); - virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); - virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); - virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); - virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); - virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); - virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); - virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); - virtual void set(GFXShaderConstHandle* handle, const AlignedArray& fv); - virtual void set(GFXShaderConstHandle* handle, const MatrixF& mat, const GFXShaderConstType matType = GFXSCT_Float4x4); - virtual void set(GFXShaderConstHandle* handle, const MatrixF* mat, const U32 arraySize, const GFXShaderConstType matrixType = GFXSCT_Float4x4); - - // GFXResource - virtual const String describeSelf() const; - virtual void zombify() {} - virtual void resurrect() {} - -private: - - friend class GFXGLShader; - U8* mBuffer; - WeakRefPtr mShader; - - template - void internalSet(GFXShaderConstHandle* handle, const ConstType& param); - - template - void internalSet(GFXShaderConstHandle* handle, const AlignedArray& fv); -}; - -#endif // _GFXGLSHADER_H_ \ No newline at end of file +#endif // _GFXGLSHADER_H_ diff --git a/Engine/source/gui/shaderEditor/guiShaderEditor.cpp b/Engine/source/gui/shaderEditor/guiShaderEditor.cpp new file mode 100644 index 000000000..7d0415296 --- /dev/null +++ b/Engine/source/gui/shaderEditor/guiShaderEditor.cpp @@ -0,0 +1,1003 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +#include "platform/platform.h" +#include "gui/shaderEditor/guiShaderEditor.h" +#include "gui/shaderEditor/nodes/materialOutputNode.h" +#include "gui/shaderEditor/nodes/mathNode.h" + +#include "core/frameAllocator.h" +#include "core/stream/fileStream.h" +#include "core/stream/memStream.h" +#include "console/consoleTypes.h" +#include "gui/core/guiCanvas.h" +#include "console/engineAPI.h" +#include "console/script.h" +#include "console/typeValidators.h" +#include "gfx/primBuilder.h" + +IMPLEMENT_CONOBJECT(GuiShaderEditor); + +ConsoleDocClass(GuiShaderEditor, + "@brief Implementation of a shader node editor.\n\n" + "Editor use only.\n\n" + "@internal" +); + +GuiShaderEditor::GuiShaderEditor() + : mDragBeginPoint(-1, -1), + mViewOffset(0,0), + mZoomScale(1.0f), + mFullBoxSelection(false), + mDragAddSelection(false), + mDragMoveUndo(false) +{ + VECTOR_SET_ASSOCIATION(mCurrNodes); + VECTOR_SET_ASSOCIATION(mSelectedNodes); + VECTOR_SET_ASSOCIATION(mDragBeginPoints); + VECTOR_SET_ASSOCIATION(mCurrConnections); + + mActive = true; + mMouseDownMode = GuiShaderEditor::Selecting; + + mTrash = NULL; + mTempConnection = NULL; + mNodeSize = 10; + // test + addNode(new BRDFOutputNode()); + addNode(new MathAddNode()); + addNode(new GuiShaderNode()); +} + +bool GuiShaderEditor::onWake() +{ + if (!Parent::onWake()) + return false; + + return true; +} + +void GuiShaderEditor::onSleep() +{ + Parent::onSleep(); +} + +// anything smaller than 4 is way too small.... +IRangeValidator nodeSizeRange(4, 30); + +void GuiShaderEditor::initPersistFields() +{ + docsURL; + addGroup("Node Settings"); + addFieldV("nodeSize", TypeS32, Offset(mNodeSize, GuiShaderEditor),&nodeSizeRange, + "Size of nodes."); + endGroup("Node Settings"); + + addGroup("Selection"); + addField("fullBoxSelection", TypeBool, Offset(mFullBoxSelection, GuiShaderEditor), + "If true, rectangle selection will only select controls fully inside the drag rectangle."); + endGroup("Selection"); + Parent::initPersistFields(); +} + +bool GuiShaderEditor::onAdd() +{ + if (!Parent::onAdd()) + return false; + + mTrash = new SimGroup(); + + if (!mTrash->registerObject()) + return false; + + + return true; +} + +void GuiShaderEditor::onRemove() +{ + Parent::onRemove(); + + mTrash->deleteObject(); + + mTrash = NULL; + + /* for (GuiShaderNode* node : mCurrNodes) + { + SAFE_DELETE(node); + }*/ + + for (GuiShaderNode* node : mSelectedNodes) + { + SAFE_DELETE(node); + } +} + +void GuiShaderEditor::onPreRender() +{ + setUpdate(); +} + +void GuiShaderEditor::renderNodes(Point2I offset, const RectI& updateRect) +{ + // Save the current clip rect + // so we can restore it at the end of this method. + RectI savedClipRect = GFX->getClipRect(); + + // offset is the upper-left corner of this control in screen coordinates + // updateRect is the intersection rectangle in screen coords of the control + // hierarchy. This can be set as the clip rectangle in most cases. + RectI clipRect = updateRect; + clipRect.inset(2, 2); + + GFXDrawUtil* drawer = GFX->getDrawUtil(); + + // render nodes in reverse order. + for (ShaderNodeVector::iterator i = mCurrNodes.end(); i-- != mCurrNodes.begin(); ) + { + GuiShaderNode* node = *i; + // this is useful for sub node graphs. + if (node->isVisible()) + { + Point2I childPos = offset + node->getPosition(); + RectI childClip(childPos, node->getExtent() ); + + if (selectionContains(node)) + { + node->mSelected = true; + } + else + { + node->mSelected = false; + } + + if (childClip.intersect(clipRect)) + { + GFX->setClipRect(childClip); + GFX->setStateBlock(mDefaultGuiSB); + node->renderNode(childPos, childClip, mNodeSize); + } + + GFX->setClipRect(clipRect); + GFX->setStateBlock(mDefaultGuiSB); + for (NodeInput* input : node->mInputNodes) + { + Point2I pos = node->localToGlobalCoord(input->pos) + offset; + + ColorI border = input->col; + + ColorI fill = mProfile->mFillColor; + if (hasConnection(input)) + { + fill = input->col; + } + + RectI socketRect(pos, Point2I(mNodeSize, mNodeSize)); + drawer->drawCircleFill(socketRect, fill, mNodeSize / 2, 1.0f, border); + } + + for (NodeOutput* output : node->mOutputNodes) + { + Point2I pos = node->localToGlobalCoord(output->pos) + offset; + + ColorI border = output->col; + + ColorI fill = mProfile->mFillColor; + if (hasConnection(output)) + { + fill = output->col; + } + + RectI socketRect(pos, Point2I(mNodeSize, mNodeSize)); + drawer->drawCircleFill(socketRect, fill, mNodeSize / 2, 1.0f, border); + } + } + } + + // Restore the clip rect to what it was at the start + // of this method. + GFX->setClipRect(savedClipRect); +} + +void GuiShaderEditor::renderConnections(Point2I offset, const RectI& updateRect) +{ + // Save the current clip rect + // so we can restore it at the end of this method. + RectI savedClipRect = GFX->getClipRect(); + + // offset is the upper-left corner of this control in screen coordinates + // updateRect is the intersection rectangle in screen coords of the control + // hierarchy. This can be set as the clip rectangle in most cases. + RectI clipRect = updateRect; + clipRect.inset(2, 2); + + GFXDrawUtil* drawer = GFX->getDrawUtil(); + + for (NodeConnection* conn : mCurrConnections) + { + // for temp connetion, nodeA is always the first node selected. + Point2I start(Point2I::Zero); + Point2I end(Point2I::Zero); + + start = conn->nodeA->localToGlobalCoord(conn->inSocket->pos) + offset; + end = conn->nodeB->localToGlobalCoord(conn->outSocket->pos) + offset; + + start += Point2I(mNodeSize / 2, mNodeSize / 2); + end += Point2I(mNodeSize / 2, mNodeSize / 2); + + drawer->drawThickLine(start, end,ColorI(255,255,255,255), 2.0f); + } + + // Restore the clip rect to what it was at the start + // of this method. + GFX->setClipRect(savedClipRect); +} + +void GuiShaderEditor::onRender(Point2I offset, const RectI& updateRect) +{ + offset += mViewOffset; + + GFXDrawUtil* drawer = GFX->getDrawUtil(); + + // render our nodes. + renderConnections(offset, updateRect); + renderNodes(offset, updateRect); + + if (mActive) + { + if (mMouseDownMode == DragConnection) + { + // something went wrong.... fix it fix it fix it. + if (mTempConnection == NULL) + return; + else + { + // for temp connetion, nodeA is always the first node selected. + Point2I start(Point2I::Zero); + ColorI color(ColorI::WHITE); + if (mTempConnection->inSocket != NULL) + { + start = mTempConnection->nodeA->localToGlobalCoord(mTempConnection->inSocket->pos) + offset; + color = mTempConnection->inSocket->col; + } + else if (mTempConnection->outSocket != NULL) + { + start = mTempConnection->nodeA->localToGlobalCoord(mTempConnection->outSocket->pos) + offset; + color = mTempConnection->outSocket->col; + } + + RectI sockActive(start, Point2I(mNodeSize, mNodeSize)); + start += Point2I(mNodeSize / 2, mNodeSize / 2); + + drawer->drawThickLine(start, mLastMousePos + offset, color, 2.0f); + + // draw socket overlay over the top of the line. + drawer->drawCircleFill(sockActive, color, mNodeSize / 2); + } + } + // Draw selection rectangle last so it is rendered on top. + if (mMouseDownMode == DragSelecting) + { + RectI b; + getDragRect(b); + b.point += offset; + + // Draw outline. + drawer->drawRect(b, ColorI(100, 100, 100, 128)); + + // Draw fill. + b.inset(1, 1); + drawer->drawRectFill(b, ColorI(150, 150, 150, 128)); + } + } +} + +bool GuiShaderEditor::onKeyDown(const GuiEvent& event) +{ + if (!mActive) + return Parent::onKeyDown(event); + + if (!(event.modifier & SI_PRIMARY_CTRL)) + { + switch (event.keyCode) + { + case KEY_BACKSPACE: + case KEY_DELETE: + deleteSelection(); + return true; + default: + break; + } + } + + return false; +} + +void GuiShaderEditor::onMouseDown(const GuiEvent& event) +{ + if (!mActive) + { + Parent::onMouseDown(event); + return; + } + + setFirstResponder(); + + // lock mouse + mouseLock(); + + // get mouse pos with our view offset and scale. + mLastMousePos = globalToLocalCoord(event.mousePoint) - mViewOffset; + + GuiShaderNode* hitNode = findHitNode(mLastMousePos); + + if(findHitSocket(mLastMousePos)) + { + // handled in hit socket. + return; + } + else + { + if (event.modifier & SI_SHIFT) + { + startDragRectangle(mLastMousePos); + mDragAddSelection = true; + } + else if (selectionContains(hitNode)) + { + if (event.modifier & SI_MULTISELECT) + { + removeSelection(hitNode); + setMouseMode(Selecting); + } + else if (event.modifier & SI_PRIMARY_ALT) + { + startDragClone(mLastMousePos); + } + else + { + startDragMove(mLastMousePos); + } + } + else + { + if (hitNode == NULL) + { + startDragRectangle(mLastMousePos); + mDragAddSelection = false; + } + else if (event.modifier & SI_PRIMARY_ALT && hitNode != NULL) + { + // Alt is down. Start a drag clone. + clearSelection(); + addSelection(hitNode); + startDragClone(mLastMousePos); + } + else if (event.modifier & SI_MULTISELECT) + { + addSelection(hitNode); + } + else + { + // Clicked on node. Start move. + clearSelection(); + addSelection(hitNode); + startDragMove(mLastMousePos); + } + } + } + +} + +void GuiShaderEditor::onMouseUp(const GuiEvent& event) +{ + if (!mActive) + { + Parent::onMouseUp(event); + return; + } + + //unlock the mouse + mouseUnlock(); + + // Reset Drag Axis Alignment Information + mDragBeginPoint.set(-1, -1); + mDragBeginPoints.clear(); + + // get mouse pos with our view offset and scale. + mLastMousePos = globalToLocalCoord(event.mousePoint) - mViewOffset; + + if (mMouseDownMode == DragConnection) + { + U32 ret = finishConnection(mLastMousePos); + + if (ret == 1) // we set the input on mouse up, nodeB is the inputSocket, swap order. + { + NodeConnection* conn = new NodeConnection(); + conn->nodeA = mTempConnection->nodeB; + conn->nodeB = mTempConnection->nodeA; + conn->inSocket = mTempConnection->inSocket; + conn->outSocket = mTempConnection->outSocket; + + mCurrConnections.push_back(conn); + } + + if (ret == 2) // we set the output on mouse up, nodeB is the outputSocket + { + NodeConnection* conn = new NodeConnection(); + conn->nodeA = mTempConnection->nodeA; + conn->nodeB = mTempConnection->nodeB; + conn->inSocket = mTempConnection->inSocket; + conn->outSocket = mTempConnection->outSocket; + + mCurrConnections.push_back(conn); + } + + mTempConnection = NULL; + } + + if (mMouseDownMode == DragSelecting) + { + if (!(event.modifier & SI_MULTISELECT) && !mDragAddSelection) + clearSelection(); + + RectI rect; + getDragRect(rect); + + if (rect.extent.x <= 2 && rect.extent.y <= 2) + { + addSelectionAtPoint(rect.point); + } + else + { + Vector< GuiShaderNode* > hits; + findNodesInRect(rect, hits); + + for (GuiShaderNode* node : hits) + { + addSelection(node); + } + } + } + + //reset the mouse mode + setFirstResponder(); + setMouseMode(Selecting); +} + +void GuiShaderEditor::onMouseDragged(const GuiEvent& event) +{ + if (!mActive) + { + Parent::onMouseDragged(event); + return; + } + + // get mouse pos with our view offset and scale. + Point2I mousePoint = globalToLocalCoord(event.mousePoint) - mViewOffset; + + if (mMouseDownMode == DragClone) + { + // If we haven't yet crossed the mouse delta to actually start the + // clone, check if we have now. + + S32 delta = mAbs((mousePoint - mDragBeginPoint).len()); + if (delta >= 4) + { + cloneSelection(); + mLastMousePos = mDragBeginPoint; + mDragMoveUndo = false; + + setMouseMode(MovingSelection); + } + } + + if (mMouseDownMode == MovingSelection && mSelectedNodes.size()) + { + Point2I delta = mousePoint - mLastMousePos; + RectI selBounds = getSelectionBounds(); + + if (delta.x || delta.y) + moveSelection(delta, mDragMoveUndo); + + mLastMousePos += delta; + } + else + mLastMousePos = mousePoint; +} + +void GuiShaderEditor::onMiddleMouseDown(const GuiEvent& event) +{ + if (!mActive) + { + Parent::onMiddleMouseDown(event); + return; + } + + setFirstResponder(); + + // lock mouse + mouseLock(); + + // get mouse pos with our view offset and scale. + mLastMousePos = globalToLocalCoord(event.mousePoint); + + setMouseMode(DragPanning); + getRoot()->showCursor(false); +} + +void GuiShaderEditor::onMiddleMouseUp(const GuiEvent& event) +{ + if (!mActive) + { + Parent::onMiddleMouseUp(event); + return; + } + + getRoot()->showCursor(true); + + //unlock the mouse + mouseUnlock(); + + // Reset Drag Axis Alignment Information + mDragBeginPoint.set(-1, -1); + mDragBeginPoints.clear(); + + // get mouse pos with our view offset and scale. + mLastMousePos = globalToLocalCoord(event.mousePoint); + + setFirstResponder(); + setMouseMode(Selecting); +} + +void GuiShaderEditor::onMiddleMouseDragged(const GuiEvent& event) +{ + if (!mActive) + { + Parent::onMiddleMouseDragged(event); + return; + } + + // get mouse pos with our view offset and scale. + Point2I mousePoint = globalToLocalCoord(event.mousePoint); + + if (mMouseDownMode == DragPanning) + { + Point2I delta = mousePoint - mLastMousePos; + // invert it + if (delta.x || delta.y) + mViewOffset += -delta; + + mLastMousePos += delta; + } + else + mLastMousePos = mousePoint; +} + +bool GuiShaderEditor::onMouseWheelUp(const GuiEvent& event) +{ + if (!mActive || !mAwake || !mVisible) + return Parent::onMouseWheelUp(event); + + mZoomScale *= 1.1f; + + return true; +} + +bool GuiShaderEditor::onMouseWheelDown(const GuiEvent& event) +{ + if (!mActive || !mAwake || !mVisible) + return Parent::onMouseWheelDown(event); + + mZoomScale *= 0.9f; + + return true; +} + +RectI GuiShaderEditor::getSelectionBounds() +{ + + Vector::const_iterator i = mSelectedNodes.begin(); + + Point2I minPos = (*i)->localToGlobalCoord(Point2I(0, 0)); + Point2I maxPos = minPos; + + for (; i != mSelectedNodes.end(); i++) + { + Point2I iPos = (**i).localToGlobalCoord(Point2I(0, 0)); + + minPos.x = getMin(iPos.x, minPos.x); + minPos.y = getMin(iPos.y, minPos.y); + + Point2I iExt = (**i).getExtent(); + + iPos.x += iExt.x; + iPos.y += iExt.y; + + maxPos.x = getMax(iPos.x, maxPos.x); + maxPos.y = getMax(iPos.y, maxPos.y); + } + + minPos = globalToLocalCoord(minPos); + maxPos = globalToLocalCoord(maxPos); + + return RectI(minPos.x, minPos.y, (maxPos.x - minPos.x), (maxPos.y - minPos.y)); +} + +void GuiShaderEditor::deleteSelection() +{ + for (GuiShaderNode* node : mSelectedNodes) + { + mTrash->addObject(node); + + Vector connVec; + for (NodeInput* input : node->mInputNodes) + { + hasConnection(input, connVec); + } + + for (NodeOutput* output : node->mOutputNodes) + { + hasConnection(output, connVec); + } + + for (NodeConnection* conn : connVec) + { + Vector< NodeConnection* >::iterator i = T3D::find(mCurrConnections.begin(), mCurrConnections.end(), conn); + if (i != mCurrConnections.end()) + { + mCurrConnections.erase(i); + } + } + + Vector< GuiShaderNode* >::iterator i = T3D::find(mCurrNodes.begin(), mCurrNodes.end(), node); + if (i != mCurrNodes.end()) + mCurrNodes.erase(i); + } + + clearSelection(); +} + +void GuiShaderEditor::moveSelection(const Point2I& delta, bool callback) +{ + for (GuiShaderNode* node : mSelectedNodes) + { + node->setPosition(node->getPosition() + delta); + } +} + +void GuiShaderEditor::clearSelection() +{ + mSelectedNodes.clear(); +} + +void GuiShaderEditor::cloneSelection() +{ + Vector newSelection; + + for (GuiShaderNode* node : mSelectedNodes) + { + GuiShaderNode* clone = dynamic_cast(node->deepClone()); + if (clone) + newSelection.push_back(clone); + } + + clearSelection(); + + for (GuiShaderNode* cloneNode : newSelection) + { + mCurrNodes.push_back(cloneNode); + addSelection(cloneNode); + } +} + +void GuiShaderEditor::addSelectionAtPoint(const Point2I& pos) +{ + // turn hit off on already selected nodes. + canHitSelectedNodes(false); + + GuiShaderNode* node = findHitNode(pos); + + // reset hit status. + canHitSelectedNodes(); + + if (node) + addSelection(node); +} + +void GuiShaderEditor::addSelection(GuiShaderNode* inNode) +{ + if (inNode != NULL && !selectionContains(inNode)) + { + mSelectedNodes.push_back(inNode); + } +} + +bool GuiShaderEditor::selectionContains(GuiShaderNode* inNode) +{ + for (GuiShaderNode* node : mSelectedNodes) + { + if (node == inNode) + return true; + } + + return false; +} + +void GuiShaderEditor::removeSelection(GuiShaderNode* inNode) +{ + if (selectionContains(inNode)) + { + Vector< GuiShaderNode* >::iterator i = T3D::find(mSelectedNodes.begin(), mSelectedNodes.end(), inNode); + if (i != mSelectedNodes.end()) + mSelectedNodes.erase(i); + } +} + +void GuiShaderEditor::canHitSelectedNodes(bool state) +{ + for (GuiShaderNode* node : mSelectedNodes) + node->setCanHit(state); +} + +//----------------------------------------------------------------------------- +// Input handling +//----------------------------------------------------------------------------- + +GuiShaderNode* GuiShaderEditor::findHitNode(const Point2I& pt) +{ + for (GuiShaderNode* node : mCurrNodes) + { + if (node->pointInControl(pt)) + { + // selecting one node, push it to the front of the mcurrnodes stack so its rendered on top. + Vector< GuiShaderNode* >::iterator i = T3D::find(mCurrNodes.begin(), mCurrNodes.end(), node); + if (i != mCurrNodes.end()) + { + mCurrNodes.erase(i); + mCurrNodes.insert(mCurrNodes.begin(), node); + } + + return node; + } + } + + return nullptr; +} + +bool GuiShaderEditor::findHitSocket(const Point2I& pt) +{ + Point2I parentOffset = localToGlobalCoord(getPosition()) + mViewOffset; + Point2I offsetPoint = pt + localToGlobalCoord(getPosition()); + + for (GuiShaderNode* node : mCurrNodes) + { + for (NodeInput* inNode : node->mInputNodes) + { + Point2I offSet = node->localToGlobalCoord(inNode->pos) + parentOffset; + RectI box(offSet.x, offSet.y, mNodeSize, mNodeSize); + + S32 xt = offsetPoint.x - box.point.x; + S32 yt = offsetPoint.y - box.point.y; + if (xt >= 0 && yt >= 0 && xt < box.extent.x && yt < box.extent.y) + { + mTempConnection = new NodeConnection(); + mTempConnection->nodeA = node; + mTempConnection->inSocket = inNode; + setMouseMode(DragConnection); + return true; + } + } + + for (NodeOutput* outNode : node->mOutputNodes) + { + Point2I offSet = node->localToGlobalCoord(outNode->pos) + parentOffset; + RectI box(offSet.x, offSet.y, mNodeSize, mNodeSize); + + S32 xt = offsetPoint.x - box.point.x; + S32 yt = offsetPoint.y - box.point.y; + if (xt >= 0 && yt >= 0 && xt < box.extent.x && yt < box.extent.y) + { + mTempConnection = new NodeConnection(); + mTempConnection->nodeA = node; + mTempConnection->outSocket = outNode; + setMouseMode(DragConnection); + return true; + } + } + } + return false; +} + +U32 GuiShaderEditor::finishConnection(const Point2I& pt) +{ + Point2I parentOffset = localToGlobalCoord(getPosition()) + mViewOffset; + Point2I offsetPoint = pt + localToGlobalCoord(getPosition()); + + for (GuiShaderNode* node : mCurrNodes) + { + for (NodeInput* inNode : node->mInputNodes) + { + Point2I offSet = node->localToGlobalCoord(inNode->pos) + parentOffset; + RectI box(offSet.x, offSet.y, mNodeSize, mNodeSize); + + S32 xt = offsetPoint.x - box.point.x; + S32 yt = offsetPoint.y - box.point.y; + if (xt >= 0 && yt >= 0 && xt < box.extent.x && yt < box.extent.y) + { + if (mTempConnection->nodeA == node || mTempConnection->inSocket != NULL) + return false; + + NodeConnection* conn; + if(hasConnection(inNode, conn)) + { + Vector< NodeConnection* >::iterator i = T3D::find(mCurrConnections.begin(), mCurrConnections.end(), conn); + if (i != mCurrConnections.end()) + { + mCurrConnections.erase(i); + } + } + + mTempConnection->nodeB = node; + mTempConnection->inSocket = inNode; + return 1; + } + } + + for (NodeOutput* outNode : node->mOutputNodes) + { + Point2I offSet = node->localToGlobalCoord(outNode->pos) + parentOffset; + RectI box(offSet.x, offSet.y, mNodeSize, mNodeSize); + + S32 xt = offsetPoint.x - box.point.x; + S32 yt = offsetPoint.y - box.point.y; + if (xt >= 0 && yt >= 0 && xt < box.extent.x && yt < box.extent.y) + { + if (mTempConnection->nodeA == node || mTempConnection->outSocket != NULL) + return false; + + NodeConnection* conn; + if (hasConnection(mTempConnection->inSocket, conn)) + { + Vector< NodeConnection* >::iterator i = T3D::find(mCurrConnections.begin(), mCurrConnections.end(), conn); + if (i != mCurrConnections.end()) + { + mCurrConnections.erase(i); + } + } + + mTempConnection->nodeB = node; + mTempConnection->outSocket = outNode; + return 2; + } + } + } + return 0; +} + +bool GuiShaderEditor::hasConnection(NodeSocket* inSocket) +{ + for (NodeConnection* con : mCurrConnections) + { + if (con->inSocket == dynamic_cast(inSocket) || con->outSocket == dynamic_cast(inSocket)) + { + return true; + } + } + + return false; +} + +bool GuiShaderEditor::hasConnection(NodeSocket* inSocket, Vector& conn) +{ + bool ret = false; + + for (NodeConnection* con : mCurrConnections) + { + if (con->inSocket == dynamic_cast(inSocket) || con->outSocket == dynamic_cast(inSocket)) + { + conn.push_back(con); + ret = true; + } + } + + return ret; +} + +bool GuiShaderEditor::hasConnection(NodeSocket* inSocket, NodeConnection*& conn) +{ + for (NodeConnection* con : mCurrConnections) + { + if (con->inSocket == dynamic_cast(inSocket) || con->outSocket == dynamic_cast(inSocket)) + { + if (conn != nullptr) + conn = con; + return true; + } + } + return false; +} + +void GuiShaderEditor::findNodesInRect(const RectI& rect, Vector& outResult) +{ + canHitSelectedNodes(false); + for (GuiShaderNode* node : mCurrNodes) + { + if (node->getBounds().overlaps(rect)) + { + outResult.push_back(node); + } + } + + canHitSelectedNodes(); +} + +void GuiShaderEditor::getDragRect(RectI& box) +{ + box.point.x = getMin(mLastMousePos.x, mSelectionAnchor.x); + box.extent.x = getMax(mLastMousePos.x, mSelectionAnchor.x) - box.point.x + 1; + box.point.y = getMin(mLastMousePos.y, mSelectionAnchor.y); + box.extent.y = getMax(mLastMousePos.y, mSelectionAnchor.y) - box.point.y + 1; +} + +void GuiShaderEditor::startDragMove(const Point2I& startPoint) +{ + mDragMoveUndo = true; + + mDragBeginPoint = startPoint; + + mDragBeginPoints.reserve(mSelectedNodes.size()); + + for (GuiShaderNode* node : mSelectedNodes) + { + mDragBeginPoints.push_back(node->getPosition()); + } + + setMouseMode(MovingSelection); + +} + +void GuiShaderEditor::startDragRectangle(const Point2I& startPoint) +{ + mSelectionAnchor = startPoint; + setMouseMode(DragSelecting); +} + +void GuiShaderEditor::startDragClone(const Point2I& startPoint) +{ + mDragBeginPoint = startPoint; + setMouseMode(DragClone); +} + +void GuiShaderEditor::setMouseMode(mouseModes mode) +{ + if (mMouseDownMode != mode) + { + mMouseDownMode = mode; + } +} + +void GuiShaderEditor::addNode(GuiShaderNode* newNode) +{ + mCurrNodes.push_back(newNode); +} + diff --git a/Engine/source/gui/shaderEditor/guiShaderEditor.h b/Engine/source/gui/shaderEditor/guiShaderEditor.h new file mode 100644 index 000000000..a853951a4 --- /dev/null +++ b/Engine/source/gui/shaderEditor/guiShaderEditor.h @@ -0,0 +1,147 @@ +//----------------------------------------------------------------------------- +// 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 _GUISHADEREDITOR_H_ +#define _GUISHADEREDITOR_H_ + +#ifndef _GUICONTROL_H_ +#include "gui/core/guiControl.h" +#endif +#ifndef _UNDO_H_ +#include "util/undo.h" +#endif +#ifndef _GFX_GFXDRAWER_H_ +#include "gfx/gfxDrawUtil.h" +#endif + +#ifndef _SHADERNODE_H_ +#include "gui/shaderEditor/guiShaderNode.h" +#endif // !_SHADERNODE_H_ + +struct NodeConnection +{ + // keep track of the nodes hit. + GuiShaderNode* nodeA = NULL; + GuiShaderNode* nodeB = NULL; + + // keep track of the sockets. + NodeInput* inSocket = NULL; + NodeOutput* outSocket = NULL; +}; + +class GuiShaderEditor : public GuiControl +{ +public: + + typedef GuiControl Parent; + + enum mouseModes { Selecting, MovingSelection, DragPanning, DragConnection, DragSelecting, DragClone }; + +protected: + + // list + typedef Vector ShaderNodeVector; + typedef Vector ShderNodeConnections; + // all nodes in this graph. + ShaderNodeVector mCurrNodes; + ShderNodeConnections mCurrConnections; + NodeConnection* mTempConnection; + // Undo + SimGroup* mTrash; + + // view controls + Point2I mViewOffset; + F32 mZoomScale; + // mouse interaction + mouseModes mMouseDownMode; + Point2I mLastMousePos; + Point2I mLastDragPos; + Point2I mSelectionAnchor; + Point2I mDragBeginPoint; + Vector mDragBeginPoints; + bool mDragAddSelection; + bool mDragMoveUndo; + bool mFullBoxSelection; + S32 mNodeSize; + ShaderNodeVector mSelectedNodes; + + void renderNodes(Point2I offset, const RectI& updateRect); + void renderConnections(Point2I offset, const RectI& updateRect); + + // functions for handling mouse events. + GuiShaderNode* findHitNode(const Point2I& pt); + bool findHitSocket(const Point2I& pt); + U32 finishConnection(const Point2I& pt); + bool hasConnection(NodeSocket* inSocket); + bool hasConnection(NodeSocket* inSocket, Vector& conn); + bool hasConnection(NodeSocket* inSocket, NodeConnection*& conn); + + void findNodesInRect(const RectI& rect, Vector& outResult); + + void getDragRect(RectI& box); + void startDragMove(const Point2I& startPoint); + void startDragRectangle(const Point2I& startPoint); + void startDragClone(const Point2I& startPoint); + void setMouseMode(mouseModes mode); + void addNode(GuiShaderNode* newNode); + +public: + GuiShaderEditor(); + + DECLARE_CONOBJECT(GuiShaderEditor); + DECLARE_CATEGORY("Shader Editor"); + DECLARE_DESCRIPTION("Implements a shader node based editor."); + + bool onWake(); + void onSleep(); + static void initPersistFields(); + virtual bool onAdd() override; + virtual void onRemove() override; + + virtual void onPreRender() override; + void drawThickLine(const Point2I& pt1, const Point2I& pt2, U32 thickness = 2, ColorI col1 = ColorI(255, 255, 255), ColorI col2 = ColorI(255, 255, 255)); + virtual void onRender(Point2I offset, const RectI& updateRect) override; + + // interaction + virtual bool onKeyDown(const GuiEvent& event) override; + virtual void onMouseDown(const GuiEvent& event) override; + virtual void onMouseUp(const GuiEvent& event) override; + virtual void onMouseDragged(const GuiEvent& event) override; + virtual void onMiddleMouseDown(const GuiEvent& event) override; + virtual void onMiddleMouseUp(const GuiEvent& event) override; + virtual void onMiddleMouseDragged(const GuiEvent& event) override; + virtual bool onMouseWheelUp(const GuiEvent& event) override; + virtual bool onMouseWheelDown(const GuiEvent& event) override; + + RectI getSelectionBounds(); + void deleteSelection(); + void moveSelection(const Point2I& delta, bool callback = true); + void clearSelection(); + void cloneSelection(); + void addSelectionAtPoint(const Point2I& pos); + void addSelection(GuiShaderNode* inNode); + bool selectionContains(GuiShaderNode* inNode); + void removeSelection(GuiShaderNode* inNode); + void canHitSelectedNodes(bool state = true); +}; + +#endif _GUISHADEREDITOR_H_ diff --git a/Engine/source/gui/shaderEditor/guiShaderNode.cpp b/Engine/source/gui/shaderEditor/guiShaderNode.cpp new file mode 100644 index 000000000..65dea429d --- /dev/null +++ b/Engine/source/gui/shaderEditor/guiShaderNode.cpp @@ -0,0 +1,203 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +#include "platform/platform.h" +#include "gui/shaderEditor/guiShaderNode.h" + +#include "gui/core/guiCanvas.h" + +IMPLEMENT_CONOBJECT(GuiShaderNode); + +ConsoleDocClass(GuiShaderNode, + "@brief Base class for all nodes to derive from.\n\n" + "Editor use only.\n\n" + "@internal" +); + + +GuiShaderNode::GuiShaderNode() +{ + VECTOR_SET_ASSOCIATION(mInputNodes); + VECTOR_SET_ASSOCIATION(mOutputNodes); + + mTitle = "Default Node"; + mSelected = false; + mNodeType = NodeTypes::Default; + + + GuiControlProfile* profile = NULL; + if (Sim::findObject("GuiShaderEditorProfile", profile)) + setControlProfile(profile); + + // fixed extent for all nodes, only height should be changed + setExtent(180, 35); + + mPrevNodeSize = -1; +} + +bool GuiShaderNode::onWake() +{ + if (!Parent::onWake()) + return false; + + return true; +} + +void GuiShaderNode::onSleep() +{ + Parent::onSleep(); +} + +void GuiShaderNode::initPersistFields() +{ + docsURL; + Parent::initPersistFields(); +} + +bool GuiShaderNode::onAdd() +{ + if (!Parent::onAdd()) + return false; + + return true; +} + +void GuiShaderNode::onRemove() +{ + Parent::onRemove(); +} + +void GuiShaderNode::renderNode(Point2I offset, const RectI& updateRect, const S32 nodeSize) +{ + if (!mProfile) + return Parent::onRender(offset, updateRect); + + GFXDrawUtil* drawer = GFX->getDrawUtil(); + + // draw background. + // Get our rect. + RectI winRect; + winRect.point = offset; + winRect.extent = getExtent(); + + ColorI border = mProfile->mBorderColor; + + if (mSelected) + border = mProfile->mBorderColorSEL; + + drawer->drawRoundedRect(15.0f, winRect, mProfile->mFillColor, 5.0f, border); + + // draw header + ColorI header(50, 50, 50, 128); + + switch (mNodeType) + { + case NodeTypes::Default: + header = ColorI(128, 50, 128, 128); + break; + case NodeTypes::Uniform: + header = ColorI(50, 100, 128, 128); + break; + case NodeTypes::Input: + header = ColorI(128, 100, 50, 128); + break; + case NodeTypes::Output: + header = ColorI(50, 100, 50, 128); + break; + case NodeTypes::TextureSampler: + header = ColorI(50, 50, 128, 128); + break; + case NodeTypes::MathOperation: + header = ColorI(128, 0, 128, 128); + break; + case NodeTypes::Procedural: + header = ColorI(128, 100, 0, 128); + break; + case NodeTypes::Generator: + header = ColorI(0, 100, 128, 128); + break; + default: + header = ColorI(128, 0, 0, 128); + break; + } + + RectI headRect; + U32 headerSize = 30; + headRect.point = offset; + headRect.extent = Point2I(getExtent().x, headerSize); + drawer->drawRoundedRect(15.0f, headRect, header); + + // draw header text. + U32 strWidth = mProfile->mFont->getStrWidth(mTitle.c_str()); + Point2I headerPos = Point2I((getExtent().x / 2) - (strWidth / 2), (headerSize / 2) - (mProfile->mFont->getFontSize() / 2)); + drawer->setBitmapModulation(mProfile->mFontColor); + drawer->drawText(mProfile->mFont, headerPos + offset, mTitle); + drawer->clearBitmapModulation(); + + if (mInputNodes.size() > 0 || mOutputNodes.size() > 0) + { + U32 textPadX = nodeSize, textPadY = mProfile->mFont->getFontSize() + (nodeSize / 2); + Point2I slotPos(textPadX, headerSize + (nodeSize / 2)); + drawer->setBitmapModulation(mProfile->mFontColor); + for (NodeInput* input : mInputNodes) + { + drawer->drawText(mProfile->mFont, slotPos + offset, input->name); + + if (input->pos == Point2I::Zero || mPrevNodeSize != nodeSize) + input->pos = Point2I(-(nodeSize / 2) + 1, slotPos.y + ((mProfile->mFont->getFontSize() / 2) - (nodeSize / 2))); + + slotPos.y += textPadY; + } + + U32 inputY = slotPos.y; + + slotPos = Point2I(getExtent().x, headerSize + (nodeSize / 2)); + for (NodeOutput* output : mOutputNodes) + { + strWidth = mProfile->mFont->getStrWidth(output->name.c_str()); + slotPos.x = getExtent().x - strWidth - textPadX; + + drawer->drawText(mProfile->mFont, slotPos + offset, output->name); + + if (output->pos == Point2I::Zero || mPrevNodeSize != nodeSize) + output->pos = Point2I(getExtent().x - (nodeSize / 2) - 1 , slotPos.y + ((mProfile->mFont->getFontSize() / 2) - (nodeSize / 2))); + + slotPos.y += textPadY; + } + drawer->clearBitmapModulation(); + + U32 outputY = slotPos.y; + + if (getExtent().y < slotPos.y || mPrevNodeSize != nodeSize) + setExtent(Point2I(getExtent().x, mMax(inputY, outputY))); + + mPrevNodeSize = nodeSize; + } +} + +void GuiShaderNode::write(Stream& stream, U32 tabStop, U32 flags) +{ +} + +void GuiShaderNode::read(Stream& stream) +{ +} diff --git a/Engine/source/gui/shaderEditor/guiShaderNode.h b/Engine/source/gui/shaderEditor/guiShaderNode.h new file mode 100644 index 000000000..0ab409ca9 --- /dev/null +++ b/Engine/source/gui/shaderEditor/guiShaderNode.h @@ -0,0 +1,159 @@ +//----------------------------------------------------------------------------- +// 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 _SHADERNODE_H_ +#define _SHADERNODE_H_ + +#ifndef _GUICONTROL_H_ +#include "gui/core/guiControl.h" +#endif + +#ifndef _SIMBASE_H_ +#include "console/simBase.h" +#endif + +#ifndef _GFX_GFXDRAWER_H_ +#include "gfx/gfxDrawUtil.h" +#endif + + +enum class NodeTypes +{ + Default, + Uniform, + Input, + Output, + TextureSampler, + MathOperation, + Procedural, + Generator +}; + +enum class DataDimensions +{ + Dynamic, // can be any dimension, usually defined by what was connected to it. + Scalar, + Vector2, + Vector3, + Vector4, + Mat4x4, +}; + +// parent class for sockets detection in shaderEditor. +struct NodeSocket +{ + String name; + DataDimensions dimensions; + ColorI col = ColorI::WHITE; + NodeSocket() + :name(String::EmptyString), dimensions(DataDimensions::Dynamic) + {} + NodeSocket(String inName, DataDimensions inDim) + :name(inName), dimensions(inDim) + { + switch (inDim) + { + case DataDimensions::Dynamic: + col = ColorI(200, 200, 200, 128); + break; + case DataDimensions::Scalar: + col = ColorI(210, 105, 30, 128); + break; + case DataDimensions::Vector2: + col = ColorI(152, 251,152, 128); + break; + case DataDimensions::Vector3: + col = ColorI(127, 255, 212, 128); + break; + case DataDimensions::Vector4: + col = ColorI(100, 149, 237, 128); + break; + case DataDimensions::Mat4x4: + col = ColorI(153, 50, 204, 128); + break; + default: + break; + } + } + +public: + virtual ~NodeSocket() {} +}; + +struct NodeInput : NodeSocket +{ + Point2I pos = Point2I::Zero; + + NodeInput() + :NodeSocket() + {} + NodeInput(String inName , DataDimensions inDim) + :NodeSocket(inName , inDim) + {} +}; + +struct NodeOutput : NodeSocket +{ + Point2I pos = Point2I::Zero; + + NodeOutput() + :NodeSocket() + {} + NodeOutput(String inName, DataDimensions inDim) + :NodeSocket(inName, inDim) + {} +}; + +class GuiShaderNode : public GuiControl +{ +private: + typedef GuiControl Parent; + +protected: + String mTitle; + NodeTypes mNodeType; + S32 mPrevNodeSize; +public: + Vector mInputNodes; + Vector mOutputNodes; + + GuiShaderNode(); + + bool onWake(); + void onSleep(); + static void initPersistFields(); + virtual bool onAdd() override; + virtual void onRemove() override; + + void renderNode(Point2I offset, const RectI& updateRect, const S32 nodeSize); + // Serialization functions + void write(Stream& stream, U32 tabStop = 0, U32 flags = 0); + void read(Stream& stream); + + // is the parent that all other nodes are derived from. + DECLARE_CONOBJECT(GuiShaderNode); + DECLARE_CATEGORY("Shader Core"); + DECLARE_DESCRIPTION("Base class for all shader nodes."); + + bool mSelected; +}; +#endif // !_SHADERNODE_H_ diff --git a/Engine/source/gui/shaderEditor/nodes/materialOutputNode.cpp b/Engine/source/gui/shaderEditor/nodes/materialOutputNode.cpp new file mode 100644 index 000000000..a0b4d10c2 --- /dev/null +++ b/Engine/source/gui/shaderEditor/nodes/materialOutputNode.cpp @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +#include "platform/platform.h" +#include "gui/shaderEditor/nodes/materialOutputNode.h" + +//----------------------------------------------------------------- +// BRDF Output Node. +//----------------------------------------------------------------- + +IMPLEMENT_CONOBJECT(BRDFOutputNode); + +ConsoleDocClass(BRDFOutputNode, + "@brief Deferred Material output.\n\n" + "Editor use only.\n\n" + "@internal" +); + +BRDFOutputNode::BRDFOutputNode() + : GuiShaderNode() +{ + mNodeType = NodeTypes::Output; + + mInputNodes.push_back(new NodeInput("Albedo", DataDimensions::Vector3)); + mInputNodes.push_back(new NodeInput("Normal", DataDimensions::Vector3)); + mInputNodes.push_back(new NodeInput("Ambient Occlusion", DataDimensions::Scalar)); + mInputNodes.push_back(new NodeInput("Metallic", DataDimensions::Scalar)); + mInputNodes.push_back(new NodeInput("Roughness", DataDimensions::Scalar)); + mInputNodes.push_back(new NodeInput("Emissive Color", DataDimensions::Vector3)); + mInputNodes.push_back(new NodeInput("Opacity", DataDimensions::Scalar)); + + mTitle = "Standard BRDF"; +} diff --git a/Engine/source/gui/shaderEditor/nodes/materialOutputNode.h b/Engine/source/gui/shaderEditor/nodes/materialOutputNode.h new file mode 100644 index 000000000..023fb869e --- /dev/null +++ b/Engine/source/gui/shaderEditor/nodes/materialOutputNode.h @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +#include "gui/shaderEditor/guiShaderNode.h" + +//----------------------------------------------------------------- +// Put all material output nodes here. +//----------------------------------------------------------------- + +class BRDFOutputNode : public GuiShaderNode +{ + typedef GuiShaderNode Parent; +public: + BRDFOutputNode(); + + // is the parent that all other nodes are derived from. + DECLARE_CONOBJECT(BRDFOutputNode); + DECLARE_CATEGORY("Shader Output"); + DECLARE_DESCRIPTION("Deferred Material output."); +}; diff --git a/Engine/source/gui/shaderEditor/nodes/mathNode.cpp b/Engine/source/gui/shaderEditor/nodes/mathNode.cpp new file mode 100644 index 000000000..ed6905339 --- /dev/null +++ b/Engine/source/gui/shaderEditor/nodes/mathNode.cpp @@ -0,0 +1,49 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +#include "platform/platform.h" + +#include "gui/shaderEditor/nodes/mathNode.h" + +//----------------------------------------------------------------- +// Math addition Node. +//----------------------------------------------------------------- + +IMPLEMENT_CONOBJECT(MathAddNode); + +ConsoleDocClass(MathAddNode, + "@brief Math addition node.\n\n" + "Editor use only.\n\n" + "@internal" +); + +MathAddNode::MathAddNode() + : GuiShaderNode() +{ + mNodeType = NodeTypes::MathOperation; + + mInputNodes.push_back(new NodeInput("A", DataDimensions::Dynamic)); + mInputNodes.push_back(new NodeInput("B", DataDimensions::Dynamic)); + + mOutputNodes.push_back(new NodeOutput("Result", DataDimensions::Dynamic)); + + mTitle = "Math Node"; +} diff --git a/Engine/source/gui/shaderEditor/nodes/mathNode.h b/Engine/source/gui/shaderEditor/nodes/mathNode.h new file mode 100644 index 000000000..92a177aba --- /dev/null +++ b/Engine/source/gui/shaderEditor/nodes/mathNode.h @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +#include "gui/shaderEditor/guiShaderNode.h" + +//----------------------------------------------------------------- +// Put all Math nodes here. +//----------------------------------------------------------------- + +class MathAddNode : public GuiShaderNode +{ + typedef GuiShaderNode Parent; +public: + MathAddNode(); + + // is the parent that all other nodes are derived from. + DECLARE_CONOBJECT(MathAddNode); + DECLARE_CATEGORY("Shader Math"); + DECLARE_DESCRIPTION("Math addition node."); +}; diff --git a/Engine/source/materials/processedCustomMaterial.cpp b/Engine/source/materials/processedCustomMaterial.cpp index 1610d7ec9..abca21dd9 100644 --- a/Engine/source/materials/processedCustomMaterial.cpp +++ b/Engine/source/materials/processedCustomMaterial.cpp @@ -35,7 +35,6 @@ #include "materials/materialParameters.h" #include "gfx/sim/gfxStateBlockData.h" #include "core/util/safeDelete.h" -#include "gfx/genericConstBuffer.h" #include "console/simFieldDictionary.h" #include "console/propertyParsing.h" #include "gfx/util/screenspace.h" diff --git a/Engine/source/materials/processedShaderMaterial.cpp b/Engine/source/materials/processedShaderMaterial.cpp index dfba63533..83f58e1d9 100644 --- a/Engine/source/materials/processedShaderMaterial.cpp +++ b/Engine/source/materials/processedShaderMaterial.cpp @@ -26,7 +26,6 @@ #include "core/util/safeDelete.h" #include "gfx/sim/cubemapData.h" #include "gfx/gfxShader.h" -#include "gfx/genericConstBuffer.h" #include "gfx/gfxPrimitiveBuffer.h" #include "scene/sceneRenderState.h" #include "shaderGen/shaderFeature.h" diff --git a/Engine/source/materials/shaderData.cpp b/Engine/source/materials/shaderData.cpp index 8d8e8d103..34eab775d 100644 --- a/Engine/source/materials/shaderData.cpp +++ b/Engine/source/materials/shaderData.cpp @@ -48,10 +48,12 @@ ConsoleDocClass( ShaderData, "// Used for the procedural clould system\n" "singleton ShaderData( CloudLayerShader )\n" "{\n" - " DXVertexShaderFile = $Core::CommonShaderPath @ \"/cloudLayerV.hlsl\";\n" - " DXPixelShaderFile = $Core::CommonShaderPath @ \"/cloudLayerP.hlsl\";\n" - " OGLVertexShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerV.glsl\";\n" - " OGLPixelShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerP.glsl\";\n" + " DXVertexShaderFile = $Core::CommonShaderPath @ \"/cloudLayerV.hlsl\";\n" + " DXPixelShaderFile = $Core::CommonShaderPath @ \"/cloudLayerP.hlsl\";\n" + " DXGeometryShaderFile = $Core::CommonShaderPath @ \"/cloudLayerG.hlsl\";\n" + " OGLVertexShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerV.glsl\";\n" + " OGLPixelShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerP.glsl\";\n" + " OGLGeometryShaderFile = $Core::CommonShaderPath @ \"/gl/cloudLayerG.glsl\";\n" " pixVersion = 2.0;\n" "};\n" "@endtsexample\n\n" @@ -67,70 +69,87 @@ ShaderData::ShaderData() for( int i = 0; i < NumTextures; ++i) mRTParams[i] = false; + + mDXVertexShaderName = StringTable->EmptyString(); + mDXPixelShaderName = StringTable->EmptyString(); + mDXGeometryShaderName = StringTable->EmptyString(); + + mOGLVertexShaderName = StringTable->EmptyString(); + mOGLPixelShaderName = StringTable->EmptyString(); + mOGLGeometryShaderName = StringTable->EmptyString(); } void ShaderData::initPersistFields() { docsURL; - addField("DXVertexShaderFile", TypeStringFilename, Offset(mDXVertexShaderName, ShaderData), - "@brief %Path to the DirectX vertex shader file to use for this ShaderData.\n\n" - "It must contain only one program and no pixel shader, just the vertex shader." - "It can be either an HLSL or assembly level shader. HLSL's must have a " - "filename extension of .hlsl, otherwise its assumed to be an assembly file."); + addField("DXVertexShaderFile", TypeStringFilename, Offset(mDXVertexShaderName, ShaderData), + "@brief %Path to the DirectX vertex shader file to use for this ShaderData.\n\n" + "It must contain only one program and no pixel shader, just the vertex shader." + "It can be either an HLSL or assembly level shader. HLSL's must have a " + "filename extension of .hlsl, otherwise its assumed to be an assembly file."); - addField("DXPixelShaderFile", TypeStringFilename, Offset(mDXPixelShaderName, ShaderData), - "@brief %Path to the DirectX pixel shader file to use for this ShaderData.\n\n" - "It must contain only one program and no vertex shader, just the pixel " - "shader. It can be either an HLSL or assembly level shader. HLSL's " - "must have a filename extension of .hlsl, otherwise its assumed to be an assembly file."); + addField("DXPixelShaderFile", TypeStringFilename, Offset(mDXPixelShaderName, ShaderData), + "@brief %Path to the DirectX pixel shader file to use for this ShaderData.\n\n" + "It must contain only one program and no vertex shader, just the pixel " + "shader. It can be either an HLSL or assembly level shader. HLSL's " + "must have a filename extension of .hlsl, otherwise its assumed to be an assembly file."); - addField("OGLVertexShaderFile", TypeStringFilename, Offset(mOGLVertexShaderName, ShaderData), - "@brief %Path to an OpenGL vertex shader file to use for this ShaderData.\n\n" - "It must contain only one program and no pixel shader, just the vertex shader."); + addField("DXGeometryShaderFile", TypeStringFilename, Offset(mDXGeometryShaderName, ShaderData), + "@brief %Path to the DirectX geometry shader file to use for this ShaderData.\n\n" + "It can be either an HLSL or assembly level shader. HLSL's must have a " + "filename extension of .hlsl, otherwise its assumed to be an assembly file."); - addField("OGLPixelShaderFile", TypeStringFilename, Offset(mOGLPixelShaderName, ShaderData), - "@brief %Path to an OpenGL pixel shader file to use for this ShaderData.\n\n" - "It must contain only one program and no vertex shader, just the pixel " - "shader."); + addField("OGLVertexShaderFile", TypeStringFilename, Offset(mOGLVertexShaderName, ShaderData), + "@brief %Path to an OpenGL vertex shader file to use for this ShaderData.\n\n" + "It must contain only one program and no pixel shader, just the vertex shader."); - addField("useDevicePixVersion", TypeBool, Offset(mUseDevicePixVersion, ShaderData), - "@brief If true, the maximum pixel shader version offered by the graphics card will be used.\n\n" - "Otherwise, the script-defined pixel shader version will be used.\n\n"); + addField("OGLPixelShaderFile", TypeStringFilename, Offset(mOGLPixelShaderName, ShaderData), + "@brief %Path to an OpenGL pixel shader file to use for this ShaderData.\n\n" + "It must contain only one program and no vertex shader, just the pixel " + "shader."); - addField("pixVersion", TypeF32, Offset(mPixVersion, ShaderData), - "@brief Indicates target level the shader should be compiled.\n\n" - "Valid numbers at the time of this writing are 1.1, 1.4, 2.0, and 3.0. " - "The shader will not run properly if the hardware does not support the " - "level of shader compiled."); - - addField("defines", TypeRealString, Offset(mDefines, ShaderData), - "@brief String of case-sensitive defines passed to the shader compiler.\n\n" + addField("OGLGeometryShaderFile", TypeStringFilename, Offset(mOGLGeometryShaderName, ShaderData), + "@brief %Path to the OpenGL Geometry shader file to use for this ShaderData.\n\n"); + + addField("useDevicePixVersion", TypeBool, Offset(mUseDevicePixVersion, ShaderData), + "@brief If true, the maximum pixel shader version offered by the graphics card will be used.\n\n" + "Otherwise, the script-defined pixel shader version will be used.\n\n"); + + addField("pixVersion", TypeF32, Offset(mPixVersion, ShaderData), + "@brief Indicates target level the shader should be compiled.\n\n" + "Valid numbers at the time of this writing are 1.1, 1.4, 2.0, and 3.0. " + "The shader will not run properly if the hardware does not support the " + "level of shader compiled."); + + addField("defines", TypeRealString, Offset(mDefines, ShaderData), + "@brief String of case-sensitive defines passed to the shader compiler.\n\n" "The string should be delimited by a semicolon, tab, or newline character." - + "@tsexample\n" - "singleton ShaderData( FlashShader )\n" - "{\n" - "DXVertexShaderFile = $shaderGen::cachePath @ \"/postFx/flashV.hlsl\";\n" - "DXPixelShaderFile = $shaderGen::cachePath @ \"/postFx/flashP.hlsl\";\n\n" - " //Define setting the color of WHITE_COLOR.\n" - "defines = \"WHITE_COLOR=float4(1.0,1.0,1.0,0.0)\";\n\n" - "pixVersion = 2.0\n" - "}\n" + "singleton ShaderData( FlashShader )\n" + "{\n" + "DXVertexShaderFile = $shaderGen::cachePath @ \"/postFx/flashV.hlsl\";\n" + "DXPixelShaderFile = $shaderGen::cachePath @ \"/postFx/flashP.hlsl\";\n\n" + "DXGeometryShaderFile = $shaderGen::cachePath @ \"/postFx/flashG.hlsl\";\n\n" + " //Define setting the color of WHITE_COLOR.\n" + "defines = \"WHITE_COLOR=float4(1.0,1.0,1.0,0.0)\";\n\n" + "pixVersion = 2.0\n" + "}\n" "@endtsexample\n\n" - ); + ); - addField("samplerNames", TypeRealString, Offset(mSamplerNames, ShaderData), NumTextures, + addField("samplerNames", TypeRealString, Offset(mSamplerNames, ShaderData), NumTextures, "@brief Indicates names of samplers present in shader. Order is important.\n\n" - "Order of sampler names are used to assert correct sampler register/location" + "Order of sampler names are used to assert correct sampler register/location" "Other objects (GFXStateBlockData, PostEffect...) use index number to link samplers." - ); + ); - addField("rtParams", TypeBool, Offset(mRTParams, ShaderData), NumTextures, ""); + addField("rtParams", TypeBool, Offset(mRTParams, ShaderData), NumTextures, ""); Parent::initPersistFields(); // Make sure we get activation signals. - LightManager::smActivateSignal.notify( &ShaderData::_onLMActivate ); + LightManager::smActivateSignal.notify(&ShaderData::_onLMActivate); } bool ShaderData::onAdd() @@ -147,8 +166,8 @@ bool ShaderData::onAdd() for(int i = 0; i < NumTextures; ++i) { - if( mSamplerNames[i].isNotEmpty() && !mSamplerNames[i].startsWith("$") ) - mSamplerNames[i].insert(0, "$"); + if( mSamplerNames[i].isNotEmpty() && !mSamplerNames[i].startsWith("$") ) + mSamplerNames[i].insert(0, "$"); } return true; @@ -164,12 +183,12 @@ void ShaderData::onRemove() const Vector& ShaderData::_getMacros() { - // If they have already been processed then + // If they have already been processed then // return the cached result. if ( mShaderMacros.size() != 0 || mDefines.isEmpty() ) return mShaderMacros; - mShaderMacros.clear(); + mShaderMacros.clear(); GFXShaderMacro macro; const U32 defineCount = StringUnit::getUnitCount( mDefines, ";\n\t" ); for ( U32 i=0; i < defineCount; i++ ) @@ -195,7 +214,7 @@ GFXShader* ShaderData::getShader( const Vector ¯os ) // Convert the final macro list to a string. String cacheKey; - GFXShaderMacro::stringize( macros, &cacheKey ); + GFXShaderMacro::stringize( macros, &cacheKey ); // Lookup the shader for this instance. ShaderCache::Iterator iter = mShaders.find( cacheKey ); @@ -237,9 +256,13 @@ GFXShader* ShaderData::_createShader( const Vector ¯os ) { case Direct3D11: { - success = shader->init( mDXVertexShaderName, - mDXPixelShaderName, - pixver, + if (mDXVertexShaderName != String::EmptyString) + shader->setShaderStageFile(GFXShaderStage::VERTEX_SHADER, mDXVertexShaderName); + if (mDXPixelShaderName != String::EmptyString) + shader->setShaderStageFile(GFXShaderStage::PIXEL_SHADER, mDXPixelShaderName); + if (mDXGeometryShaderName != String::EmptyString) + shader->setShaderStageFile(GFXShaderStage::GEOMETRY_SHADER, mDXGeometryShaderName); + success = shader->init( pixver, macros, samplers); break; @@ -247,14 +270,19 @@ GFXShader* ShaderData::_createShader( const Vector ¯os ) case OpenGL: { - success = shader->init( mOGLVertexShaderName, - mOGLPixelShaderName, - pixver, + if(mOGLVertexShaderName != String::EmptyString) + shader->setShaderStageFile(GFXShaderStage::VERTEX_SHADER, mOGLVertexShaderName); + if (mOGLPixelShaderName != String::EmptyString) + shader->setShaderStageFile(GFXShaderStage::PIXEL_SHADER, mOGLPixelShaderName); + if (mOGLGeometryShaderName != String::EmptyString) + shader->setShaderStageFile(GFXShaderStage::GEOMETRY_SHADER, mOGLGeometryShaderName); + + success = shader->init( pixver, macros, samplers); break; } - + default: // Other device types are assumed to not support shaders. success = false; @@ -268,7 +296,7 @@ GFXShader* ShaderData::_createShader( const Vector ¯os ) { if(descs[i].constType != GFXSCT_Sampler && descs[i].constType != GFXSCT_SamplerCube) continue; - + GFXShaderConstHandle *handle = shader->findShaderConstHandle(descs[i].name); if(!handle || !handle->isValid()) continue; @@ -321,7 +349,7 @@ void ShaderData::_onLMActivate( const char *lm, bool activate ) bool ShaderData::hasSamplerDef(const String &_samplerName, int &pos) const { - String samplerName = _samplerName.startsWith("$") ? _samplerName : "$"+_samplerName; + String samplerName = _samplerName.startsWith("$") ? _samplerName : "$"+_samplerName; for(int i = 0; i < NumTextures; ++i) { if( mSamplerNames[i].equal(samplerName, String::NoCase ) ) @@ -342,9 +370,9 @@ bool ShaderData::_checkDefinition(GFXShader *shader) samplers.reserve(NumTextures); bool rtParams[NumTextures]; for(int i = 0; i < NumTextures; ++i) - rtParams[i] = false; + rtParams[i] = false; - const Vector &shaderConstDesc = shader->getShaderConstDesc(); + const Vector &shaderConstDesc = shader->getShaderConstDesc(); for(int i = 0; i < shaderConstDesc.size(); ++i) { @@ -352,7 +380,7 @@ bool ShaderData::_checkDefinition(GFXShader *shader) if(desc.constType == GFXSCT_Sampler) { samplers.push_back(desc.name ); - } + } } for(int i = 0; i < samplers.size(); ++i) @@ -361,14 +389,14 @@ bool ShaderData::_checkDefinition(GFXShader *shader) bool find = hasSamplerDef(samplers[i], pos); if(find && pos >= 0 && mRTParams[pos]) - { + { if( !shader->findShaderConstHandle( String::ToString("$rtParams%d", pos)) ) { String errStr = String::ToString("ShaderData(%s) sampler[%d] used but rtParams%d not used in shader compilation. Possible error", shader->getPixelShaderFile().c_str(), pos, pos); Con::errorf(errStr); error = true; } - } + } if(!find) { @@ -377,7 +405,7 @@ bool ShaderData::_checkDefinition(GFXShader *shader) GFXAssertFatal(0, errStr); error = true; } - } + } return !error; } diff --git a/Engine/source/materials/shaderData.h b/Engine/source/materials/shaderData.h index 4bef16679..e07f513cf 100644 --- a/Engine/source/materials/shaderData.h +++ b/Engine/source/materials/shaderData.h @@ -47,7 +47,7 @@ protected: /// static Vector smAllShaderData; - typedef HashTable ShaderCache; + typedef HashTable ShaderCache; ShaderCache mShaders; @@ -56,12 +56,12 @@ protected: F32 mPixVersion; StringTableEntry mDXVertexShaderName; - StringTableEntry mDXPixelShaderName; + StringTableEntry mDXGeometryShaderName; StringTableEntry mOGLVertexShaderName; - StringTableEntry mOGLPixelShaderName; + StringTableEntry mOGLGeometryShaderName; /// A semicolon, tab, or newline delimited string of case /// sensitive defines that are passed to the shader compiler. @@ -80,40 +80,40 @@ protected: /// them if the content has changed. const Vector& _getMacros(); - /// Helper for converting an array of macros + /// Helper for converting an array of macros /// into a formatted string. - void _stringizeMacros( const Vector ¯os, - String *outString ); + void _stringizeMacros(const Vector& macros, + String* outString); /// Creates a new shader returning NULL on error. - GFXShader* _createShader( const Vector ¯os ); + GFXShader* _createShader(const Vector& macros); /// @see LightManager::smActivateSignal - static void _onLMActivate( const char *lm, bool activate ); + static void _onLMActivate(const char* lm, bool activate); enum { NumTextures = 16 }; - String mSamplerNames[NumTextures]; + String mSamplerNames[NumTextures]; bool mRTParams[NumTextures]; - bool _checkDefinition(GFXShader *shader); + bool _checkDefinition(GFXShader* shader); public: - void setSamplerName(const String &name, int idx) { mSamplerNames[idx] = name; } + void setSamplerName(const String& name, int idx) { mSamplerNames[idx] = name; } String getSamplerName(int idx) const { return mSamplerNames[idx]; } - bool hasSamplerDef(const String &samplerName, int &pos) const; + bool hasSamplerDef(const String& samplerName, int& pos) const; bool hasRTParamsDef(const int pos) const { return mRTParams[pos]; } ShaderData(); - /// Returns an initialized shader instance or NULL + /// Returns an initialized shader instance or NULL /// if the shader failed to be created. - GFXShader* getShader( const Vector ¯os = Vector() ); + GFXShader* getShader(const Vector& macros = Vector()); /// Forces a reinitialization of all the instanced shaders. void reloadShaders(); @@ -124,7 +124,7 @@ public: /// Returns the required pixel shader version for this shader. F32 getPixVersion() const { return mPixVersion; } - + // SimObject virtual bool onAdd(); virtual void onRemove(); diff --git a/Engine/source/platformWin32/winPlatformCPUCount.cpp b/Engine/source/platformWin32/winPlatformCPUCount.cpp index e4b113c67..31edce054 100644 --- a/Engine/source/platformWin32/winPlatformCPUCount.cpp +++ b/Engine/source/platformWin32/winPlatformCPUCount.cpp @@ -1,19 +1,19 @@ // Original code is: -// Copyright (c) 2005 Intel Corporation +// Copyright (c) 2005 Intel Corporation // All Rights Reserved // // CPUCount.cpp : Detects three forms of hardware multi-threading support across IA-32 platform -// The three forms of HW multithreading are: Multi-processor, Multi-core, and +// The three forms of HW multithreading are: Multi-processor, Multi-core, and // HyperThreading Technology. // This application enumerates all the logical processors enabled by OS and BIOS, -// determine the HW topology of these enabled logical processors in the system +// determine the HW topology of these enabled logical processors in the system // using information provided by CPUID instruction. // A multi-processing system can support any combination of the three forms of HW -// multi-threading support. The relevant topology can be identified using a -// three level decomposition of the "initial APIC ID" into -// Package_id, core_id, and SMT_id. Such decomposition provides a three-level map of +// multi-threading support. The relevant topology can be identified using a +// three level decomposition of the "initial APIC ID" into +// Package_id, core_id, and SMT_id. Such decomposition provides a three-level map of // the topology of hardware resources and -// allow multi-threaded software to manage shared hardware resources in +// allow multi-threaded software to manage shared hardware resources in // the platform to reduce resource contention // Multicore detection algorithm for processor and cache topology requires @@ -60,25 +60,25 @@ namespace CPUInfo { PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL; DWORD returnLength = 0; - + // get buffer length DWORD rc = GetLogicalProcessorInformation( buffer, &returnLength ); buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc( returnLength ); - rc = GetLogicalProcessorInformation( buffer, &returnLength ); + rc = GetLogicalProcessorInformation( buffer, &returnLength ); // if we fail, assume single threaded if( FALSE == rc ) - { + { free( buffer ); Con::errorf("Unable to determine CPU Count, assuming 1 core"); TotAvailCore = 1; TotAvailLogical = 1; return CONFIG_SingleCoreAndHTNotCapable; - } + } -#pragma push -#pragma warning (disable: 6011) +#pragma warning( push ) +#pragma warning( disable: 6011 ) PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer; DWORD byteOffset = 0; @@ -95,7 +95,7 @@ namespace CPUInfo { } free( buffer ); -#pragma pop +#pragma warning( pop ) EConfig StatusFlag = CONFIG_SingleCoreAndHTNotCapable; diff --git a/Engine/source/scene/sceneQueryUtil.h b/Engine/source/scene/sceneQueryUtil.h index d53af4b17..5c913127b 100644 --- a/Engine/source/scene/sceneQueryUtil.h +++ b/Engine/source/scene/sceneQueryUtil.h @@ -5,7 +5,7 @@ /// allows it to return the appropriate geometry. enum PolyListContext { - /// A hint that the polyist is intended + /// A hint that the polyist is intended /// for collision testing. PLC_Collision, @@ -24,7 +24,7 @@ enum PolyListContext /// A hint that the polyist will be used /// to export geometry and would like to have - /// texture coords and materials. + /// texture coords and materials. PLC_Export }; @@ -71,7 +71,7 @@ struct SceneBinRange inline bool isGlobal() const { return minCoord[0] == 0 && - minCoord[0] == 0 && + minCoord[1] == 0 && maxCoord[0] == 0xFFFF && maxCoord[1] == 0xFFFF; } diff --git a/Engine/source/shaderGen/HLSL/debugVizFeatureHLSL.cpp b/Engine/source/shaderGen/HLSL/debugVizFeatureHLSL.cpp index bef95f4fd..72c50cd40 100644 --- a/Engine/source/shaderGen/HLSL/debugVizFeatureHLSL.cpp +++ b/Engine/source/shaderGen/HLSL/debugVizFeatureHLSL.cpp @@ -122,13 +122,13 @@ void DebugVizHLSL::processPix(Vector& componentList, if (fd.features[MFT_LightMap] || fd.features[MFT_ToneMap] || fd.features[MFT_VertLit]) return; - MultiLine* meta = new MultiLine; + MultiLine* newMeta = new MultiLine; // Now the wsPosition and wsView. Var* worldToTangent = getInWorldToTangent(componentList); Var* wsNormal = getInWorldNormal(componentList); Var* wsPosition = getInWsPosition(componentList); - Var* wsView = getWsView(wsPosition, meta); + Var* wsView = getWsView(wsPosition, newMeta); //Reflection Probe WIP U32 MAX_FORWARD_PROBES = 4; @@ -153,32 +153,32 @@ void DebugVizHLSL::processPix(Vector& componentList, Var* showAttenVar = new Var("showAttenVar", "int"); char buf[64]; dSprintf(buf, sizeof(buf), " @ = %s;\r\n", showAtten); - meta->addStatement(new GenOp(buf, new DecOp(showAttenVar))); + newMeta->addStatement(new GenOp(buf, new DecOp(showAttenVar))); Var* showContribVar = new Var("showContribVar", "int"); dSprintf(buf, sizeof(buf), " @ = %s;\r\n", showContrib); - meta->addStatement(new GenOp(buf, new DecOp(showContribVar))); + newMeta->addStatement(new GenOp(buf, new DecOp(showContribVar))); Var* showSpecVar = new Var("showSpecVar", "int"); dSprintf(buf, sizeof(buf), " @ = %s;\r\n", showSpec); - meta->addStatement(new GenOp(buf, new DecOp(showSpecVar))); + newMeta->addStatement(new GenOp(buf, new DecOp(showSpecVar))); Var* showDiffVar = new Var("showDiffVar", "int"); dSprintf(buf, sizeof(buf), " @ = %s;\r\n", showDiff); - meta->addStatement(new GenOp(buf, new DecOp(showDiffVar))); + newMeta->addStatement(new GenOp(buf, new DecOp(showDiffVar))); String computeForwardProbes = String(" @ = debugVizForwardProbes(@,@,@,@,@,@,@,@,\r\n\t\t"); computeForwardProbes += String("@,TORQUE_SAMPLER2D_MAKEARG(@),\r\n\t\t"); computeForwardProbes += String("TORQUE_SAMPLERCUBEARRAY_MAKEARG(@),TORQUE_SAMPLERCUBEARRAY_MAKEARG(@), @, @, @, @).rgb; \r\n"); - meta->addStatement(new GenOp(computeForwardProbes.c_str(), ibl, surface, cubeMips, numProbes, worldToObjArray, probeConfigData, inProbePosArray, refScaleArray, inRefPosArray, + newMeta->addStatement(new GenOp(computeForwardProbes.c_str(), ibl, surface, cubeMips, numProbes, worldToObjArray, probeConfigData, inProbePosArray, refScaleArray, inRefPosArray, skylightCubemapIdx, BRDFTexture, irradianceCubemapAR, specularCubemapAR, showAttenVar, showContribVar, showSpecVar, showDiffVar)); - meta->addStatement(new GenOp(" @.rgb = @.rgb;\r\n", color, ibl)); + newMeta->addStatement(new GenOp(" @.rgb = @.rgb;\r\n", color, ibl)); - output = meta; + output = newMeta; return; } } diff --git a/Engine/source/shaderGen/shaderGen.cpp b/Engine/source/shaderGen/shaderGen.cpp index 9ae35d474..54b297772 100644 --- a/Engine/source/shaderGen/shaderGen.cpp +++ b/Engine/source/shaderGen/shaderGen.cpp @@ -47,7 +47,7 @@ MODULE_BEGIN( ShaderGen ) { ManagedSingleton< ShaderGen >::createSingleton(); } - + MODULE_SHUTDOWN { ManagedSingleton< ShaderGen >::deleteSingleton(); @@ -94,7 +94,7 @@ bool ShaderGen::_handleGFXEvent(GFXDevice::GFXDeviceEventType event) } void ShaderGen::initShaderGen() -{ +{ if (mInit) return; @@ -125,7 +125,7 @@ void ShaderGen::initShaderGen() { // If we didn't get a path then we're gonna cache the shaders to // a virtualized memory file system. - mMemFS = new Torque::Mem::MemFileSystem( "shadergen:/" ); + mMemFS = new Torque::Mem::MemFileSystem( "shadergen:/" ); Torque::FS::Mount( "shadergen", mMemFS ); } else @@ -136,8 +136,8 @@ void ShaderGen::initShaderGen() } void ShaderGen::generateShader( const MaterialFeatureData &featureData, - char *vertFile, - char *pixFile, + char *vertFile, + char *pixFile, F32 *pixVersion, const GFXVertexFormat *vertexFormat, const char* cacheName, @@ -155,23 +155,23 @@ void ShaderGen::generateShader( const MaterialFeatureData &featureData, char pixShaderName[256]; // Note: We use a postfix of _V/_P here so that it sorts the matching - // vert and pixel shaders together when listed alphabetically. + // vert and pixel shaders together when listed alphabetically. dSprintf( vertShaderName, sizeof(vertShaderName), "shadergen:/%s_V.%s", cacheName, mFileEnding.c_str() ); dSprintf( pixShaderName, sizeof(pixShaderName), "shadergen:/%s_P.%s", cacheName, mFileEnding.c_str() ); - + dStrcpy( vertFile, vertShaderName, 256 ); dStrcpy( pixFile, pixShaderName, 256 ); - + // this needs to change - need to optimize down to ps v.1.1 *pixVersion = GFX->getPixelShaderVersion(); - + if ( !Con::getBoolVariable( "ShaderGen::GenNewShaders", true ) ) { // If we are not regenerating the shader we will return here. // But we must fill in the shader macros first! _processVertFeatures( macros, true ); - _processPixFeatures( macros, true ); + _processPixFeatures( macros, true ); return; } @@ -190,7 +190,7 @@ void ShaderGen::generateShader( const MaterialFeatureData &featureData, _processVertFeatures(macros); _printVertShader( *s ); delete s; - + ((ShaderConnector*)mComponents[C_CONNECTOR])->reset(); LangElement::deleteElements(); @@ -202,7 +202,7 @@ void ShaderGen::generateShader( const MaterialFeatureData &featureData, AssertFatal(false, "Failed to open Shader Stream" ); delete s; return; - } + } mOutput = new MultiLine; _processPixFeatures(macros); @@ -284,7 +284,7 @@ void ShaderGen::_processVertFeatures( Vector ¯os, bool macro mOutput->addStatement( feature->getOutput() ); feature->reset(); - mOutput->addStatement( new GenOp( " \r\n" ) ); + mOutput->addStatement( new GenOp( " \r\n" ) ); } } @@ -327,7 +327,7 @@ void ShaderGen::_processPixFeatures( Vector ¯os, bool macros mOutput->addStatement( new GenOp( " \r\n" ) ); } } - + ShaderConnector *connect = dynamic_cast( mComponents[C_CONNECTOR] ); connect->sortVars(); } @@ -335,7 +335,7 @@ void ShaderGen::_processPixFeatures( Vector ¯os, bool macros void ShaderGen::_printFeatureList(Stream &stream) { mPrinter->printLine(stream, "// Features:"); - + const FeatureSet &features = mFeatureData.features; for( U32 i=0; i < features.getCount(); i++ ) @@ -376,7 +376,7 @@ void ShaderGen::_printDependencies(Stream &stream) for( U32 j=0; j < dependencies.size(); j++ ) { - if ( j != i && + if ( j != i && *dependencies[i] == *dependencies[j] ) { dup = true; @@ -386,7 +386,7 @@ void ShaderGen::_printDependencies(Stream &stream) if ( dup ) dependencies.erase( i ); - else + else i++; } @@ -493,7 +493,10 @@ GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const G generateShader( featureData, vertFile, pixFile, &pixVersion, vertexFormat, cacheKey, shaderMacros ); GFXShader *shader = GFX->createShader(); - if (!shader->init(vertFile, pixFile, pixVersion, shaderMacros, samplers, &mInstancingFormat)) + shader->setShaderStageFile(GFXShaderStage::VERTEX_SHADER, vertFile); + shader->setShaderStageFile(GFXShaderStage::PIXEL_SHADER, pixFile); + + if (!shader->init(pixVersion, shaderMacros, samplers, &mInstancingFormat)) { delete shader; return NULL; @@ -508,5 +511,5 @@ void ShaderGen::flushProceduralShaders() { // The shaders are reference counted, so we // just need to clear the map. - mProcShaders.clear(); + mProcShaders.clear(); } diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript b/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript index 6a2981fa9..51552e141 100644 --- a/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript @@ -149,4 +149,42 @@ singleton ShaderData( CubemapSaveShader ) samplerNames[0] = "$cubemapTex"; pixVersion = 3.0; +}; + +//----------------------------------------------------------------------------- +// GUI shaders +//----------------------------------------------------------------------------- +singleton ShaderData( RoundedRectangleGUI ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/colorV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/fixedFunction/roundedRectangleP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/colorV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/roundedRectangleP.glsl"; + + pixVersion = 3.0; +}; + +singleton ShaderData( CircularGUI ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/colorV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/fixedFunction/circleP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/colorV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/circleP.glsl"; + + pixVersion = 3.0; +}; + +singleton ShaderData( ThickLineGUI ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/colorV.hlsl"; + DXGeometryShaderFile = $Core::CommonShaderPath @ "/fixedFunction/thickLineG.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/fixedFunction/thickLineP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/colorV.glsl"; + OGLGeometryShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/thickLineG.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/thickLineP.glsl"; + + pixVersion = 3.0; }; \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/circleP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/circleP.hlsl new file mode 100644 index 000000000..684e53ff3 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/circleP.hlsl @@ -0,0 +1,66 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct Conn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; +}; + +uniform float2 sizeUni; +uniform float radius; +uniform float2 rectCenter; +uniform float borderSize; +uniform float4 borderCol; + +float circle(float2 p, float2 center, float r) +{ + return length(p - center); +} + +float4 main(Conn IN) : TORQUE_TARGET0 +{ + float distance = circle(IN.HPOS.xy, rectCenter, radius); + + float4 fromColor = borderCol; + float4 toColor = float4(0.0, 0.0, 0.0, 0.0); + + if(distance < radius) + { + distance = abs(distance) - radius; + + if(distance < (radius - (borderSize))) + { + toColor = IN.color; + distance = abs(distance) - (borderSize); + } + + float blend = smoothstep(0.0, 1.0, distance); + return lerp(fromColor, toColor, blend); + } + + distance = abs(distance) - radius; + float blend = smoothstep(0.0, 1.0, distance); + return lerp(fromColor, toColor, blend); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/circleP.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/circleP.glsl new file mode 100644 index 000000000..4882019b8 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/circleP.glsl @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +in vec4 color; + +out vec4 OUT_col; + +uniform vec2 sizeUni; +uniform float radius; +uniform vec2 rectCenter; +uniform float borderSize; +uniform vec4 borderCol; + +float circle(vec2 p, vec2 center, float r) +{ + return length(p - center); +} + +void main() +{ + float dist = circle(gl_FragCoord.xy, rectCenter, radius); + + vec4 fromColor = borderCol; + vec4 toColor = vec4(0.0, 0.0, 0.0, 0.0); + + if(dist < radius) + { + dist = abs(dist) - radius; + + if(dist < (radius - (borderSize))) + { + toColor = color; + dist = abs(dist) - (borderSize); + } + + float blend = smoothstep(0.0, 1.0, dist); + OUT_col = mix(fromColor, toColor, blend); + } + + dist = abs(dist) - radius; + float blend = smoothstep(0.0, 1.0, dist); + OUT_col = mix(fromColor, toColor, blend); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/roundedRectangleP.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/roundedRectangleP.glsl new file mode 100644 index 000000000..57599b550 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/roundedRectangleP.glsl @@ -0,0 +1,98 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +in vec4 color; + +out vec4 OUT_col; + +uniform vec2 sizeUni; +uniform vec2 rectCenter; +uniform vec2 oneOverViewport; +uniform float radius; +uniform float borderSize; +uniform vec4 borderCol; + +float RoundedRectSDF(vec2 p, vec2 size, float radius) +{ + // Calculate distance to each side of the rectangle + vec2 dist = abs(p) - size + vec2(radius, radius); + + // Compute the distance to the rounded corners + float cornerDist = length(max(dist, 0.0)); + + // Return the minimum distance (negative inside, positive outside) + return min(max(dist.x, dist.y), 0.0) + cornerDist - radius; +} + +void main() +{ + vec2 p = gl_FragCoord.xy; + + float halfBorder = borderSize * 0.5; + vec2 halfSize = sizeUni * 0.5; + p -= rectCenter; + + // Calculate signed distance field for rounded rectangle + vec4 fromColor = borderCol; + // alpha + vec4 toColor = vec4(0.0, 0.0, 0.0, 0.0); + + float cornerRadius = radius; + + // if ((p.y < 0.0 && p.x < 0.0) || // top left corner + // (p.y < 0.0 && p.x > 0.0) || // top right corner + // (p.y > 0.0 && p.x > 0.0) || // bottom right corner. + // (p.y > 0.0 && p.x < 0.0)) // bottom left corner + // { + // cornerRadius = radius; + // } + + if(cornerRadius > 0.0 || halfBorder > 0.0) + { + float sdf = RoundedRectSDF(p, halfSize, cornerRadius - halfBorder); + + if(halfBorder > 0.0) + { + if(sdf < 0.0) + { + // if ((p.y >= -halfSize.y - radius + halfBorder && p.y <= -halfSize.y + radius - halfBorder) || // top border + // (p.y >= halfSize.y - radius + halfBorder && p.y <= halfSize.y + radius - halfBorder) || // bottom border + // (p.x >= -halfSize.x - radius + halfBorder && p.x <= -halfSize.x + radius - halfBorder) || // left border + // (p.x >= halfSize.x - radius + halfBorder && p.x <= halfSize.x + radius - halfBorder) ) { // right border + + // } + toColor = color; + sdf = abs(sdf) / borderSize; + } + + } + else{ + fromColor = color; + } + + float alpha = smoothstep(-1.0, 1.0, sdf); + OUT_col = mix(fromColor, toColor, alpha); + } + else + { + OUT_col = color; + } +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/thickLineG.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/thickLineG.glsl new file mode 100644 index 000000000..f52486699 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/thickLineG.glsl @@ -0,0 +1,67 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +layout (lines) in; +layout (triangle_strip, max_vertices = 4) out; + +in VS_OUT { + vec4 color; +} gs_in[]; + + +out vec4 fragColor; + +uniform float thickness; +uniform vec2 oneOverViewport; + +void main() +{ + // Calculate the direction of the line segment + vec2 direction = normalize(gl_in[1].gl_Position.xy - gl_in[0].gl_Position.xy); + + // Calculate perpendicular direction + vec2 perpendicular = normalize(vec2(-direction.y, direction.x)); + + // Calculate offset for thickness + vec2 offset = vec2(thickness * oneOverViewport.x, thickness * oneOverViewport.y) * perpendicular; + + // Calculate vertices for the line with thickness + vec2 p0 = gl_in[0].gl_Position.xy + offset; + vec2 p1 = gl_in[0].gl_Position.xy - offset; + vec2 p2 = gl_in[1].gl_Position.xy + offset; + vec2 p3 = gl_in[1].gl_Position.xy - offset; + + fragColor = gs_in[0].color; + gl_Position = vec4(p0, 0.0f, 1.0f); + EmitVertex(); + + gl_Position = vec4(p1, 0.0f, 1.0f); + EmitVertex(); + + gl_Position = vec4(p2, 0.0f, 1.0f); + EmitVertex(); + + gl_Position = vec4(p3, 0.0f, 1.0f); + EmitVertex(); + + EndPrimitive(); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/thickLineP.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/thickLineP.glsl new file mode 100644 index 000000000..eeee83abc --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/thickLineP.glsl @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +in vec4 fragColor; + +out vec4 OUT_col; + +void main() +{ + OUT_col = fragColor; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/roundedRectangleP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/roundedRectangleP.hlsl new file mode 100644 index 000000000..9dbffc4f4 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/roundedRectangleP.hlsl @@ -0,0 +1,103 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct Conn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; +}; + +uniform float2 sizeUni; +uniform float2 rectCenter; +uniform float2 oneOverViewport; +uniform float radius; +uniform float borderSize; +uniform float4 borderCol; + +float RoundedRectSDF(float2 p, float2 size, float radius) +{ + // Calculate distance to each side of the rectangle + float2 dist = abs(p) - size + float2(radius, radius); + + // Compute the distance to the rounded corners + float cornerDist = length(max(dist, 0.0)); + + // Return the minimum distance (negative inside, positive outside) + return min(max(dist.x, dist.y), 0.0) + cornerDist - radius; +} + +float4 main(Conn IN) : TORQUE_TARGET0 +{ + float2 p = IN.HPOS.xy; + + float halfBorder = borderSize * 0.5; + float2 halfSize = sizeUni * 0.5; + p -= rectCenter; + + // Calculate signed distance field for rounded rectangle + float4 fromColor = borderCol; + // alpha + float4 toColor = float4(0.0, 0.0, 0.0, 0.0); + + float cornerRadius = radius; + + // if ((p.y < 0.0 && p.x < 0.0) || // top left corner + // (p.y < 0.0 && p.x > 0.0) || // top right corner + // (p.y > 0.0 && p.x > 0.0) || // bottom right corner. + // (p.y > 0.0 && p.x < 0.0)) // bottom left corner + // { + // cornerRadius = radius; + // } + + if(cornerRadius > 0.0 || halfBorder > 0.0) + { + float sdf = RoundedRectSDF(p, halfSize, cornerRadius - halfBorder); + + if(halfBorder > 0.0) + { + if(sdf < 0.0) + { + // if ((p.y >= -halfSize.y - radius + halfBorder && p.y <= -halfSize.y + radius - halfBorder) || // top border + // (p.y >= halfSize.y - radius + halfBorder && p.y <= halfSize.y + radius - halfBorder) || // bottom border + // (p.x >= -halfSize.x - radius + halfBorder && p.x <= -halfSize.x + radius - halfBorder) || // left border + // (p.x >= halfSize.x - radius + halfBorder && p.x <= halfSize.x + radius - halfBorder) ) { // right border + + // } + toColor = IN.color; + sdf = abs(sdf) / borderSize; + } + + } + else{ + fromColor = IN.color; + } + + float alpha = smoothstep(-1.0, 1.0, sdf); + return lerp(fromColor, toColor, alpha); + } + else + { + return IN.color; + } +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/thickLineG.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/thickLineG.hlsl new file mode 100644 index 000000000..a7cf3d67a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/thickLineG.hlsl @@ -0,0 +1,77 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct Conn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; +}; + +struct PSConn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; +}; + +uniform float thickness; +uniform float2 oneOverViewport; + +[maxvertexcount(4)] +void main(line Conn lineSegment[2], inout TriangleStream outstream) +{ + // Calculate the direction of the line segment + float2 direction = normalize(lineSegment[1].HPOS.xy - lineSegment[0].HPOS.xy); + + // Calculate perpendicular direction + float2 perpendicular = normalize(float2(-direction.y, direction.x)); + + // Calculate offset for thickness + float2 offset = float2(thickness * oneOverViewport.x, thickness * oneOverViewport.y) * perpendicular; + + // Calculate vertices for the line with thickness + float2 p0 = lineSegment[0].HPOS.xy + offset; + float2 p1 = lineSegment[0].HPOS.xy - offset; + float2 p2 = lineSegment[1].HPOS.xy + offset; + float2 p3 = lineSegment[1].HPOS.xy - offset; + + PSConn output; + + output.HPOS = float4(p0, 0.0f, 1.0f); + output.color = lineSegment[0].color; + outstream.Append(output); + + output.HPOS = float4(p1, 0.0f, 1.0f); + output.color = lineSegment[0].color; + outstream.Append(output); + + output.HPOS = float4(p2, 0.0f, 1.0f); + output.color = lineSegment[1].color; + outstream.Append(output); + + output.HPOS = float4(p3, 0.0f, 1.0f); + output.color = lineSegment[1].color; + outstream.Append(output); + + outstream.RestartStrip(); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/thickLineP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/thickLineP.hlsl new file mode 100644 index 000000000..e2659f777 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/thickLineP.hlsl @@ -0,0 +1,34 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct PSConn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; +}; + +float4 main(PSConn IN) : TORQUE_TARGET0 +{ + return IN.color; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/gui/profiles.ed.tscript b/Templates/BaseGame/game/tools/gui/profiles.ed.tscript index 770c2ad61..26886e128 100644 --- a/Templates/BaseGame/game/tools/gui/profiles.ed.tscript +++ b/Templates/BaseGame/game/tools/gui/profiles.ed.tscript @@ -943,6 +943,16 @@ singleton GuiControlProfile( GuiBackFillProfile ) category = "Editor"; }; +singleton GuiControlProfile(GuiShaderEditorProfile : ToolsGuiDefaultProfile) +{ + opaque = true; + canKeyFocus = true; + border = true; + borderColor = "128 128 128 128"; + borderColorHL = "128 128 0"; + borderColorSEL = "128 0 128 128"; +}; + singleton GuiControlProfile( GuiControlListPopupProfile ) { opaque = true; diff --git a/Templates/BaseGame/game/tools/shaderEditor/gui/shaderEditorGui.asset.taml b/Templates/BaseGame/game/tools/shaderEditor/gui/shaderEditorGui.asset.taml new file mode 100644 index 000000000..9898caa03 --- /dev/null +++ b/Templates/BaseGame/game/tools/shaderEditor/gui/shaderEditorGui.asset.taml @@ -0,0 +1,7 @@ + diff --git a/Templates/BaseGame/game/tools/shaderEditor/gui/shaderEditorGui.ed.gui b/Templates/BaseGame/game/tools/shaderEditor/gui/shaderEditorGui.ed.gui new file mode 100644 index 000000000..9a6f23cc5 --- /dev/null +++ b/Templates/BaseGame/game/tools/shaderEditor/gui/shaderEditorGui.ed.gui @@ -0,0 +1,122 @@ +//--- OBJECT WRITE BEGIN --- +$guiContent = new GuiControl(ShaderEditorGui) { + extent = "1280 720"; + profile = "GuiDefaultProfile"; + tooltipProfile = "ToolsGuiToolTipProfile"; + isContainer = "1"; + canSaveDynamicFields = "1"; + + new GuiFrameSetCtrl() { + columns = "0 320 1000"; + borderWidth = "2"; + borderColor = "10 10 10 0"; + autoBalance = "1"; + extent = "1280 720"; + horizSizing = "width"; + vertSizing = "height"; + profile = "ToolsGuiFrameSetProfile"; + tooltipProfile = "ToolsGuiToolTipProfile"; + + new GuiControl() { + extent = "318 720"; + horizSizing = "width"; + vertSizing = "height"; + profile = "ToolsGuiDefaultProfile"; + tooltipProfile = "ToolsGuiToolTipProfile"; + isContainer = "1"; + + new GuiSplitContainer() { + orientation = "Horizontal"; + splitPoint = "0 200"; + extent = "317 720"; + horizSizing = "width"; + vertSizing = "height"; + profile = "ToolsGuiDefaultProfile"; + tooltipProfile = "ToolsGuiToolTipProfile"; + + new GuiPanel(ShaderEditorPreview) { + docking = "Client"; + extent = "317 198"; + profile = "ToolsGuiButtonProfile"; + tooltipProfile = "ToolsGuiToolTipProfile"; + internalName = "Panel1"; + }; + new GuiPanel(ShaderEditorInspector) { + docking = "Client"; + position = "0 202"; + extent = "317 518"; + profile = "ToolsGuiButtonProfile"; + tooltipProfile = "ToolsGuiToolTipProfile"; + internalName = "panel2"; + }; + }; + }; + new GuiControl() { + position = "320 0"; + extent = "678 720"; + horizSizing = "width"; + vertSizing = "height"; + profile = "ToolsGuiButtonProfile"; + tooltipProfile = "ToolsGuiToolTipProfile"; + isContainer = "1"; + + new GuiShaderEditor(ShaderNodeGraph) { + extent = "678 720"; + horizSizing = "width"; + vertSizing = "height"; + profile = "GuiShaderEditorProfile"; + tooltipProfile = "GuiToolTipProfile"; + }; + }; + new GuiControl(ShaderEditorSidebar) { + position = "1000 0"; + extent = "280 720"; + horizSizing = "width"; + vertSizing = "height"; + profile = "ToolsGuiDefaultProfile"; + tooltipProfile = "ToolsGuiButtonProfile"; + isContainer = "1"; + + new GuiTabBookCtrl(ShaderEditorTabBook) { + tabHeight = "20"; + allowReorder = "1"; + selectedPage = "0"; + position = "3 5"; + extent = "271 520"; + horizSizing = "width"; + vertSizing = "height"; + profile = "ToolsGuiTabBookProfile"; + tooltipProfile = "ToolsGuiToolTipProfile"; + + new GuiTabPageCtrl() { + fitBook = "1"; + text = "Library"; + position = "0 20"; + extent = "271 500"; + horizSizing = "width"; + vertSizing = "height"; + profile = "ToolsGuiTabPageProfile"; + tooltipProfile = "ToolsGuiToolTipProfile"; + + new GuiScrollCtrl() { + hScrollBar = "dynamic"; + childMargin = "0 2"; + extent = "271 490"; + horizSizing = "width"; + vertSizing = "height"; + profile = "ToolsGuiScrollProfile"; + tooltipProfile = "ToolsGuiToolTipProfile"; + + new GuiStackControl(ShaderToolbox) { + extent = "591 1000"; + horizSizing = "width"; + profile = "ToolsGuiDefaultProfile"; + tooltipProfile = "ToolsGuiToolTipProfile"; + }; + }; + }; + }; + }; + }; +}; +//--- OBJECT WRITE END --- diff --git a/Tools/CMake/modules/tools.cmake b/Tools/CMake/modules/tools.cmake index 070c4e15b..62cad2f3b 100644 --- a/Tools/CMake/modules/tools.cmake +++ b/Tools/CMake/modules/tools.cmake @@ -4,7 +4,8 @@ option(TORQUE_TOOLS "Enable Torque Tools" ON) if(TORQUE_TOOLS) message("Enabling Torque Tools Module") - file(GLOB_RECURSE TORQUE_TOOLS_SOURCES "gui/editor/*.cpp" "gui/editor/*.h" "gui/worldEditor/*.cpp" "gui/worldEditor/*.h") + file(GLOB_RECURSE TORQUE_TOOLS_SOURCES "gui/editor/*.cpp" "gui/editor/*.h" "gui/worldEditor/*.cpp" "gui/worldEditor/*.h" "gui/shaderEditor/*.cpp" "gui/shaderEditor/*.h" + "gui/shaderEditor/nodes/*.cpp" "gui/shaderEditor/nodes/*.h") file(GLOB_RECURSE TORQUE_TOOLS_SOURCES2 "environment/editors/*.cpp" "environment/editors/*.h") file(GLOB_RECURSE TORQUE_TOOLS_SOURCES3 "forest/editor/*.cpp" "forest/editor/*.h")