358 lines
11 KiB
C++
358 lines
11 KiB
C++
#include "CRenderer.h"
|
|
|
|
#include "CDrawUtil.h"
|
|
#include "CGraphics.h"
|
|
#include "Core/GameProject/CResourceStore.h"
|
|
#include "Core/Resource/Factory/CTextureDecoder.h"
|
|
#include <Common/Math/CTransform4f.h>
|
|
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <vector>
|
|
#include <sstream>
|
|
|
|
// ************ STATIC MEMBER INITIALIZATION ************
|
|
uint32 CRenderer::sNumRenderers = 0;
|
|
|
|
// ************ INITIALIZATION ************
|
|
CRenderer::CRenderer()
|
|
: mOptions(ERenderOption::EnableUVScroll | ERenderOption::EnableBackfaceCull)
|
|
, mBloomMode(EBloomMode::NoBloom)
|
|
, mDrawGrid(true)
|
|
, mInitialized(false)
|
|
, mContextIndex(-1)
|
|
{
|
|
sNumRenderers++;
|
|
}
|
|
|
|
CRenderer::~CRenderer()
|
|
{
|
|
sNumRenderers--;
|
|
CGraphics::ReleaseContext(mContextIndex);
|
|
|
|
if (sNumRenderers == 0)
|
|
{
|
|
CGraphics::Shutdown();
|
|
CDrawUtil::Shutdown();
|
|
}
|
|
}
|
|
|
|
void CRenderer::Init()
|
|
{
|
|
if (!mInitialized)
|
|
{
|
|
glClearColor(mClearColor.R, mClearColor.G, mClearColor.B, mClearColor.A);
|
|
mContextIndex = CGraphics::GetContextIndex();
|
|
mInitialized = true;
|
|
}
|
|
}
|
|
|
|
// ************ ACCESSORS ************
|
|
FRenderOptions CRenderer::RenderOptions() const
|
|
{
|
|
return mOptions;
|
|
}
|
|
|
|
void CRenderer::ToggleBackfaceCull(bool Enable)
|
|
{
|
|
if (Enable) mOptions |= ERenderOption::EnableBackfaceCull;
|
|
else mOptions &= ~ERenderOption::EnableBackfaceCull;
|
|
}
|
|
|
|
void CRenderer::ToggleUVAnimation(bool Enable)
|
|
{
|
|
if (Enable) mOptions |= ERenderOption::EnableUVScroll;
|
|
else mOptions &= ~ERenderOption::EnableUVScroll;
|
|
}
|
|
|
|
void CRenderer::ToggleGrid(bool Enable)
|
|
{
|
|
mDrawGrid = Enable;
|
|
}
|
|
|
|
void CRenderer::ToggleOccluders(bool Enable)
|
|
{
|
|
if (Enable) mOptions |= ERenderOption::EnableOccluders;
|
|
else mOptions &= ~ERenderOption::EnableOccluders;
|
|
}
|
|
|
|
void CRenderer::ToggleAlphaDisabled(bool Enable)
|
|
{
|
|
if (Enable) mOptions |= ERenderOption::NoAlpha;
|
|
else mOptions &= ~ERenderOption::NoAlpha;
|
|
}
|
|
|
|
void CRenderer::SetBloom(EBloomMode BloomMode)
|
|
{
|
|
mBloomMode = BloomMode;
|
|
|
|
if (BloomMode != EBloomMode::NoBloom)
|
|
mOptions |= ERenderOption::EnableBloom;
|
|
else
|
|
mOptions &= ~ERenderOption::EnableBloom;
|
|
}
|
|
|
|
void CRenderer::SetClearColor(const CColor& rkClear)
|
|
{
|
|
mClearColor = rkClear;
|
|
mClearColor.A = 0.f;
|
|
glClearColor(mClearColor.R, mClearColor.G, mClearColor.B, mClearColor.A);
|
|
}
|
|
|
|
void CRenderer::SetViewportSize(uint32 Width, uint32 Height)
|
|
{
|
|
mViewportWidth = Width;
|
|
mViewportHeight = Height;
|
|
mBloomHScale = ((float) Width / 640);
|
|
mBloomVScale = ((float) Height / 528);
|
|
mBloomWidth = (uint32) (320 * mBloomHScale);
|
|
mBloomHeight = (uint32) (224 * mBloomVScale);
|
|
mBloomHScale = 1.f / mBloomHScale;
|
|
mBloomVScale = 1.f / mBloomVScale;
|
|
}
|
|
|
|
// ************ RENDER ************
|
|
void CRenderer::RenderBuckets(const SViewInfo& rkViewInfo)
|
|
{
|
|
if (!mInitialized) Init();
|
|
mSceneFramebuffer.Bind();
|
|
|
|
// Set backface culling
|
|
if (mOptions & ERenderOption::EnableBackfaceCull) glEnable(GL_CULL_FACE);
|
|
else glDisable(GL_CULL_FACE);
|
|
|
|
// Render scene to texture
|
|
glDepthRange(0.f, 1.f);
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
|
|
mBackgroundBucket.Draw(rkViewInfo);
|
|
mBackgroundBucket.Clear();
|
|
ClearDepthBuffer();
|
|
mMidgroundBucket.Draw(rkViewInfo);
|
|
mMidgroundBucket.Clear();
|
|
ClearDepthBuffer();
|
|
RenderBloom();
|
|
ClearDepthBuffer();
|
|
rkViewInfo.pCamera->LoadMatrices();
|
|
mForegroundBucket.Draw(rkViewInfo);
|
|
mForegroundBucket.Clear();
|
|
ClearDepthBuffer();
|
|
mUIBucket.Draw(rkViewInfo);
|
|
mUIBucket.Clear();
|
|
ClearDepthBuffer();
|
|
}
|
|
|
|
void CRenderer::RenderBloom()
|
|
{
|
|
// Check to ensure bloom is enabled. Also don't render bloom in unlit mode.
|
|
if (mBloomMode == EBloomMode::NoBloom || CGraphics::sLightMode != CGraphics::ELightingMode::World) return;
|
|
|
|
// Setup
|
|
static const float skHOffset[6] = { -0.008595f, -0.005470f, -0.002345f,
|
|
0.002345f, 0.005470f, 0.008595f };
|
|
|
|
static const float skVOffset[6] = { -0.012275f, -0.007815f, -0.003350f,
|
|
0.003350f, 0.007815f, 0.012275f };
|
|
|
|
static const CColor skTintColors[6] = { CColor::Integral(17, 17, 17),
|
|
CColor::Integral(53, 53, 53),
|
|
CColor::Integral(89, 89, 89),
|
|
CColor::Integral(89, 89, 89),
|
|
CColor::Integral(53, 53, 53),
|
|
CColor::Integral(17, 17, 17) };
|
|
|
|
uint32 BloomWidth = (mBloomMode == EBloomMode::Bloom ? mBloomWidth : mViewportWidth);
|
|
uint32 BloomHeight = (mBloomMode == EBloomMode::Bloom ? mBloomHeight : mViewportHeight);
|
|
float BloomHScale = (mBloomMode == EBloomMode::Bloom ? mBloomHScale : 0);
|
|
float BloomVScale = (mBloomMode == EBloomMode::Bloom ? mBloomVScale : 0);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
glViewport(0, 0, BloomWidth, BloomHeight);
|
|
glClearColor(0.f, 0.f, 0.f, 0.f);
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
glDepthMask(GL_FALSE);
|
|
|
|
CGraphics::SetIdentityMVP();
|
|
CGraphics::UpdateMVPBlock();
|
|
|
|
mPostProcessFramebuffer.Resize(mViewportWidth, mViewportHeight);
|
|
mSceneFramebuffer.Bind(GL_READ_FRAMEBUFFER);
|
|
mPostProcessFramebuffer.Bind(GL_DRAW_FRAMEBUFFER);
|
|
glBlitFramebuffer(0, 0, mViewportWidth, mViewportHeight, 0, 0, mViewportWidth, mViewportHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
|
|
// Pass 1: Alpha-blend the scene texture on a black background
|
|
mBloomFramebuffers[0].Resize(BloomWidth, BloomHeight);
|
|
mBloomFramebuffers[0].Bind();
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
CDrawUtil::UseTextureShader();
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
|
|
mPostProcessFramebuffer.Texture()->Bind(0);
|
|
CDrawUtil::DrawSquare();
|
|
|
|
// Pass 2: Horizontal blur
|
|
mBloomFramebuffers[1].Resize(BloomWidth, BloomHeight);
|
|
mBloomFramebuffers[1].Bind();
|
|
|
|
CDrawUtil::UseTextureShader(CColor::skGray);
|
|
glBlendFunc(GL_ONE, GL_ZERO);
|
|
mBloomFramebuffers[0].Texture()->Bind(0);
|
|
CDrawUtil::DrawSquare();
|
|
|
|
for (uint32 iPass = 0; iPass < 6; iPass++)
|
|
{
|
|
CDrawUtil::UseTextureShader(skTintColors[iPass]);
|
|
CVector3f Translate(skHOffset[iPass] * BloomHScale, 0.f, 0.f);
|
|
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate);
|
|
CGraphics::UpdateMVPBlock();
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
CDrawUtil::DrawSquare();
|
|
}
|
|
|
|
// Pass 3: Vertical blur
|
|
mBloomFramebuffers[2].Resize(BloomWidth, BloomHeight);
|
|
mBloomFramebuffers[2].Bind();
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
CDrawUtil::UseTextureShader(CColor::skGray);
|
|
glBlendFunc(GL_ONE, GL_ZERO);
|
|
mBloomFramebuffers[1].Texture()->Bind(0);
|
|
CDrawUtil::DrawSquare();
|
|
|
|
for (uint32 iPass = 0; iPass < 6; iPass++)
|
|
{
|
|
CDrawUtil::UseTextureShader(skTintColors[iPass]);
|
|
CVector3f Translate(0.f, skVOffset[iPass] * BloomVScale, 0.f);
|
|
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate);
|
|
CGraphics::UpdateMVPBlock();
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
CDrawUtil::DrawSquare();
|
|
}
|
|
|
|
// Render result onto main scene framebuffer
|
|
mPostProcessFramebuffer.Bind();
|
|
glViewport(0, 0, mViewportWidth, mViewportHeight);
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
|
|
|
|
CGraphics::SetIdentityMVP();
|
|
CGraphics::UpdateMVPBlock();
|
|
|
|
CDrawUtil::UseTextureShader();
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
mBloomFramebuffers[2].Texture()->Bind(0);
|
|
CDrawUtil::DrawSquare();
|
|
|
|
if (mBloomMode == EBloomMode::BloomMaps)
|
|
{
|
|
// Bloom maps are in the framebuffer alpha channel.
|
|
// White * dst alpha = bloom map colors
|
|
CDrawUtil::UseColorShader(CColor::skWhite);
|
|
glBlendFunc(GL_DST_ALPHA, GL_ZERO);
|
|
CDrawUtil::DrawSquare();
|
|
}
|
|
|
|
// Copy framebuffer back into the scene framebuffer for more rendering
|
|
mPostProcessFramebuffer.Bind(GL_READ_FRAMEBUFFER);
|
|
mSceneFramebuffer.Bind(GL_DRAW_FRAMEBUFFER);
|
|
glBlitFramebuffer(0, 0, mViewportWidth, mViewportHeight, 0, 0, mViewportWidth, mViewportHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
|
|
// Clean up
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
void CRenderer::RenderSky(CModel *pSkyboxModel, const SViewInfo& rkViewInfo)
|
|
{
|
|
if (!mInitialized) Init();
|
|
if (!pSkyboxModel) return;
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
|
|
CGraphics::sVertexBlock.COLOR0_Amb = CColor::skWhite;
|
|
CGraphics::sPixelBlock.SetAllTevColors(CColor::skWhite);
|
|
CGraphics::sPixelBlock.TintColor = CColor::skWhite;
|
|
CGraphics::sNumLights = 0;
|
|
CGraphics::UpdateVertexBlock();
|
|
CGraphics::UpdatePixelBlock();
|
|
CGraphics::UpdateLightBlock();
|
|
|
|
// Load rotation-only view matrix
|
|
CGraphics::sMVPBlock.ViewMatrix = rkViewInfo.RotationOnlyViewMatrix;
|
|
CGraphics::UpdateMVPBlock();
|
|
|
|
glDepthRange(1.f, 1.f);
|
|
pSkyboxModel->Draw(mOptions, 0);
|
|
}
|
|
|
|
void CRenderer::AddMesh(IRenderable *pRenderable, int ComponentIndex, const CAABox& rkAABox, bool Transparent, ERenderCommand Command, EDepthGroup DepthGroup /*= eMidground*/)
|
|
{
|
|
SRenderablePtr Ptr;
|
|
Ptr.pRenderable = pRenderable;
|
|
Ptr.ComponentIndex = ComponentIndex;
|
|
Ptr.AABox = rkAABox;
|
|
Ptr.Command = Command;
|
|
|
|
switch (DepthGroup)
|
|
{
|
|
case EDepthGroup::Background:
|
|
mBackgroundBucket.Add(Ptr, Transparent);
|
|
break;
|
|
|
|
case EDepthGroup::Midground:
|
|
mMidgroundBucket.Add(Ptr, Transparent);
|
|
break;
|
|
|
|
case EDepthGroup::Foreground:
|
|
mForegroundBucket.Add(Ptr, Transparent);
|
|
break;
|
|
|
|
case EDepthGroup::UI:
|
|
mUIBucket.Add(Ptr, Transparent);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CRenderer::BeginFrame()
|
|
{
|
|
if (!mInitialized) Init();
|
|
|
|
CGraphics::SetActiveContext(mContextIndex);
|
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mDefaultFramebuffer);
|
|
|
|
mSceneFramebuffer.SetMultisamplingEnabled(true);
|
|
mSceneFramebuffer.Resize(mViewportWidth, mViewportHeight);
|
|
mSceneFramebuffer.Bind();
|
|
|
|
glViewport(0, 0, mViewportWidth, mViewportHeight);
|
|
|
|
InitFramebuffer();
|
|
}
|
|
|
|
void CRenderer::EndFrame()
|
|
{
|
|
// Copy result to the backbuffer
|
|
mSceneFramebuffer.Bind(GL_READ_FRAMEBUFFER);
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDefaultFramebuffer);
|
|
glViewport(0, 0, mViewportWidth, mViewportHeight);
|
|
glBlitFramebuffer(0, 0, mViewportWidth, mViewportHeight, 0, 0, mViewportWidth, mViewportHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
gDrawCount = 0;
|
|
}
|
|
|
|
void CRenderer::ClearDepthBuffer()
|
|
{
|
|
glDepthMask(GL_TRUE);
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
}
|
|
|
|
// ************ PRIVATE ************
|
|
void CRenderer::InitFramebuffer()
|
|
{
|
|
glClearColor(mClearColor.R, mClearColor.G, mClearColor.B, mClearColor.A);
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
glDepthMask(GL_TRUE);
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
}
|
|
|
|
uint32 gDrawCount;
|