Refactored framebuffer implementations

master
Tomasz Kapuściński 2015-06-21 18:48:31 +02:00
parent 94851c2694
commit 7d57ec634e
17 changed files with 1174 additions and 389 deletions

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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 &params);
//! 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

View File

@ -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

View File

@ -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;

View File

@ -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
{

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);