Refactored framebuffer implementations
parent
94851c2694
commit
7d57ec634e
|
@ -98,6 +98,7 @@ set(BASE_SOURCES
|
|||
common/resources/sndfile.cpp
|
||||
graphics/core/color.cpp
|
||||
graphics/core/nulldevice.cpp
|
||||
graphics/core/framebuffer.cpp
|
||||
graphics/engine/camera.cpp
|
||||
graphics/engine/cloud.cpp
|
||||
graphics/engine/engine.cpp
|
||||
|
@ -115,6 +116,7 @@ set(BASE_SOURCES
|
|||
graphics/opengl/gl21device.cpp
|
||||
graphics/opengl/gl33device.cpp
|
||||
graphics/opengl/glutil.cpp
|
||||
graphics/opengl/glframebuffer.cpp
|
||||
object/auto/auto.cpp
|
||||
object/auto/autobase.cpp
|
||||
object/auto/autoconvert.cpp
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "graphics/core/material.h"
|
||||
#include "graphics/core/texture.h"
|
||||
#include "graphics/core/vertex.h"
|
||||
#include "graphics/core/framebuffer.h"
|
||||
|
||||
#include "math/intpoint.h"
|
||||
#include "math/matrix.h"
|
||||
|
@ -75,6 +76,8 @@ struct DeviceConfig
|
|||
int alphaSize;
|
||||
//! Color depth in bits
|
||||
int depthSize;
|
||||
//! Stencil depth in bits
|
||||
int stencilSize;
|
||||
|
||||
//! Force hardware acceleration (video mode set will fail on lack of hw accel)
|
||||
bool hardwareAccel;
|
||||
|
@ -99,6 +102,7 @@ struct DeviceConfig
|
|||
greenSize = 8;
|
||||
alphaSize = 8;
|
||||
depthSize = 24;
|
||||
stencilSize = 8;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -131,7 +135,6 @@ enum RenderState
|
|||
RENDER_STATE_ALPHA_TEST,
|
||||
RENDER_STATE_CULLING,
|
||||
RENDER_STATE_DEPTH_BIAS,
|
||||
RENDER_STATE_OFFSCREEN_RENDERING
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -418,17 +421,20 @@ public:
|
|||
//! Sets the current fill mode
|
||||
virtual void SetFillMode(FillMode mode) = 0;
|
||||
|
||||
//! Initializes offscreen buffer
|
||||
virtual void InitOffscreenBuffer(int width, int height) = 0;
|
||||
|
||||
//! Sets render target to texture
|
||||
virtual void SetRenderTexture(RenderTarget target, int texture) = 0;
|
||||
|
||||
//! Copies content of framebuffer to texture
|
||||
virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) = 0;
|
||||
|
||||
//! Returns the pixels of the entire screen
|
||||
virtual void* GetFrameBufferPixels() const = 0;
|
||||
|
||||
//! Returns framebuffer with given name or nullptr if it doesn't exist
|
||||
virtual CFramebuffer* GetFramebuffer(std::string name) = 0;
|
||||
|
||||
//! Creates new framebuffer with given name or nullptr if it's not possible
|
||||
virtual CFramebuffer* CreateFramebuffer(std::string name, const FramebufferParams& params) = 0;
|
||||
|
||||
//! Deletes framebuffer
|
||||
virtual void DeleteFramebuffer(std::string name) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* This file is part of the Colobot: Gold Edition source code
|
||||
* Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||
* http://epsite?.ch; http://colobot.info; http://github.com/colobot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see http://gnu.org/licenses
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file graphics/core/framebuffer.h
|
||||
* \brief Abstract representation of framebuffer and offscreen buffers
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "graphics/core/framebuffer.h"
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
CDefaultFramebuffer::CDefaultFramebuffer(const FramebufferParams& params)
|
||||
: m_width(params.width), m_height(params.height), m_depth(params.depth)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CDefaultFramebuffer::Create()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CDefaultFramebuffer::Destroy()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CDefaultFramebuffer::IsDefault()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Returns width of buffers in this framebuffer
|
||||
int CDefaultFramebuffer::GetWidth()
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
//! Returns height of buffers in this framebuffer
|
||||
int CDefaultFramebuffer::GetHeight()
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
//! Returns depth size in bits
|
||||
int CDefaultFramebuffer::GetDepth()
|
||||
{
|
||||
return m_depth;
|
||||
}
|
||||
|
||||
//! Returns number of samples or 1 if multisampling is not supported
|
||||
int CDefaultFramebuffer::GetSamples()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
//! Returns texture that contains color buffer or 0 if not available
|
||||
int CDefaultFramebuffer::GetColorTexture()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Returns texture that contains depth buffer or 0 if not available
|
||||
int CDefaultFramebuffer::GetDepthTexture()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Binds this framebuffer to context
|
||||
void CDefaultFramebuffer::Bind()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//! Unbinds this framebuffer from context
|
||||
void CDefaultFramebuffer::Unbind()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // end of Gfx
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* This file is part of the Colobot: Gold Edition source code
|
||||
* Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||
* http://epsite?.ch; http://colobot.info; http://github.com/colobot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see http://gnu.org/licenses
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file graphics/core/framebuffer.h
|
||||
* \brief Abstract representation of framebuffer and offscreen buffers
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
/**
|
||||
* \struct FramebufferParams
|
||||
* \brief Contains parameters for new framebuffer
|
||||
*/
|
||||
struct FramebufferParams
|
||||
{
|
||||
//! Requested width of buffers
|
||||
int width;
|
||||
//! Requested height of buffers
|
||||
int height;
|
||||
//! Requested depth buffer
|
||||
int depth;
|
||||
//! Requested number of samples for multisampling
|
||||
int samples;
|
||||
//! true requests color texture
|
||||
bool colorTexture;
|
||||
//! true requests depth texture
|
||||
bool depthTexture;
|
||||
|
||||
|
||||
//! Initializes
|
||||
FramebufferParams()
|
||||
{
|
||||
LoadDefault();
|
||||
}
|
||||
|
||||
//! Loads default values
|
||||
void LoadDefault()
|
||||
{
|
||||
width = 1024;
|
||||
height = 1024;
|
||||
depth = 16;
|
||||
samples = 1;
|
||||
colorTexture = false;
|
||||
depthTexture = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \class CFramebuffer
|
||||
* \brief Abstract interface of default framebuffer and offscreen framebuffers
|
||||
*
|
||||
* This code encapsulates basics of default framebuffer and offscreen buffers
|
||||
* and allows offscreen rendering in generic way. CDevice may or may not implement
|
||||
* offscreen buffers depending on available hardware but is required to provide
|
||||
* default framebuffer implementation. Because of some hardware restrictions
|
||||
* and in order to simplify interface, you can't bind/unbind textures from
|
||||
* offscreen buffers and you can't change it's parameters.
|
||||
*/
|
||||
class CFramebuffer
|
||||
{
|
||||
public:
|
||||
//! Creates this framebuffer
|
||||
virtual void Create() = 0;
|
||||
|
||||
//! Destroys this framebuffer
|
||||
virtual void Destroy() = 0;
|
||||
|
||||
//! Returns true if this is default framebuffer
|
||||
virtual bool IsDefault() = 0;
|
||||
|
||||
//! Returns width of buffers in this framebuffer
|
||||
virtual int GetWidth() = 0;
|
||||
|
||||
//! Returns height of buffers in this framebuffer
|
||||
virtual int GetHeight() = 0;
|
||||
|
||||
//! Returns depth size in bits
|
||||
virtual int GetDepth() = 0;
|
||||
|
||||
//! Returns number of samples or 1 if multisampling is not supported
|
||||
virtual int GetSamples() = 0;
|
||||
|
||||
//! Returns texture that contains color buffer or 0 if not available
|
||||
virtual int GetColorTexture() = 0;
|
||||
|
||||
//! Returns texture that contains depth buffer or 0 if not available
|
||||
virtual int GetDepthTexture() = 0;
|
||||
|
||||
//! Binds this framebuffer to context
|
||||
virtual void Bind() = 0;
|
||||
|
||||
//! Unbinds this framebuffer from context
|
||||
virtual void Unbind() = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \class CDefaultFramebuffer
|
||||
* \brief Concrete implementation of default framebuffer.
|
||||
*
|
||||
* This class represents default framebuffer implementation.
|
||||
*/
|
||||
class CDefaultFramebuffer : public CFramebuffer
|
||||
{
|
||||
private:
|
||||
int m_width, m_height, m_depth;
|
||||
|
||||
public:
|
||||
explicit CDefaultFramebuffer(const FramebufferParams ¶ms);
|
||||
|
||||
//! Creates default framebuffer
|
||||
virtual void Create() OVERRIDE;
|
||||
|
||||
//! Destroys default framebuffer
|
||||
virtual void Destroy() OVERRIDE;
|
||||
|
||||
//! Returns true
|
||||
virtual bool IsDefault() OVERRIDE;
|
||||
|
||||
//! Returns width of buffers in this framebuffer
|
||||
virtual int GetWidth() OVERRIDE;
|
||||
|
||||
//! Returns height of buffers in this framebuffer
|
||||
virtual int GetHeight() OVERRIDE;
|
||||
|
||||
//! Returns depth size in bits
|
||||
virtual int GetDepth() OVERRIDE;
|
||||
|
||||
//! Returns number of samples or 1 if multisampling is not supported
|
||||
virtual int GetSamples() OVERRIDE;
|
||||
|
||||
//! Returns texture that contains color buffer or 0 if not available
|
||||
virtual int GetColorTexture() OVERRIDE;
|
||||
|
||||
//! Returns texture that contains depth buffer or 0 if not available
|
||||
virtual int GetDepthTexture() OVERRIDE;
|
||||
|
||||
//! Binds this framebuffer to context
|
||||
virtual void Bind() OVERRIDE;
|
||||
|
||||
//! Unbinds this framebuffer from context
|
||||
virtual void Unbind() OVERRIDE;
|
||||
};
|
||||
|
||||
} // end of Gfx
|
|
@ -359,14 +359,6 @@ FillMode CNullDevice::GetFillMode()
|
|||
return FILL_POINT;
|
||||
}
|
||||
|
||||
void CNullDevice::InitOffscreenBuffer(int width, int height)
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDevice::SetRenderTexture(RenderTarget target, int texture)
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDevice::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
|
||||
{
|
||||
}
|
||||
|
@ -376,6 +368,19 @@ void* CNullDevice::GetFrameBufferPixels() const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CFramebuffer* CNullDevice::GetFramebuffer(std::string name)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CFramebuffer* CNullDevice::CreateFramebuffer(std::string name, const FramebufferParams& params)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CNullDevice::DeleteFramebuffer(std::string name)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
||||
|
||||
|
|
|
@ -142,13 +142,15 @@ public:
|
|||
virtual void SetFillMode(FillMode mode) ;
|
||||
virtual FillMode GetFillMode();
|
||||
|
||||
virtual void InitOffscreenBuffer(int width, int height);
|
||||
|
||||
virtual void SetRenderTexture(RenderTarget target, int texture);
|
||||
|
||||
virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height);
|
||||
|
||||
virtual void* GetFrameBufferPixels() const;
|
||||
|
||||
virtual CFramebuffer* GetFramebuffer(std::string name);
|
||||
|
||||
virtual CFramebuffer* CreateFramebuffer(std::string name, const FramebufferParams& params);
|
||||
|
||||
virtual void DeleteFramebuffer(std::string name);
|
||||
|
||||
private:
|
||||
Math::Matrix m_matrix;
|
||||
|
|
|
@ -3527,6 +3527,24 @@ void CEngine::RenderShadowMap()
|
|||
{
|
||||
width = height = 1024;
|
||||
}
|
||||
|
||||
FramebufferParams params;
|
||||
params.width = params.height = width;
|
||||
params.depth = depth;
|
||||
params.depthTexture = true;
|
||||
|
||||
CFramebuffer *framebuffer = m_device->CreateFramebuffer("shadow", params);
|
||||
if (framebuffer == nullptr)
|
||||
{
|
||||
GetLogger()->Error("Could not create framebuffer, disabling shadows\n");
|
||||
m_shadowMapping = false;
|
||||
m_offscreenShadowRendering = false;
|
||||
m_qualityShadows = false;
|
||||
return;
|
||||
}
|
||||
|
||||
m_shadowMap.id = framebuffer->GetDepthTexture();
|
||||
m_shadowMap.size = Math::IntPoint(width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3538,13 +3556,8 @@ void CEngine::RenderShadowMap()
|
|||
|
||||
width = height = 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
m_shadowMap = m_device->CreateDepthTexture(width, height, depth);
|
||||
|
||||
if (m_offscreenShadowRendering)
|
||||
{
|
||||
m_device->InitOffscreenBuffer(width, height);
|
||||
m_shadowMap = m_device->CreateDepthTexture(width, height, depth);
|
||||
}
|
||||
|
||||
GetLogger()->Info("Created shadow map texture: %dx%d, depth %d\n", width, height, depth);
|
||||
|
@ -3552,8 +3565,7 @@ void CEngine::RenderShadowMap()
|
|||
|
||||
if (m_offscreenShadowRendering)
|
||||
{
|
||||
m_device->SetRenderState(RENDER_STATE_OFFSCREEN_RENDERING, true);
|
||||
m_device->SetRenderTexture(RENDER_TARGET_DEPTH, m_shadowMap.id);
|
||||
m_device->GetFramebuffer("shadow")->Bind();
|
||||
}
|
||||
|
||||
m_device->Clear();
|
||||
|
@ -3666,8 +3678,7 @@ void CEngine::RenderShadowMap()
|
|||
|
||||
if (m_offscreenShadowRendering) // shadow map texture already have depth information, just unbind it
|
||||
{
|
||||
m_device->SetRenderTexture(RENDER_TARGET_DEPTH, 0);
|
||||
m_device->SetRenderState(RENDER_STATE_OFFSCREEN_RENDERING, false);
|
||||
m_device->GetFramebuffer("shadow")->Unbind();
|
||||
}
|
||||
else // copy depth buffer to shadow map
|
||||
{
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
|
||||
#include "graphics/opengl/gl21device.h"
|
||||
#include "graphics/opengl/glframebuffer.h"
|
||||
#include "graphics/engine/engine.h"
|
||||
|
||||
#include "common/config.h"
|
||||
|
@ -48,11 +49,6 @@ CGL21Device::CGL21Device(const DeviceConfig &config)
|
|||
m_glMajor = 1;
|
||||
m_glMinor = 1;
|
||||
|
||||
m_framebuffer = 0;
|
||||
m_colorBuffer = 0;
|
||||
m_depthBuffer = 0;
|
||||
m_offscreenRenderingEnabled = false;
|
||||
|
||||
m_perPixelLighting = false;
|
||||
}
|
||||
|
||||
|
@ -199,15 +195,6 @@ bool CGL21Device::Create()
|
|||
|
||||
GetLogger()->Info("OpenGL %d.%d\n", m_glMajor, m_glMinor);
|
||||
|
||||
m_framebufferObject = glewIsSupported("GL_EXT_framebuffer_object");
|
||||
if (m_framebufferObject)
|
||||
{
|
||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &m_maxRenderbufferSize);
|
||||
|
||||
GetLogger()->Info("Offscreen rendering available\n");
|
||||
GetLogger()->Info("Maximum renderbuffer size: %d\n", m_maxRenderbufferSize);
|
||||
}
|
||||
|
||||
// Detect support of anisotropic filtering
|
||||
m_anisotropyAvailable = glewIsSupported("GL_EXT_texture_filter_anisotropic");
|
||||
if(m_anisotropyAvailable)
|
||||
|
@ -356,6 +343,19 @@ bool CGL21Device::Create()
|
|||
for (int i = 0; i < 8; i++)
|
||||
glUniform1i(uni_LightEnabled[i], 0);
|
||||
|
||||
// create default framebuffer object
|
||||
FramebufferParams framebufferParams;
|
||||
|
||||
framebufferParams.width = m_config.size.x;
|
||||
framebufferParams.height = m_config.size.y;
|
||||
framebufferParams.depth = m_config.depthSize;
|
||||
|
||||
m_framebuffers["default"] = new CDefaultFramebuffer(framebufferParams);
|
||||
|
||||
m_framebufferSupport = DetectFramebufferSupport();
|
||||
if (m_framebufferSupport != FBS_NONE)
|
||||
GetLogger()->Debug("Framebuffer supported\n");
|
||||
|
||||
GetLogger()->Info("CDevice created successfully\n");
|
||||
|
||||
return true;
|
||||
|
@ -368,6 +368,15 @@ void CGL21Device::Destroy()
|
|||
glUseProgram(0);
|
||||
glDeleteProgram(m_program);
|
||||
|
||||
// delete framebuffers
|
||||
for (std::map<std::string, CFramebuffer*>::iterator i = m_framebuffers.begin(); i != m_framebuffers.end(); i++)
|
||||
{
|
||||
i->second->Destroy();
|
||||
delete i->second;
|
||||
}
|
||||
|
||||
m_framebuffers.clear();
|
||||
|
||||
DestroyAllTextures();
|
||||
|
||||
m_lights.clear();
|
||||
|
@ -1561,25 +1570,6 @@ void CGL21Device::SetRenderState(RenderState state, bool enabled)
|
|||
|
||||
return;
|
||||
}
|
||||
else if (state == RENDER_STATE_OFFSCREEN_RENDERING)
|
||||
{
|
||||
if (!m_framebufferObject)
|
||||
{
|
||||
GetLogger()->Error("Cannot enable offscreen rendering without framebuffer object!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
m_offscreenRenderingEnabled = enabled;
|
||||
|
||||
if (m_framebuffer == 0)
|
||||
InitOffscreenBuffer(2048, 2048);
|
||||
|
||||
GLuint toBind = (enabled ? m_framebuffer : 0);
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, toBind);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (state == RENDER_STATE_ALPHA_TEST)
|
||||
{
|
||||
glUniform1i(uni_AlphaTestEnabled, enabled ? 1 : 0);
|
||||
|
@ -1693,79 +1683,6 @@ void CGL21Device::SetFillMode(FillMode mode)
|
|||
else assert(false);
|
||||
}
|
||||
|
||||
void CGL21Device::InitOffscreenBuffer(int width, int height)
|
||||
{
|
||||
if (!m_framebufferObject) return;
|
||||
|
||||
width = Math::Min(width, m_maxRenderbufferSize);
|
||||
height = Math::Min(height, m_maxRenderbufferSize);
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
if (m_colorBuffer != 0)
|
||||
glDeleteRenderbuffersEXT(1, &m_colorBuffer);
|
||||
|
||||
glGenRenderbuffersEXT(1, &m_colorBuffer);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_colorBuffer);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, width, height);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
|
||||
if (m_depthBuffer != 0)
|
||||
glDeleteRenderbuffersEXT(1, &m_depthBuffer);
|
||||
|
||||
glGenRenderbuffersEXT(1, &m_depthBuffer);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
|
||||
if (m_framebuffer == 0)
|
||||
glGenFramebuffersEXT(1, &m_framebuffer);
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_framebuffer);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_colorBuffer);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer);
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
GetLogger()->Info("Initialized offscreen buffer %dx%d\n", width, height);
|
||||
}
|
||||
|
||||
void CGL21Device::SetRenderTexture(RenderTarget target, int texture)
|
||||
{
|
||||
if (!m_framebufferObject) return;
|
||||
if (!m_offscreenRenderingEnabled) return;
|
||||
|
||||
GLenum attachment;
|
||||
GLuint defaultBuffer;
|
||||
|
||||
switch (target)
|
||||
{
|
||||
case RENDER_TARGET_COLOR:
|
||||
attachment = GL_COLOR_ATTACHMENT0_EXT;
|
||||
defaultBuffer = m_colorBuffer;
|
||||
break;
|
||||
case RENDER_TARGET_DEPTH:
|
||||
attachment = GL_DEPTH_ATTACHMENT_EXT;
|
||||
defaultBuffer = m_depthBuffer;
|
||||
break;
|
||||
case RENDER_TARGET_STENCIL:
|
||||
attachment = GL_STENCIL_ATTACHMENT_EXT;
|
||||
defaultBuffer = 0;
|
||||
break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
|
||||
if (texture == 0) // unbind texture and bind default buffer
|
||||
{
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_2D, 0, 0);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, defaultBuffer);
|
||||
}
|
||||
else // unbind default buffer and bind texture
|
||||
{
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, 0);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_2D, texture, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void CGL21Device::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
|
||||
{
|
||||
if (texture.id == 0) return;
|
||||
|
@ -1794,4 +1711,53 @@ void* CGL21Device::GetFrameBufferPixels()const{
|
|||
return static_cast<void*>(p);
|
||||
}
|
||||
|
||||
CFramebuffer* CGL21Device::GetFramebuffer(std::string name)
|
||||
{
|
||||
if (m_framebuffers.find(name) != m_framebuffers.end())
|
||||
return m_framebuffers[name];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CFramebuffer* CGL21Device::CreateFramebuffer(std::string name, const FramebufferParams& params)
|
||||
{
|
||||
// existing framebuffer was found
|
||||
if (m_framebuffers.find(name) != m_framebuffers.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
CFramebuffer *framebuffer;
|
||||
|
||||
if (m_framebufferSupport == FBS_ARB)
|
||||
framebuffer = new CGLFramebuffer(params);
|
||||
else if (m_framebufferSupport == FBS_EXT)
|
||||
framebuffer = new CGLFramebufferEXT(params);
|
||||
else
|
||||
return nullptr;
|
||||
|
||||
framebuffer->Create();
|
||||
|
||||
m_framebuffers[name] = framebuffer;
|
||||
return framebuffer;
|
||||
}
|
||||
}
|
||||
|
||||
void CGL21Device::DeleteFramebuffer(std::string name)
|
||||
{
|
||||
// can't delete default framebuffer
|
||||
if (name == "default") return;
|
||||
|
||||
auto position = m_framebuffers.find(name);
|
||||
|
||||
if (position != m_framebuffers.end())
|
||||
{
|
||||
position->second->Destroy();
|
||||
delete position->second;
|
||||
|
||||
m_framebuffers.erase(position);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
||||
|
|
|
@ -137,14 +137,16 @@ public:
|
|||
|
||||
virtual void SetFillMode(FillMode mode) OVERRIDE;
|
||||
|
||||
virtual void InitOffscreenBuffer(int width, int height) OVERRIDE;
|
||||
|
||||
virtual void SetRenderTexture(RenderTarget target, int texture) OVERRIDE;
|
||||
|
||||
virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) OVERRIDE;
|
||||
|
||||
virtual void* GetFrameBufferPixels() const OVERRIDE;
|
||||
|
||||
virtual CFramebuffer* GetFramebuffer(std::string name) OVERRIDE;
|
||||
|
||||
virtual CFramebuffer* CreateFramebuffer(std::string name, const FramebufferParams& params) OVERRIDE;
|
||||
|
||||
virtual void DeleteFramebuffer(std::string name) OVERRIDE;
|
||||
|
||||
private:
|
||||
//! Updates position for given light based on transformation matrices
|
||||
void UpdateLightPosition(int index);
|
||||
|
@ -188,6 +190,9 @@ private:
|
|||
//! Set of all created textures
|
||||
std::set<Texture> m_allTextures;
|
||||
|
||||
//! Map of framebuffers
|
||||
std::map<std::string, CFramebuffer*> m_framebuffers;
|
||||
|
||||
//! Type of vertex structure
|
||||
enum VertexType
|
||||
{
|
||||
|
@ -215,6 +220,8 @@ private:
|
|||
int m_maxAnisotropy;
|
||||
//! Whether offscreen rendering is available
|
||||
bool m_framebufferObject;
|
||||
//! Framebuffer support
|
||||
FramebufferSupport m_framebufferSupport;
|
||||
//! Map of saved VBO objects
|
||||
std::map<unsigned int, VboObjectInfo> m_vboObjects;
|
||||
//! Last ID of VBO object
|
||||
|
@ -222,18 +229,6 @@ private:
|
|||
//! Currently bound VBO
|
||||
GLuint m_currentVBO;
|
||||
|
||||
// Offscreen buffer
|
||||
//! Framebuffer object
|
||||
GLuint m_framebuffer;
|
||||
//! Color renderbuffer
|
||||
GLuint m_colorBuffer;
|
||||
//! Depth renderbuffer
|
||||
GLuint m_depthBuffer;
|
||||
//! Maximum available renderbuffer size
|
||||
int m_maxRenderbufferSize;
|
||||
//! true if offscreen rendering enabled
|
||||
bool m_offscreenRenderingEnabled;
|
||||
|
||||
//! true enables per-pixel lighting
|
||||
bool m_perPixelLighting;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "graphics/opengl/gl33device.h"
|
||||
#include "graphics/opengl/glframebuffer.h"
|
||||
#include "graphics/engine/engine.h"
|
||||
|
||||
#include "common/config.h"
|
||||
|
@ -47,11 +48,6 @@ CGL33Device::CGL33Device(const DeviceConfig &config)
|
|||
m_glMajor = 1;
|
||||
m_glMinor = 1;
|
||||
|
||||
m_framebuffer = 0;
|
||||
m_colorBuffer = 0;
|
||||
m_depthBuffer = 0;
|
||||
m_offscreenRenderingEnabled = false;
|
||||
|
||||
m_perPixelLighting = false;
|
||||
}
|
||||
|
||||
|
@ -205,9 +201,6 @@ bool CGL33Device::Create()
|
|||
GetLogger()->Info("OpenGL %d.%d\n", m_glMajor, m_glMinor);
|
||||
}
|
||||
|
||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
|
||||
GetLogger()->Info("Maximum renderbuffer size: %d\n", m_maxRenderbufferSize);
|
||||
|
||||
// Detect support of anisotropic filtering
|
||||
m_anisotropyAvailable = glewIsSupported("GL_EXT_texture_filter_anisotropic");
|
||||
if(m_anisotropyAvailable)
|
||||
|
@ -249,8 +242,6 @@ bool CGL33Device::Create()
|
|||
m_vertexTex2 = CreateStaticBuffer(PRIMITIVE_POINTS, static_cast<VertexTex2*>(nullptr), 1);
|
||||
m_vertexCol = CreateStaticBuffer(PRIMITIVE_POINTS, static_cast<VertexCol*>(nullptr), 1);
|
||||
|
||||
GetLogger()->Info("CDevice created successfully\n");
|
||||
|
||||
int value;
|
||||
if (CProfile::GetInstance().GetIntProperty("Setup", "PerPixelLighting", value))
|
||||
{
|
||||
|
@ -379,23 +370,35 @@ bool CGL33Device::Create()
|
|||
for (int i = 0; i < 8; i++)
|
||||
glUniform1i(uni_Light[i].Enabled, 0);
|
||||
|
||||
// create default framebuffer object
|
||||
FramebufferParams framebufferParams;
|
||||
|
||||
framebufferParams.width = m_config.size.x;
|
||||
framebufferParams.height = m_config.size.y;
|
||||
framebufferParams.depth = m_config.depthSize;
|
||||
|
||||
m_framebuffers["default"] = new CDefaultFramebuffer(framebufferParams);
|
||||
|
||||
GetLogger()->Info("CDevice created successfully\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CGL33Device::Destroy()
|
||||
{
|
||||
// delete shader program
|
||||
glUseProgram(0);
|
||||
glDeleteProgram(m_shaderProgram);
|
||||
|
||||
if (m_framebuffer != 0)
|
||||
// delete framebuffers
|
||||
for (std::map<std::string, CFramebuffer*>::iterator i = m_framebuffers.begin(); i != m_framebuffers.end(); i++)
|
||||
{
|
||||
glDeleteFramebuffers(1, &m_framebuffer);
|
||||
glDeleteRenderbuffers(1, &m_colorBuffer);
|
||||
glDeleteRenderbuffers(1, &m_depthBuffer);
|
||||
|
||||
m_framebuffer = 0;
|
||||
i->second->Destroy();
|
||||
delete i->second;
|
||||
}
|
||||
|
||||
m_framebuffers.clear();
|
||||
|
||||
// Delete the remaining textures
|
||||
// Should not be strictly necessary, but just in case
|
||||
DestroyAllTextures();
|
||||
|
@ -1443,6 +1446,8 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
|
|||
|
||||
bool changed = (info.vertexType != VERTEX_TYPE_NORMAL) || (size > info.size);
|
||||
|
||||
if (info.vertexType != VERTEX_TYPE_NORMAL) CLogger::GetInstance().Debug("Changing static buffer type\n");
|
||||
|
||||
info.primitiveType = primitiveType;
|
||||
info.vertexType = VERTEX_TYPE_NORMAL;
|
||||
info.vertexCount = vertexCount;
|
||||
|
@ -1498,6 +1503,8 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
|
|||
|
||||
bool changed = (info.vertexType != VERTEX_TYPE_TEX2) || (size > info.size);
|
||||
|
||||
if (info.vertexType != VERTEX_TYPE_TEX2) CLogger::GetInstance().Debug("Changing static buffer type\n");
|
||||
|
||||
info.primitiveType = primitiveType;
|
||||
info.vertexType = VERTEX_TYPE_TEX2;
|
||||
info.vertexCount = vertexCount;
|
||||
|
@ -1551,7 +1558,9 @@ void CGL33Device::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primit
|
|||
|
||||
unsigned int size = vertexCount * sizeof(VertexCol);
|
||||
|
||||
bool changed = (info.vertexType != VERTEX_TYPE_TEX2) || (size > info.size);
|
||||
bool changed = (info.vertexType != VERTEX_TYPE_COL) || (size > info.size);
|
||||
|
||||
if (info.vertexType != VERTEX_TYPE_NORMAL) CLogger::GetInstance().Debug("Changing static buffer type\n");
|
||||
|
||||
info.primitiveType = primitiveType;
|
||||
info.vertexType = VERTEX_TYPE_COL;
|
||||
|
@ -1735,19 +1744,6 @@ void CGL33Device::SetRenderState(RenderState state, bool enabled)
|
|||
|
||||
return;
|
||||
}
|
||||
else if (state == RENDER_STATE_OFFSCREEN_RENDERING)
|
||||
{
|
||||
if (m_framebuffer == 0)
|
||||
InitOffscreenBuffer(1024, 1024);
|
||||
|
||||
m_offscreenRenderingEnabled = enabled;
|
||||
|
||||
GLuint toBind = (enabled ? m_framebuffer : 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, toBind);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (state == RENDER_STATE_FOG)
|
||||
{
|
||||
glUniform1i(uni_FogEnabled, enabled ? 1 : 0);
|
||||
|
@ -1860,76 +1856,6 @@ void CGL33Device::SetFillMode(FillMode mode)
|
|||
else assert(false);
|
||||
}
|
||||
|
||||
void CGL33Device::InitOffscreenBuffer(int width, int height)
|
||||
{
|
||||
width = Math::Min(width, m_maxRenderbufferSize);
|
||||
height = Math::Min(height, m_maxRenderbufferSize);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
if (m_colorBuffer != 0)
|
||||
glDeleteRenderbuffers(1, &m_colorBuffer);
|
||||
|
||||
glGenRenderbuffers(1, &m_colorBuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_colorBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
if (m_depthBuffer != 0)
|
||||
glDeleteRenderbuffers(1, &m_depthBuffer);
|
||||
|
||||
glGenRenderbuffers(1, &m_depthBuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
if (m_framebuffer == 0)
|
||||
glGenFramebuffers(1, &m_framebuffer);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorBuffer);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer);
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
|
||||
|
||||
GetLogger()->Info("Initialized offscreen buffer %dx%d\n", width, height);
|
||||
}
|
||||
|
||||
void CGL33Device::SetRenderTexture(RenderTarget target, int texture)
|
||||
{
|
||||
if (!m_offscreenRenderingEnabled) return;
|
||||
|
||||
GLenum attachment;
|
||||
GLuint defaultBuffer;
|
||||
|
||||
switch (target)
|
||||
{
|
||||
case RENDER_TARGET_COLOR:
|
||||
attachment = GL_COLOR_ATTACHMENT0;
|
||||
defaultBuffer = m_colorBuffer;
|
||||
break;
|
||||
case RENDER_TARGET_DEPTH:
|
||||
attachment = GL_DEPTH_ATTACHMENT;
|
||||
defaultBuffer = m_depthBuffer;
|
||||
break;
|
||||
case RENDER_TARGET_STENCIL:
|
||||
attachment = GL_STENCIL_ATTACHMENT;
|
||||
defaultBuffer = 0;
|
||||
break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
|
||||
if (texture == 0) // unbind texture and bind default buffer
|
||||
{
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, 0, 0);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, defaultBuffer);
|
||||
}
|
||||
else // unbind default buffer and bind texture
|
||||
{
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void CGL33Device::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
|
||||
{
|
||||
if (texture.id == 0) return;
|
||||
|
@ -1957,6 +1883,47 @@ void* CGL33Device::GetFrameBufferPixels() const
|
|||
return static_cast<void*>(p);
|
||||
}
|
||||
|
||||
CFramebuffer* CGL33Device::GetFramebuffer(std::string name)
|
||||
{
|
||||
if (m_framebuffers.find(name) != m_framebuffers.end())
|
||||
return m_framebuffers[name];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CFramebuffer* CGL33Device::CreateFramebuffer(std::string name, const FramebufferParams& params)
|
||||
{
|
||||
// existing framebuffer was found
|
||||
if (m_framebuffers.find(name) != m_framebuffers.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
CGLFramebuffer* framebuffer = new CGLFramebuffer(params);
|
||||
framebuffer->Create();
|
||||
|
||||
m_framebuffers[name] = framebuffer;
|
||||
return framebuffer;
|
||||
}
|
||||
}
|
||||
|
||||
void CGL33Device::DeleteFramebuffer(std::string name)
|
||||
{
|
||||
// can't delete default framebuffer
|
||||
if (name == "default") return;
|
||||
|
||||
auto position = m_framebuffers.find(name);
|
||||
|
||||
if (position != m_framebuffers.end())
|
||||
{
|
||||
position->second->Destroy();
|
||||
delete position->second;
|
||||
|
||||
m_framebuffers.erase(position);
|
||||
}
|
||||
}
|
||||
|
||||
void CGL33Device::UpdateRenderingMode()
|
||||
{
|
||||
bool enabled = m_texturesEnabled[0] && m_currentTextures[0].id != 0;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "graphics/core/device.h"
|
||||
#include "graphics/opengl/glutil.h"
|
||||
#include "graphics/opengl/glframebuffer.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -135,14 +136,16 @@ public:
|
|||
|
||||
virtual void SetFillMode(FillMode mode) OVERRIDE;
|
||||
|
||||
virtual void InitOffscreenBuffer(int width, int height) OVERRIDE;
|
||||
|
||||
virtual void SetRenderTexture(RenderTarget target, int texture) OVERRIDE;
|
||||
|
||||
virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) OVERRIDE;
|
||||
|
||||
virtual void* GetFrameBufferPixels() const OVERRIDE;
|
||||
|
||||
virtual CFramebuffer* GetFramebuffer(std::string name) OVERRIDE;
|
||||
|
||||
virtual CFramebuffer* CreateFramebuffer(std::string name, const FramebufferParams& params) OVERRIDE;
|
||||
|
||||
virtual void DeleteFramebuffer(std::string name) OVERRIDE;
|
||||
|
||||
private:
|
||||
//! Updates position for given light based on transformation matrices
|
||||
void UpdateLightPosition(int index);
|
||||
|
@ -224,17 +227,8 @@ private:
|
|||
//! Currently bound VAO
|
||||
GLuint m_currentVAO;
|
||||
|
||||
// Offscreen buffer
|
||||
//! Framebuffer object
|
||||
GLuint m_framebuffer;
|
||||
//! Color renderbuffer
|
||||
GLuint m_colorBuffer;
|
||||
//! Depth renderbuffer
|
||||
GLuint m_depthBuffer;
|
||||
//! Maximum available renderbuffer size
|
||||
int m_maxRenderbufferSize;
|
||||
//! true if offscreen rendering is enabled
|
||||
bool m_offscreenRenderingEnabled;
|
||||
//! Map of framebuffers
|
||||
std::map<std::string, CFramebuffer*> m_framebuffers;
|
||||
|
||||
//! Shader program
|
||||
GLuint m_shaderProgram;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
|
||||
#include "graphics/opengl/gldevice.h"
|
||||
#include "graphics/opengl/glframebuffer.h"
|
||||
#include "graphics/engine/engine.h"
|
||||
|
||||
#include "common/config.h"
|
||||
|
@ -50,11 +51,6 @@ CGLDevice::CGLDevice(const DeviceConfig &config)
|
|||
m_glMinor = 1;
|
||||
m_shadowMappingSupport = SMS_NONE;
|
||||
m_shadowAmbientSupported = false;
|
||||
|
||||
m_framebuffer = 0;
|
||||
m_colorBuffer = 0;
|
||||
m_depthBuffer = 0;
|
||||
m_offscreenRenderingEnabled = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -197,15 +193,6 @@ bool CGLDevice::Create()
|
|||
if (!m_multitextureAvailable)
|
||||
GetLogger()->Warn("GLEW reports multitexturing not supported - graphics quality will be degraded!\n");
|
||||
|
||||
m_framebufferObject = glewIsSupported("GL_EXT_framebuffer_object");
|
||||
if (m_framebufferObject)
|
||||
{
|
||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &m_maxRenderbufferSize);
|
||||
|
||||
GetLogger()->Info("Offscreen rendering available\n");
|
||||
GetLogger()->Info("Maximum renderbuffer size: %d\n", m_maxRenderbufferSize);
|
||||
}
|
||||
|
||||
// Detect Shadow mapping support
|
||||
if (m_glMajor >= 2 || m_glMinor >= 4) // Core depth texture+shadow, OpenGL 1.4+
|
||||
{
|
||||
|
@ -304,6 +291,19 @@ bool CGLDevice::Create()
|
|||
m_texturesEnabled = std::vector<bool> (maxTextures, false);
|
||||
m_textureStageParams = std::vector<TextureStageParams>(maxTextures, TextureStageParams());
|
||||
|
||||
// create default framebuffer object
|
||||
FramebufferParams framebufferParams;
|
||||
|
||||
framebufferParams.width = m_config.size.x;
|
||||
framebufferParams.height = m_config.size.y;
|
||||
framebufferParams.depth = m_config.depthSize;
|
||||
|
||||
m_framebuffers["default"] = new CDefaultFramebuffer(framebufferParams);
|
||||
|
||||
m_framebufferSupport = DetectFramebufferSupport();
|
||||
if (m_framebufferSupport != FBS_NONE)
|
||||
GetLogger()->Debug("Framebuffer supported\n");
|
||||
|
||||
GetLogger()->Info("CDevice created successfully\n");
|
||||
|
||||
return true;
|
||||
|
@ -311,6 +311,15 @@ bool CGLDevice::Create()
|
|||
|
||||
void CGLDevice::Destroy()
|
||||
{
|
||||
// delete framebuffers
|
||||
for (std::map<std::string, CFramebuffer*>::iterator i = m_framebuffers.begin(); i != m_framebuffers.end(); i++)
|
||||
{
|
||||
i->second->Destroy();
|
||||
delete i->second;
|
||||
}
|
||||
|
||||
m_framebuffers.clear();
|
||||
|
||||
// Delete the remaining textures
|
||||
// Should not be strictly necessary, but just in case
|
||||
DestroyAllTextures();
|
||||
|
@ -774,7 +783,7 @@ Texture CGLDevice::CreateDepthTexture(int width, int height, int depth)
|
|||
|
||||
if (m_shadowAmbientSupported)
|
||||
{
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.35f);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.5f);
|
||||
}
|
||||
|
||||
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
|
@ -1709,25 +1718,6 @@ void CGLDevice::SetRenderState(RenderState state, bool enabled)
|
|||
|
||||
return;
|
||||
}
|
||||
else if (state == RENDER_STATE_OFFSCREEN_RENDERING)
|
||||
{
|
||||
if (!m_framebufferObject)
|
||||
{
|
||||
GetLogger()->Error("Cannot enable offscreen rendering without framebuffer object!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
m_offscreenRenderingEnabled = enabled;
|
||||
|
||||
if (m_framebuffer == 0)
|
||||
InitOffscreenBuffer(2048, 2048);
|
||||
|
||||
GLuint toBind = (enabled ? m_framebuffer : 0);
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, toBind);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
GLenum flag = 0;
|
||||
|
||||
|
@ -1825,79 +1815,6 @@ void CGLDevice::SetFillMode(FillMode mode)
|
|||
else assert(false);
|
||||
}
|
||||
|
||||
void CGLDevice::InitOffscreenBuffer(int width, int height)
|
||||
{
|
||||
if (!m_framebufferObject) return;
|
||||
|
||||
width = Math::Min(width, m_maxRenderbufferSize);
|
||||
height = Math::Min(height, m_maxRenderbufferSize);
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
if (m_colorBuffer != 0)
|
||||
glDeleteRenderbuffersEXT(1, &m_colorBuffer);
|
||||
|
||||
glGenRenderbuffersEXT(1, &m_colorBuffer);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_colorBuffer);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, width, height);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
|
||||
if (m_depthBuffer != 0)
|
||||
glDeleteRenderbuffersEXT(1, &m_depthBuffer);
|
||||
|
||||
glGenRenderbuffersEXT(1, &m_depthBuffer);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
|
||||
if (m_framebuffer == 0)
|
||||
glGenFramebuffersEXT(1, &m_framebuffer);
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_framebuffer);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_colorBuffer);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer);
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
GetLogger()->Info("Initialized offscreen buffer %dx%d\n", width, height);
|
||||
}
|
||||
|
||||
void CGLDevice::SetRenderTexture(RenderTarget target, int texture)
|
||||
{
|
||||
if (!m_framebufferObject) return;
|
||||
if (!m_offscreenRenderingEnabled) return;
|
||||
|
||||
GLenum attachment;
|
||||
GLuint defaultBuffer;
|
||||
|
||||
switch (target)
|
||||
{
|
||||
case RENDER_TARGET_COLOR:
|
||||
attachment = GL_COLOR_ATTACHMENT0_EXT;
|
||||
defaultBuffer = m_colorBuffer;
|
||||
break;
|
||||
case RENDER_TARGET_DEPTH:
|
||||
attachment = GL_DEPTH_ATTACHMENT_EXT;
|
||||
defaultBuffer = m_depthBuffer;
|
||||
break;
|
||||
case RENDER_TARGET_STENCIL:
|
||||
attachment = GL_STENCIL_ATTACHMENT_EXT;
|
||||
defaultBuffer = 0;
|
||||
break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
|
||||
if (texture == 0) // unbind texture and bind default buffer
|
||||
{
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_2D, 0, 0);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, defaultBuffer);
|
||||
}
|
||||
else // unbind default buffer and bind texture
|
||||
{
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, 0);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_2D, texture, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void CGLDevice::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
|
||||
{
|
||||
if (texture.id == 0) return;
|
||||
|
@ -1927,5 +1844,54 @@ void* CGLDevice::GetFrameBufferPixels()const{
|
|||
return static_cast<void*>(p);
|
||||
}
|
||||
|
||||
CFramebuffer* CGLDevice::GetFramebuffer(std::string name)
|
||||
{
|
||||
if (m_framebuffers.find(name) != m_framebuffers.end())
|
||||
return m_framebuffers[name];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CFramebuffer* CGLDevice::CreateFramebuffer(std::string name, const FramebufferParams& params)
|
||||
{
|
||||
// existing framebuffer was found
|
||||
if (m_framebuffers.find(name) != m_framebuffers.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
CFramebuffer *framebuffer;
|
||||
|
||||
if (m_framebufferSupport == FBS_ARB)
|
||||
framebuffer = new CGLFramebuffer(params);
|
||||
else if (m_framebufferSupport == FBS_EXT)
|
||||
framebuffer = new CGLFramebufferEXT(params);
|
||||
else
|
||||
return nullptr;
|
||||
|
||||
framebuffer->Create();
|
||||
|
||||
m_framebuffers[name] = framebuffer;
|
||||
return framebuffer;
|
||||
}
|
||||
}
|
||||
|
||||
void CGLDevice::DeleteFramebuffer(std::string name)
|
||||
{
|
||||
// can't delete default framebuffer
|
||||
if (name == "default") return;
|
||||
|
||||
auto position = m_framebuffers.find(name);
|
||||
|
||||
if (position != m_framebuffers.end())
|
||||
{
|
||||
position->second->Destroy();
|
||||
delete position->second;
|
||||
|
||||
m_framebuffers.erase(position);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "graphics/core/device.h"
|
||||
#include "graphics/opengl/glutil.h"
|
||||
#include "graphics/opengl/glframebuffer.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -155,14 +156,16 @@ public:
|
|||
|
||||
virtual void SetFillMode(FillMode mode) OVERRIDE;
|
||||
|
||||
virtual void InitOffscreenBuffer(int width, int height) OVERRIDE;
|
||||
|
||||
virtual void SetRenderTexture(RenderTarget target, int texture) OVERRIDE;
|
||||
|
||||
virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) OVERRIDE;
|
||||
|
||||
virtual void* GetFrameBufferPixels() const OVERRIDE;
|
||||
|
||||
virtual CFramebuffer* GetFramebuffer(std::string name) OVERRIDE;
|
||||
|
||||
virtual CFramebuffer* CreateFramebuffer(std::string name, const FramebufferParams& params) OVERRIDE;
|
||||
|
||||
virtual void DeleteFramebuffer(std::string name) OVERRIDE;
|
||||
|
||||
private:
|
||||
//! Updates internal modelview matrix
|
||||
void UpdateModelviewMatrix();
|
||||
|
@ -204,6 +207,9 @@ private:
|
|||
//! Set of all created textures
|
||||
std::set<Texture> m_allTextures;
|
||||
|
||||
//! Map of framebuffers
|
||||
std::map<std::string, CFramebuffer*> m_framebuffers;
|
||||
|
||||
//! Type of vertex structure
|
||||
enum VertexType
|
||||
{
|
||||
|
@ -238,24 +244,14 @@ private:
|
|||
int m_maxAnisotropy;
|
||||
//! Whether offscreen rendering is available
|
||||
bool m_framebufferObject;
|
||||
//! Framebuffer support
|
||||
FramebufferSupport m_framebufferSupport;
|
||||
//! Which vertex buffer type to use
|
||||
VertexBufferType m_vertexBufferType;
|
||||
//! Map of saved VBO objects
|
||||
std::map<unsigned int, VboObjectInfo> m_vboObjects;
|
||||
//! Last ID of VBO object
|
||||
unsigned int m_lastVboId;
|
||||
|
||||
// Offscreen buffer
|
||||
//! Framebuffer object
|
||||
GLuint m_framebuffer;
|
||||
//! Color renderbuffer
|
||||
GLuint m_colorBuffer;
|
||||
//! Depth renderbuffer
|
||||
GLuint m_depthBuffer;
|
||||
//! Maximum available renderbuffer size
|
||||
int m_maxRenderbufferSize;
|
||||
//! true if offscreen rendering enabled
|
||||
bool m_offscreenRenderingEnabled;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,471 @@
|
|||
/*
|
||||
* This file is part of the Colobot: Gold Edition source code
|
||||
* Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||
* http://epsiteс.ch; http://colobot.info; http://github.com/colobot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see http://gnu.org/licenses
|
||||
*/
|
||||
|
||||
#include "graphics/opengl/glframebuffer.h"
|
||||
|
||||
#include "common/logger.h"
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
// CGLFramebuffer
|
||||
|
||||
GLuint CGLFramebuffer::m_currentFBO = 0;
|
||||
|
||||
CGLFramebuffer::CGLFramebuffer(const FramebufferParams& params)
|
||||
: m_params(params)
|
||||
{
|
||||
m_fbo = 0;
|
||||
m_colorRenderbuffer = 0;
|
||||
m_colorTexture = 0;
|
||||
m_depthRenderbuffer = 0;
|
||||
m_depthTexture = 0;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
m_depth = 0;
|
||||
m_samples = 0;
|
||||
}
|
||||
|
||||
void CGLFramebuffer::Create()
|
||||
{
|
||||
if (m_fbo != 0) return;
|
||||
|
||||
m_width = m_params.width;
|
||||
m_height = m_params.height;
|
||||
m_depth = m_params.depth;
|
||||
m_samples = m_params.samples;
|
||||
|
||||
glGenFramebuffers(1, &m_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
||||
|
||||
// create color texture
|
||||
if (m_params.colorTexture)
|
||||
{
|
||||
GLint previous;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous);
|
||||
|
||||
glGenTextures(1, &m_colorTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_colorTexture);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_params.width, m_params.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, previous);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorTexture, 0);
|
||||
}
|
||||
// create color renderbuffer
|
||||
else
|
||||
{
|
||||
glGenRenderbuffers(1, &m_colorRenderbuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);
|
||||
|
||||
if (m_params.samples > 1)
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_params.samples, GL_RGBA8, m_params.width, m_params.height);
|
||||
else
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, m_params.width, m_params.height);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorRenderbuffer);
|
||||
}
|
||||
|
||||
GLuint depthFormat = 0;
|
||||
|
||||
switch (m_params.depth)
|
||||
{
|
||||
case 16: depthFormat = GL_DEPTH_COMPONENT16; break;
|
||||
case 24: depthFormat = GL_DEPTH_COMPONENT24; break;
|
||||
case 32: depthFormat = GL_DEPTH_COMPONENT32; break;
|
||||
default: depthFormat = GL_DEPTH_COMPONENT16; break;
|
||||
}
|
||||
|
||||
// create depth texture
|
||||
if (m_params.depthTexture)
|
||||
{
|
||||
GLint previous;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous);
|
||||
|
||||
glGenTextures(1, &m_depthTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, depthFormat, m_params.width, m_params.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
||||
|
||||
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, previous);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexture, 0);
|
||||
}
|
||||
// create depth renderbuffer
|
||||
else
|
||||
{
|
||||
glGenRenderbuffers(1, &m_depthRenderbuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_depthRenderbuffer);
|
||||
|
||||
if (m_params.samples > 1)
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_params.samples, depthFormat, m_params.width, m_params.height);
|
||||
else
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, depthFormat, m_params.width, m_params.height);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthRenderbuffer);
|
||||
}
|
||||
|
||||
GLuint result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (result != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
GetLogger()->Error("Framebuffer incomplete\n");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_currentFBO);
|
||||
}
|
||||
|
||||
void CGLFramebuffer::Destroy()
|
||||
{
|
||||
if (m_fbo == 0) return;
|
||||
|
||||
if (m_currentFBO == m_fbo)
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
glDeleteFramebuffers(1, &m_fbo);
|
||||
m_fbo = 0;
|
||||
|
||||
if (m_colorRenderbuffer != 0)
|
||||
{
|
||||
glDeleteRenderbuffers(1, &m_colorRenderbuffer);
|
||||
m_colorRenderbuffer = 0;
|
||||
}
|
||||
|
||||
if (m_colorTexture != 0)
|
||||
{
|
||||
glDeleteTextures(1, &m_colorTexture);
|
||||
m_colorTexture = 0;
|
||||
}
|
||||
|
||||
if (m_depthRenderbuffer != 0)
|
||||
{
|
||||
glDeleteRenderbuffers(1, &m_depthRenderbuffer);
|
||||
m_depthRenderbuffer = 0;
|
||||
}
|
||||
|
||||
if (m_depthTexture != 0)
|
||||
{
|
||||
glDeleteTextures(1, &m_depthTexture);
|
||||
m_depthTexture = 0;
|
||||
}
|
||||
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
m_depth = 0;
|
||||
m_samples = 0;
|
||||
}
|
||||
|
||||
bool CGLFramebuffer::IsDefault()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Returns width of buffers in this framebuffer
|
||||
int CGLFramebuffer::GetWidth()
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
//! Returns height of buffers in this framebuffer
|
||||
int CGLFramebuffer::GetHeight()
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
//! Returns depth size in bits
|
||||
int CGLFramebuffer::GetDepth()
|
||||
{
|
||||
return m_depth;
|
||||
}
|
||||
|
||||
//! Returns number of samples or 1 if multisampling is not supported
|
||||
int CGLFramebuffer::GetSamples()
|
||||
{
|
||||
return m_samples;
|
||||
}
|
||||
|
||||
//! Returns texture that contains color buffer or 0 if not available
|
||||
int CGLFramebuffer::GetColorTexture()
|
||||
{
|
||||
return m_colorTexture;
|
||||
}
|
||||
|
||||
//! Returns texture that contains depth buffer or 0 if not available
|
||||
int CGLFramebuffer::GetDepthTexture()
|
||||
{
|
||||
return m_depthTexture;
|
||||
}
|
||||
|
||||
//! Binds this framebuffer to context
|
||||
void CGLFramebuffer::Bind()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
||||
m_currentFBO = m_fbo;
|
||||
}
|
||||
|
||||
//! Unbinds this framebuffer from context
|
||||
void CGLFramebuffer::Unbind()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
m_currentFBO = 0;
|
||||
}
|
||||
|
||||
// CGLFramebufferEXT
|
||||
GLuint CGLFramebufferEXT::m_currentFBO = 0;
|
||||
|
||||
CGLFramebufferEXT::CGLFramebufferEXT(const FramebufferParams& params)
|
||||
: m_params(params)
|
||||
{
|
||||
m_fbo = 0;
|
||||
m_colorRenderbuffer = 0;
|
||||
m_colorTexture = 0;
|
||||
m_depthRenderbuffer = 0;
|
||||
m_depthTexture = 0;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
m_depth = 0;
|
||||
m_samples = 0;
|
||||
}
|
||||
|
||||
void CGLFramebufferEXT::Create()
|
||||
{
|
||||
if (m_fbo != 0) return;
|
||||
|
||||
m_width = m_params.width;
|
||||
m_height = m_params.height;
|
||||
m_depth = m_params.depth;
|
||||
m_samples = m_params.samples;
|
||||
|
||||
glGenFramebuffersEXT(1, &m_fbo);
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
|
||||
|
||||
// create color texture
|
||||
if (m_params.colorTexture)
|
||||
{
|
||||
GLint previous;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous);
|
||||
|
||||
glGenTextures(1, &m_colorTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_colorTexture);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_params.width, m_params.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, previous);
|
||||
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_colorTexture, 0);
|
||||
}
|
||||
// create color renderbuffer
|
||||
else
|
||||
{
|
||||
glGenRenderbuffersEXT(1, &m_colorRenderbuffer);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_colorRenderbuffer);
|
||||
|
||||
if (m_params.samples > 1)
|
||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_params.samples, GL_RGBA8, m_params.width, m_params.height);
|
||||
else
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, m_params.width, m_params.height);
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_colorRenderbuffer);
|
||||
}
|
||||
|
||||
GLuint depthFormat = 0;
|
||||
|
||||
switch (m_params.depth)
|
||||
{
|
||||
case 16: depthFormat = GL_DEPTH_COMPONENT16; break;
|
||||
case 24: depthFormat = GL_DEPTH_COMPONENT24; break;
|
||||
case 32: depthFormat = GL_DEPTH_COMPONENT32; break;
|
||||
default: depthFormat = GL_DEPTH_COMPONENT16; break;
|
||||
}
|
||||
|
||||
// create depth texture
|
||||
if (m_params.depthTexture)
|
||||
{
|
||||
GLint previous;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous);
|
||||
|
||||
glGenTextures(1, &m_depthTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, depthFormat, m_params.width, m_params.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
||||
|
||||
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, previous);
|
||||
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_depthTexture, 0);
|
||||
}
|
||||
// create depth renderbuffer
|
||||
else
|
||||
{
|
||||
glGenRenderbuffersEXT(1, &m_depthRenderbuffer);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER, m_depthRenderbuffer);
|
||||
|
||||
if (m_params.samples > 1)
|
||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_params.samples, depthFormat, m_params.width, m_params.height);
|
||||
else
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormat, m_params.width, m_params.height);
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthRenderbuffer);
|
||||
}
|
||||
|
||||
GLuint result = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
if (result != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
{
|
||||
GetLogger()->Error("Framebuffer incomplete: %d\n", result);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_currentFBO);
|
||||
}
|
||||
|
||||
void CGLFramebufferEXT::Destroy()
|
||||
{
|
||||
if (m_fbo == 0) return;
|
||||
|
||||
if (m_currentFBO == m_fbo)
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
glDeleteFramebuffersEXT(1, &m_fbo);
|
||||
m_fbo = 0;
|
||||
|
||||
if (m_colorRenderbuffer != 0)
|
||||
{
|
||||
glDeleteRenderbuffersEXT(1, &m_colorRenderbuffer);
|
||||
m_colorRenderbuffer = 0;
|
||||
}
|
||||
|
||||
if (m_colorTexture != 0)
|
||||
{
|
||||
glDeleteTextures(1, &m_colorTexture);
|
||||
m_colorTexture = 0;
|
||||
}
|
||||
|
||||
if (m_depthRenderbuffer != 0)
|
||||
{
|
||||
glDeleteRenderbuffersEXT(1, &m_depthRenderbuffer);
|
||||
m_depthRenderbuffer = 0;
|
||||
}
|
||||
|
||||
if (m_depthTexture != 0)
|
||||
{
|
||||
glDeleteTextures(1, &m_depthTexture);
|
||||
m_depthTexture = 0;
|
||||
}
|
||||
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
m_depth = 0;
|
||||
m_samples = 0;
|
||||
}
|
||||
|
||||
bool CGLFramebufferEXT::IsDefault()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Returns width of buffers in this framebuffer
|
||||
int CGLFramebufferEXT::GetWidth()
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
//! Returns height of buffers in this framebuffer
|
||||
int CGLFramebufferEXT::GetHeight()
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
//! Returns depth size in bits
|
||||
int CGLFramebufferEXT::GetDepth()
|
||||
{
|
||||
return m_depth;
|
||||
}
|
||||
|
||||
//! Returns number of samples or 1 if multisampling is not supported
|
||||
int CGLFramebufferEXT::GetSamples()
|
||||
{
|
||||
return m_samples;
|
||||
}
|
||||
|
||||
//! Returns texture that contains color buffer or 0 if not available
|
||||
int CGLFramebufferEXT::GetColorTexture()
|
||||
{
|
||||
return m_colorTexture;
|
||||
}
|
||||
|
||||
//! Returns texture that contains depth buffer or 0 if not available
|
||||
int CGLFramebufferEXT::GetDepthTexture()
|
||||
{
|
||||
return m_depthTexture;
|
||||
}
|
||||
|
||||
//! Binds this framebuffer to context
|
||||
void CGLFramebufferEXT::Bind()
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
|
||||
m_currentFBO = m_fbo;
|
||||
}
|
||||
|
||||
//! Unbinds this framebuffer from context
|
||||
void CGLFramebufferEXT::Unbind()
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
m_currentFBO = 0;
|
||||
}
|
||||
|
||||
} // end of Gfx
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* This file is part of the Colobot: Gold Edition source code
|
||||
* Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||
* http://epsiteс.ch; http://colobot.info; http://github.com/colobot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see http://gnu.org/licenses
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "graphics/core/framebuffer.h"
|
||||
#include "graphics/opengl/glutil.h"
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
/**
|
||||
* \class CGLFramebuffer
|
||||
* \brief Implementation of CFramebuffer interface in OpenGL 3.0+
|
||||
*
|
||||
* Provides the concrete implementation of core framebuffers.
|
||||
* Can be used in OpenGL 3.0+ and with ARB_framebuffer_object supported.
|
||||
*/
|
||||
class CGLFramebuffer : public CFramebuffer
|
||||
{
|
||||
protected:
|
||||
FramebufferParams m_params;
|
||||
|
||||
int m_width, m_height, m_depth, m_samples;
|
||||
|
||||
GLuint m_fbo;
|
||||
GLuint m_colorRenderbuffer;
|
||||
GLuint m_colorTexture;
|
||||
GLuint m_depthRenderbuffer;
|
||||
GLuint m_depthTexture;
|
||||
|
||||
static GLuint m_currentFBO;
|
||||
|
||||
public:
|
||||
CGLFramebuffer(const FramebufferParams& params);
|
||||
|
||||
virtual void Create() OVERRIDE;
|
||||
|
||||
virtual void Destroy() OVERRIDE;
|
||||
|
||||
virtual bool IsDefault() OVERRIDE;
|
||||
|
||||
virtual int GetWidth() OVERRIDE;
|
||||
|
||||
virtual int GetHeight() OVERRIDE;
|
||||
|
||||
virtual int GetDepth() OVERRIDE;
|
||||
|
||||
virtual int GetSamples() OVERRIDE;
|
||||
|
||||
virtual int GetColorTexture() OVERRIDE;
|
||||
|
||||
virtual int GetDepthTexture() OVERRIDE;
|
||||
|
||||
virtual void Bind() OVERRIDE;
|
||||
|
||||
virtual void Unbind() OVERRIDE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \class CGLFramebuffer
|
||||
* \brief Implementation of CFramebuffer interface in legacy OpenGL
|
||||
*
|
||||
* Provides the concrete implementation of extension framebuffers.
|
||||
* Can be used with EXT_framebuffer_object supported.
|
||||
*/
|
||||
class CGLFramebufferEXT : public CFramebuffer
|
||||
{
|
||||
protected:
|
||||
FramebufferParams m_params;
|
||||
|
||||
int m_width, m_height, m_depth, m_samples;
|
||||
|
||||
GLuint m_fbo;
|
||||
GLuint m_colorRenderbuffer;
|
||||
GLuint m_colorTexture;
|
||||
GLuint m_depthRenderbuffer;
|
||||
GLuint m_depthTexture;
|
||||
|
||||
static GLuint m_currentFBO;
|
||||
|
||||
public:
|
||||
CGLFramebufferEXT(const FramebufferParams& params);
|
||||
|
||||
virtual void Create() OVERRIDE;
|
||||
|
||||
virtual void Destroy() OVERRIDE;
|
||||
|
||||
virtual bool IsDefault() OVERRIDE;
|
||||
|
||||
virtual int GetWidth() OVERRIDE;
|
||||
|
||||
virtual int GetHeight() OVERRIDE;
|
||||
|
||||
virtual int GetDepth() OVERRIDE;
|
||||
|
||||
virtual int GetSamples() OVERRIDE;
|
||||
|
||||
virtual int GetColorTexture() OVERRIDE;
|
||||
|
||||
virtual int GetDepthTexture() OVERRIDE;
|
||||
|
||||
virtual void Bind() OVERRIDE;
|
||||
|
||||
virtual void Unbind() OVERRIDE;
|
||||
};
|
||||
|
||||
} // end of Gfx
|
|
@ -31,6 +31,14 @@ namespace Gfx {
|
|||
GLuint textureCoordinates[] = { GL_S, GL_T, GL_R, GL_Q };
|
||||
GLuint textureCoordGen[] = { GL_TEXTURE_GEN_S, GL_TEXTURE_GEN_T, GL_TEXTURE_GEN_R, GL_TEXTURE_GEN_Q };
|
||||
|
||||
FramebufferSupport DetectFramebufferSupport()
|
||||
{
|
||||
if (GetOpenGLVersion() >= 30) return FBS_ARB;
|
||||
if (glewIsSupported("GL_ARB_framebuffer_object")) return FBS_ARB;
|
||||
if (glewIsSupported("GL_EXT_framebuffer_object")) return FBS_EXT;
|
||||
return FBS_NONE;
|
||||
}
|
||||
|
||||
CDevice* CreateDevice(const DeviceConfig &config, const char *name)
|
||||
{
|
||||
if (name == nullptr) return nullptr;
|
||||
|
|
|
@ -31,6 +31,15 @@
|
|||
namespace Gfx
|
||||
{
|
||||
|
||||
enum FramebufferSupport
|
||||
{
|
||||
FBS_NONE,
|
||||
FBS_EXT,
|
||||
FBS_ARB,
|
||||
};
|
||||
|
||||
FramebufferSupport DetectFramebufferSupport();
|
||||
|
||||
//! Creates OpenGL device
|
||||
CDevice* CreateDevice(const DeviceConfig &config, const char *name);
|
||||
|
||||
|
|
Loading…
Reference in New Issue