//[-------------------------------------------------------]
//[ Private virtual SRPDirectionalLighting functions      ]
//[-------------------------------------------------------]
void SRPDirectionalLightingShaders::DrawMesh(Renderer &cRenderer, const SQCull &cCullQuery, const VisNode &cVisNode, SceneNode &cSceneNode, const MeshHandler &cMeshHandler, const Mesh &cMesh, const MeshLODLevel &cMeshLODLevel, VertexBuffer &cVertexBuffer)
{
	// Get scene container
	const VisContainer &cVisContainer = cCullQuery.GetVisContainer();

	// Get buffers
		  IndexBuffer     *pIndexBuffer  = cMeshLODLevel.GetIndexBuffer();
	const Array<Geometry> &lstGeometries = *cMeshLODLevel.GetGeometries();

	// Bind buffers
	cRenderer.SetIndexBuffer(pIndexBuffer);

	// Is lighting enabled for this scene node?
	const bool bLightingEnabled = !(cSceneNode.GetFlags() & SceneNode::NoLighting) && (m_cLightColor != Color3::Black);

	// Get available vertex buffer attributes
	// Binormal and tangent make only sense in this usage when there's also a normal, we need all three vectors!
	const bool bHasVertexTexCoord0 = (cVertexBuffer.GetVertexAttribute(VertexBuffer::TexCoord, 0) != nullptr);	// e.g. for diffuse maps
	const bool bHasVertexTexCoord1 = (cVertexBuffer.GetVertexAttribute(VertexBuffer::TexCoord, 1) != nullptr);	// e.g. for light maps
	const bool bHasVertexNormal    = (cVertexBuffer.GetVertexAttribute(VertexBuffer::Normal) != nullptr);
		  bool bHasVertexTangent   = bHasVertexNormal && (cVertexBuffer.GetVertexAttribute(VertexBuffer::Tangent) != nullptr);
	const bool bHasVertexBinormal  = bHasVertexTangent && (cVertexBuffer.GetVertexAttribute(VertexBuffer::Binormal) != nullptr);

	// For better readability, define whether or not normal mapping is possible with the given vertex data
	const bool bNormalMappingPossible = bHasVertexBinormal;	// We don't need to check for all three vectors in here :D

	// [TODO] Cleanup
	uint32 nEnvironmentFlags = 0;
	if (bHasVertexNormal)
		nEnvironmentFlags |= SRPDirectionalLightingShadersMaterial::EnvironmentVertexNormal;
	if (bHasVertexTexCoord0)
		nEnvironmentFlags |= SRPDirectionalLightingShadersMaterial::EnvironmentVertexTexCoord0;
	if (bHasVertexTexCoord1)
		nEnvironmentFlags |= SRPDirectionalLightingShadersMaterial::EnvironmentVertexTexCoord1;
	if (bNormalMappingPossible)
		nEnvironmentFlags |= SRPDirectionalLightingShadersMaterial::EnvironmentNormalMappingPossible;
	if (bLightingEnabled)
		nEnvironmentFlags |= SRPDirectionalLightingShadersMaterial::EnvironmentLightingEnabled;
	if (m_bGlowEnabled)
		nEnvironmentFlags |= SRPDirectionalLightingShadersMaterial::EnvironmentGlowEnabled;
	if (m_fDOFBlurrinessCutoff)
		nEnvironmentFlags |= SRPDirectionalLightingShadersMaterial::EnvironmentDOFEnabled;

	// Draw mesh
	for (uint32 nMat=0; nMat<cMeshHandler.GetNumOfMaterials(); nMat++) {
		// Get mesh material
		Material *pMaterial = cMeshHandler.GetMaterial(nMat);
		if (pMaterial) {
			// Draw geometries
			for (uint32 nGeo=0; nGeo<lstGeometries.GetNumOfElements(); nGeo++) {
				// Is this geometry active and is it using the current used mesh material?
				const Geometry &cGeometry = lstGeometries[nGeo];
				if (cGeometry.IsActive() && nMat == cGeometry.GetMaterial()) {
					// Transparent material?
					static const String sOpacity = "Opacity";
					const Parameter *pParameter = pMaterial->GetParameter(sOpacity);
					if ((GetFlags() & TransparentPass) ? (pParameter && pParameter->GetValue1f() < 1.0f) : (!pParameter || pParameter->GetValue1f() >= 1.0f)) {
						// SRPDirectionalLightingShaders-material caching
						SRPDirectionalLightingShadersMaterial *pSRPDirectionalLightingShadersMaterial = m_lstMaterialCache.Get(reinterpret_cast<uint64>(pMaterial));
						if (!pSRPDirectionalLightingShadersMaterial) {
							// The material is not yet cached
							pSRPDirectionalLightingShadersMaterial = new SRPDirectionalLightingShadersMaterial(*m_pRenderStates, *pMaterial, *m_pProgramGenerator);
							m_lstMaterialCache.Add(reinterpret_cast<uint64>(pMaterial), pSRPDirectionalLightingShadersMaterial);
						}

						// [TODO] Correct texture filter
						SRPDirectionalLightingShadersMaterial::GeneratedProgramUserData *pGeneratedProgramUserData = pSRPDirectionalLightingShadersMaterial->MakeMaterialCurrent(GetFlags(), nEnvironmentFlags, SRPDirectionalLightingShadersMaterial::Anisotropic2);
						if (pGeneratedProgramUserData) {
							// Ambient color
							if (pGeneratedProgramUserData->pAmbientColor)
								pGeneratedProgramUserData->pAmbientColor->Set(AmbientColor.Get());

							// Set the "ViewSpaceToWorldSpace" fragment shader parameter
							if (pGeneratedProgramUserData->pViewSpaceToWorldSpace) {
								// [TODO] Add *SQCullQuery::GetInvViewMatrix()?
								Matrix3x3 mRot = cCullQuery.GetViewMatrix().GetInverted();
								pGeneratedProgramUserData->pViewSpaceToWorldSpace->Set(mRot);
							}

							if (bLightingEnabled) {
								// Set view space light direction and light color
								if (pGeneratedProgramUserData->pLightDirection)
									pGeneratedProgramUserData->pLightDirection->Set(m_vLightDirection);
								if (pGeneratedProgramUserData->pLightColor)
									pGeneratedProgramUserData->pLightColor->Set(m_cLightColor);
							}

							// DOF
							if (pGeneratedProgramUserData->pDOFParams)
								pGeneratedProgramUserData->pDOFParams->Set(m_fDOFNearBlurDepth, m_fDOFFocalPlaneDepth, m_fDOFFarBlurDepth, m_fDOFBlurrinessCutoff);

							// Set object space to clip space matrix uniform
							if (pGeneratedProgramUserData->pObjectSpaceToClipSpaceMatrix)
								pGeneratedProgramUserData->pObjectSpaceToClipSpaceMatrix->Set(cVisNode.GetWorldViewProjectionMatrix());

							// Set object space to view space matrix uniform
							if (pGeneratedProgramUserData->pObjectSpaceToViewSpaceMatrix)
								pGeneratedProgramUserData->pObjectSpaceToViewSpaceMatrix->Set(cVisNode.GetWorldViewMatrix());

							// Parallax mapping - set object space eye position
							if (pGeneratedProgramUserData->pHeightMap && pGeneratedProgramUserData->pEyePos)
								pGeneratedProgramUserData->pEyePos->Set(cVisNode.GetInverseWorldMatrix()*(cVisContainer.GetWorldMatrix()*cCullQuery.GetCameraPosition()));

							// Set program vertex attributes, this creates a connection between "Vertex Buffer Attribute" and "Vertex Shader Attribute"
							if (pGeneratedProgramUserData->pVertexPosition)
								pGeneratedProgramUserData->pVertexPosition->Set(&cVertexBuffer, PLRenderer::VertexBuffer::Position);
							if (pGeneratedProgramUserData->pVertexTexCoord0)
								pGeneratedProgramUserData->pVertexTexCoord0->Set(&cVertexBuffer, PLRenderer::VertexBuffer::TexCoord, 0);
							if (pGeneratedProgramUserData->pVertexTexCoord1)
								pGeneratedProgramUserData->pVertexTexCoord1->Set(&cVertexBuffer, PLRenderer::VertexBuffer::TexCoord, 1);
							if (pGeneratedProgramUserData->pVertexNormal)
								pGeneratedProgramUserData->pVertexNormal->Set(&cVertexBuffer, PLRenderer::VertexBuffer::Normal);
							if (pGeneratedProgramUserData->pVertexTangent)
								pGeneratedProgramUserData->pVertexTangent->Set(&cVertexBuffer, PLRenderer::VertexBuffer::Tangent);
							if (pGeneratedProgramUserData->pVertexBinormal)
								pGeneratedProgramUserData->pVertexBinormal->Set(&cVertexBuffer, PLRenderer::VertexBuffer::Binormal);

							// Two sided lighting?
							if (pGeneratedProgramUserData->pNormalScale)
								pGeneratedProgramUserData->pNormalScale->Set(1.0f);

							// Draw the geometry
							cRenderer.DrawIndexedPrimitives(
								cGeometry.GetPrimitiveType(),
								0,
								cVertexBuffer.GetNumOfElements()-1,
								cGeometry.GetStartIndex(),
								cGeometry.GetIndexSize()
							);

							// If this is a two sided material, draw the primitives again - but with
							// flipped culling mode and vertex normals
							if (pGeneratedProgramUserData->pNormalScale) {
								// Flip normals
								pGeneratedProgramUserData->pNormalScale->Set(-1.0f);

								// Flip the backface culling
								const uint32 nCullModeBackup = cRenderer.GetRenderState(RenderState::CullMode);
								cRenderer.SetRenderState(RenderState::CullMode, Cull::CW);

								// Draw geometry - again
								cRenderer.DrawIndexedPrimitives(
									cGeometry.GetPrimitiveType(),
									0,
									cVertexBuffer.GetNumOfElements()-1,
									cGeometry.GetStartIndex(),
									cGeometry.GetIndexSize()
								);

								// Restore the previous cull mode
								cRenderer.SetRenderState(RenderState::CullMode, nCullModeBackup);
							}
						}
					}
				}
			}
		}
	}
}
Esempio n. 2
0
/**
*  @brief
*    Recursive part of PerformQuery()
*/
bool SQPlaneSet::PerformQueryRec(SceneHierarchyNode &cHierarchyNode)
{
	// Is this scene hierarchy node intersecting the plane set?
	if (!cHierarchyNode.CheckPlaneSet(m_cPlaneSet))
		return true; // Continue the query

	// Touch this node
	cHierarchyNode.Touch();

	// Get the scene context
	SceneContext *pSceneContext = GetSceneContext();
	if (pSceneContext) {
		// Inform all listeners
		const SceneHierarchyNodeItem *pItem = cHierarchyNode.GetFirstItem();
		while (pItem) {
			// Get the linked scene node
			SceneNode *pSceneNode = pItem->GetSceneNode();

			// Was this scene node already processed?
			if (pSceneNode && !pSceneContext->IsNodeTouched(*pSceneNode)) {
				// Check scene node
				const AABoundingBox &cAABB = pSceneNode->GetContainerAABoundingBox();
				if (Intersect::PlaneSetAABox(m_cPlaneSet, cAABB.vMin, cAABB.vMax)) {
					// Touch this node
					pSceneContext->TouchNode(*pSceneNode);

					// Emit signal
					SignalSceneNode(*this, *pSceneNode);
					if (m_nFlags & StopQuery)
						return false; // Stop the query right now

					// Continue recursive?
					if (m_nFlags & Recursive) {
						// Is this a container and is recursion allowed?
						if (pSceneNode->IsContainer() && !(pSceneNode->GetFlags() & SceneContainer::NoRecursion)) {
							// Backup current plane set
							const PlaneSet cPlaneSet = m_cPlaneSet;

							// Transform the plane set into container space
							m_cPlaneSet *= pSceneNode->GetTransform().GetInverseMatrix();

							// Container recursion
							const bool bContinue = PerformQueryRec(static_cast<SceneContainer*>(pSceneNode)->GetHierarchyInstance()->GetRootNode());

							// Restore plane set
							m_cPlaneSet = cPlaneSet;

							// Stop the query right now?
							if (!bContinue)
								return false;

						// Is this a cell-portal?
						} else if (pSceneNode->IsPortal() && pSceneNode->IsInstanceOf("PLScene::SNCellPortal") && !(pSceneNode->GetFlags() & SNCellPortal::NoPassThrough)) {
							// Get the target cell
							SNCellPortal   &cCellPortal	= static_cast<SNCellPortal&>(*pSceneNode);
							SceneContainer *pCell		= reinterpret_cast<SceneContainer*>(cCellPortal.GetTargetCellInstance());
							if (pCell && pCell != pSceneNode->GetContainer()) {
								// Backup current plane set
								const PlaneSet cPlaneSet = m_cPlaneSet;

								// Transform the plane set into container space
								m_cPlaneSet *= cCellPortal.GetWarpMatrix();

								// Container recursion
								const bool bContinue = PerformQueryRec(pCell->GetHierarchyInstance()->GetRootNode());

								// Restore plane set
								m_cPlaneSet = cPlaneSet;

								// Stop the query right now?
								if (!bContinue)
									return false;
							}
						}
					}
				}
			}

			// Next item, please
			pItem = pItem->GetNextItem();
		}
	}

	// Check all sub-hierarchies
	for (uint32 i=0; i<cHierarchyNode.GetNumOfNodes(); i++) {
		if (!PerformQueryRec(*cHierarchyNode.GetNode(i)))
			return false; // Stop the query right now
	}

	// Done, continue the query
	return true;
}