#include "BsRendererUtility.h" #include "BsRenderAPI.h" #include "BsMesh.h" #include "BsVertexDataDesc.h" #include "BsMaterial.h" #include "BsPass.h" #include "BsBlendState.h" #include "BsDepthStencilState.h" #include "BsRasterizerState.h" #include "BsGpuParams.h" #include "BsGpuParamDesc.h" namespace BansheeEngine { RendererUtility::RendererUtility() { VertexDataDescPtr vertexDesc = bs_shared_ptr_new(); vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION); vertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD); mFullScreenQuadMesh = MeshCore::create(4, 6, vertexDesc); } RendererUtility::~RendererUtility() { } void RendererUtility::setPass(const SPtr& material, UINT32 passIdx) { RenderAPICore& rs = RenderAPICore::instance(); SPtr pass = material->getPass(passIdx); SPtr passParams = material->getPassParameters(passIdx); struct StageData { GpuProgramType type; bool enable; SPtr params; SPtr program; }; const UINT32 numStages = 6; StageData stages[numStages] = { { GPT_VERTEX_PROGRAM, pass->hasVertexProgram(), passParams->mVertParams, pass->getVertexProgram() }, { GPT_FRAGMENT_PROGRAM, pass->hasFragmentProgram(), passParams->mFragParams, pass->getFragmentProgram() }, { GPT_GEOMETRY_PROGRAM, pass->hasGeometryProgram(), passParams->mGeomParams, pass->getGeometryProgram() }, { GPT_HULL_PROGRAM, pass->hasHullProgram(), passParams->mHullParams, pass->getHullProgram() }, { GPT_DOMAIN_PROGRAM, pass->hasDomainProgram(), passParams->mDomainParams, pass->getDomainProgram() }, { GPT_COMPUTE_PROGRAM, pass->hasComputeProgram(), passParams->mComputeParams, pass->getComputeProgram() } }; for (UINT32 i = 0; i < numStages; i++) { const StageData& stage = stages[i]; if (stage.enable) { rs.bindGpuProgram(stage.program); rs.setGpuParams(stage.type, stage.params); } else rs.unbindGpuProgram(stage.type); } // Set up non-texture related pass settings if (pass->getBlendState() != nullptr) rs.setBlendState(pass->getBlendState()); else rs.setBlendState(BlendStateCore::getDefault()); if (pass->getDepthStencilState() != nullptr) rs.setDepthStencilState(pass->getDepthStencilState(), pass->getStencilRefValue()); else rs.setDepthStencilState(DepthStencilStateCore::getDefault(), pass->getStencilRefValue()); if (pass->getRasterizerState() != nullptr) rs.setRasterizerState(pass->getRasterizerState()); else rs.setRasterizerState(RasterizerStateCore::getDefault()); } void RendererUtility::setPassParams(const SPtr& material, UINT32 passIdx) { const SPtr& passParams = material->getPassParameters(passIdx); RenderAPICore& rs = RenderAPICore::instance(); struct StageData { GpuProgramType type; SPtr params; }; const UINT32 numStages = 6; StageData stages[numStages] = { { GPT_VERTEX_PROGRAM, passParams->mVertParams }, { GPT_FRAGMENT_PROGRAM, passParams->mFragParams }, { GPT_GEOMETRY_PROGRAM, passParams->mGeomParams }, { GPT_HULL_PROGRAM, passParams->mHullParams }, { GPT_DOMAIN_PROGRAM, passParams->mDomainParams }, { GPT_COMPUTE_PROGRAM, passParams->mComputeParams } }; for (UINT32 i = 0; i < numStages; i++) { const StageData& stage = stages[i]; SPtr params = stage.params; if (params == nullptr) continue; const GpuParamDesc& paramDesc = params->getParamDesc(); for (auto iter = paramDesc.samplers.begin(); iter != paramDesc.samplers.end(); ++iter) { SPtr samplerState = params->getSamplerState(iter->second.slot); if (samplerState == nullptr) rs.setSamplerState(stage.type, iter->second.slot, SamplerStateCore::getDefault()); else rs.setSamplerState(stage.type, iter->second.slot, samplerState); } for (auto iter = paramDesc.textures.begin(); iter != paramDesc.textures.end(); ++iter) { SPtr texture = params->getTexture(iter->second.slot); if (!params->isLoadStoreTexture(iter->second.slot)) { if (texture == nullptr) rs.setTexture(stage.type, iter->second.slot, false, nullptr); else rs.setTexture(stage.type, iter->second.slot, true, texture); } else { const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot); if (texture == nullptr) rs.setLoadStoreTexture(stage.type, iter->second.slot, false, nullptr, surface); else rs.setLoadStoreTexture(stage.type, iter->second.slot, true, texture, surface); } } rs.setConstantBuffers(stage.type, params); } } void RendererUtility::draw(const SPtr& mesh, const SubMesh& subMesh) { RenderAPICore& rs = RenderAPICore::instance(); const MeshProperties& meshProps = mesh->getProperties(); std::shared_ptr vertexData = mesh->getVertexData(); rs.setVertexDeclaration(vertexData->vertexDeclaration); auto& vertexBuffers = vertexData->getBuffers(); if (vertexBuffers.size() > 0) { SPtr buffers[MAX_BOUND_VERTEX_BUFFERS]; UINT32 endSlot = 0; UINT32 startSlot = MAX_BOUND_VERTEX_BUFFERS; for (auto iter = vertexBuffers.begin(); iter != vertexBuffers.end(); ++iter) { if (iter->first >= MAX_BOUND_VERTEX_BUFFERS) BS_EXCEPT(InvalidParametersException, "Buffer index out of range"); startSlot = std::min(iter->first, startSlot); endSlot = std::max(iter->first, endSlot); } for (auto iter = vertexBuffers.begin(); iter != vertexBuffers.end(); ++iter) { buffers[iter->first - startSlot] = iter->second; } rs.setVertexBuffers(startSlot, buffers, endSlot - startSlot + 1); } rs.setDrawOperation(subMesh.drawOp); SPtr indexBuffer = mesh->getIndexBuffer(); UINT32 indexCount = subMesh.indexCount; rs.setIndexBuffer(indexBuffer); rs.drawIndexed(subMesh.indexOffset + mesh->getIndexOffset(), indexCount, mesh->getVertexOffset(), vertexData->vertexCount); mesh->_notifyUsedOnGPU(); } void RendererUtility::drawScreenQuad(const ViewportCore& viewport, const Rect2& uv, const Vector2I& textureSize) { // Note: Consider drawing the quad using a single large triangle for possibly better performance Rect2I viewArea = viewport.getArea(); Vector3 vertices[4]; vertices[0] = Vector3((float)viewArea.x, (float)viewArea.y, 0.0f); vertices[1] = Vector3((float)viewArea.x + (float)viewArea.width, (float)viewArea.y, 0.0f); vertices[2] = Vector3((float)viewArea.x, (float)viewArea.y + (float)viewArea.height, 0.0f); vertices[3] = Vector3((float)viewArea.x + (float)viewArea.width, (float)viewArea.y + (float)viewArea.height, 0.0f); Vector2 uvs[4]; uvs[0] = Vector2(uv.x, uv.y); uvs[1] = Vector2(uv.x + uv.width, uv.y); uvs[2] = Vector2(uv.x, uv.y + uv.height); uvs[3] = Vector2(uv.x + uv.width, uv.y + uv.height); auto targetProps = viewport.getTarget()->getProperties();; RenderAPICore& rapi = RenderAPICore::instance(); for (int i = 0; i < 4; i++) { vertices[i].x = -1.0f + 2.0f * (vertices[i].x + rapi.getHorizontalTexelOffset()) / targetProps.getWidth(); vertices[i].y = 1.0f - 2.0f * (vertices[i].y + rapi.getVerticalTexelOffset()) / targetProps.getHeight(); uvs[i].x /= (float)textureSize.x; uvs[i].y /= (float)textureSize.y; } SPtr vertexDesc = mFullScreenQuadMesh->getVertexDesc(); MeshDataPtr meshData = bs_shared_ptr_new(4, 6, vertexDesc); auto vecIter = meshData->getVec3DataIter(VES_POSITION); for (UINT32 i = 0; i < 4; i++) vecIter.addValue(vertices[i]); auto uvIter = meshData->getVec2DataIter(VES_TEXCOORD); for (UINT32 i = 0; i < 4; i++) uvIter.addValue(uvs[i]); auto indices = meshData->getIndices32(); indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 1; indices[4] = 3; indices[5] = 2; mFullScreenQuadMesh->writeSubresource(0, *meshData, true, false); draw(mFullScreenQuadMesh, mFullScreenQuadMesh->getProperties().getSubMesh()); } RendererUtility& gRendererUtility() { return RendererUtility::instance(); } }