Added experimental support for dynamic shadows (shadow mapping)

master
Tomasz Kapuściński 2015-05-11 15:21:17 +02:00
parent 1e3c2cc2df
commit 0b2f00530b
9 changed files with 594 additions and 38 deletions

View File

@ -123,6 +123,7 @@ enum PerformanceCounter
PCNT_RENDER_TERRAIN, //! < rendering the terrain
PCNT_RENDER_OBJECTS, //! < rendering the 3D objects
PCNT_RENDER_INTERFACE, //! < rendering 2D interface
PCNT_RENDER_SHADOW_MAP, //! < rendering shadow map
PCNT_ALL, //! < all counters together

View File

@ -91,8 +91,7 @@ enum TransformType
{
TRANSFORM_WORLD,
TRANSFORM_VIEW,
TRANSFORM_PROJECTION,
TRANSFORM_TEXTURE
TRANSFORM_PROJECTION
};
/**
@ -107,7 +106,8 @@ enum RenderState
RENDER_STATE_DEPTH_TEST,
RENDER_STATE_DEPTH_WRITE,
RENDER_STATE_ALPHA_TEST,
RENDER_STATE_CULLING
RENDER_STATE_CULLING,
RENDER_STATE_DEPTH_BIAS
};
/**
@ -276,6 +276,8 @@ public:
virtual Texture CreateTexture(CImage *image, const TextureCreateParams &params) = 0;
//! Creates a texture from raw image data; image data can be freed after that
virtual Texture CreateTexture(ImageData *data, const TextureCreateParams &params) = 0;
//! Creates a depth texture with specific dimensions and depth
virtual Texture CreateDepthTexture(int width, int height, int depth) = 0;
//! Deletes a given texture, freeing it from video memory
virtual void DestroyTexture(const Texture &texture) = 0;
//! Deletes all textures created so far
@ -296,6 +298,12 @@ public:
//! Sets only the texture wrap modes (for faster than thru stage params)
virtual void SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) = 0;
//! Sets the texture coordinate generation mode for given texture unit
virtual void SetTextureCoordGeneration(int index, TextureGenerationParams &params) = 0;
//! Sets texture coordinate transform matrix
virtual void SetTextureMatrix(int index, Math::Matrix& matrix) = 0;
//! Renders primitive composed of vertices with single texture
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) = 0;
@ -333,14 +341,20 @@ public:
//! Returns a mask of frustum planes for which the test is positive
virtual int ComputeSphereVisibility(const Math::Vector &center, float radius) = 0;
//! Changes rendering viewport
virtual void SetViewport(int x, int y, int width, int height) = 0;
//! Enables/disables the given render state
virtual void SetRenderState(RenderState state, bool enabled) = 0;
//! Sets the color mask
virtual void SetColorMask(bool red, bool green, bool blue, bool alpha) = 0;
//! Sets the function of depth test
virtual void SetDepthTestFunc(CompFunc func) = 0;
//! Sets the depth bias (constant value added to Z-coords)
virtual void SetDepthBias(float factor) = 0;
virtual void SetDepthBias(float factor, float units) = 0;
//! Sets the alpha test function and reference value
virtual void SetAlphaTestFunc(CompFunc func, float refValue) = 0;
@ -366,6 +380,9 @@ public:
//! Sets the current fill mode
virtual void SetFillMode(FillMode mode) = 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;
};

View File

@ -128,6 +128,13 @@ Texture CNullDevice::CreateTexture(ImageData *data, const TextureCreateParams &p
return tex;
}
Texture CNullDevice::CreateDepthTexture(int width, int height, int depth)
{
Texture tex;
tex.id = 1; // tex.id = 0 => invalid texture
return tex;
}
void CNullDevice::DestroyTexture(const Texture &texture)
{
}
@ -171,6 +178,14 @@ void CNullDevice::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode
{
}
void CNullDevice::SetTextureCoordGeneration(int index, TextureGenerationParams &params)
{
}
void CNullDevice::SetTextureMatrix(int index, Math::Matrix& matrix)
{
}
TextureStageParams CNullDevice::GetTextureStageParams(int index)
{
return TextureStageParams();
@ -230,6 +245,10 @@ int CNullDevice::ComputeSphereVisibility(const Math::Vector &center, float radiu
return 0;
}
void CNullDevice::SetViewport(int x, int y, int width, int height)
{
}
void CNullDevice::SetRenderState(RenderState state, bool enabled)
{
}
@ -239,6 +258,10 @@ bool CNullDevice::GetRenderState(RenderState state)
return false;
}
void CNullDevice::SetColorMask(bool red, bool green, bool blue, bool alpha)
{
}
void CNullDevice::SetDepthTestFunc(CompFunc func)
{
}
@ -248,7 +271,7 @@ CompFunc CNullDevice::GetDepthTestFunc()
return COMP_FUNC_NEVER;
}
void CNullDevice::SetDepthBias(float factor)
void CNullDevice::SetDepthBias(float factor, float units)
{
}
@ -332,6 +355,10 @@ FillMode CNullDevice::GetFillMode()
return FILL_POINT;
}
void CNullDevice::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
{
}
void* CNullDevice::GetFrameBufferPixels() const
{
return nullptr;

View File

@ -67,6 +67,7 @@ public:
virtual Texture CreateTexture(CImage *image, const TextureCreateParams &params);
virtual Texture CreateTexture(ImageData *data, const TextureCreateParams &params);
virtual Texture CreateDepthTexture(int width, int height, int depth);
virtual void DestroyTexture(const Texture &texture);
virtual void DestroyAllTextures();
@ -81,6 +82,8 @@ public:
virtual TextureStageParams GetTextureStageParams(int index);
virtual void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT);
virtual void SetTextureCoordGeneration(int index, TextureGenerationParams &params);
virtual void SetTextureMatrix(int index, Math::Matrix& matrix);
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f));
@ -98,14 +101,18 @@ public:
virtual void DestroyStaticBuffer(unsigned int bufferId);
virtual int ComputeSphereVisibility(const Math::Vector &center, float radius);
virtual void SetViewport(int x, int y, int width, int height);
virtual void SetRenderState(RenderState state, bool enabled);
virtual bool GetRenderState(RenderState state);
virtual void SetColorMask(bool red, bool green, bool blue, bool alpha);
virtual void SetDepthTestFunc(CompFunc func);
virtual CompFunc GetDepthTestFunc();
virtual void SetDepthBias(float factor);
virtual void SetDepthBias(float factor, float units);
virtual float GetDepthBias();
virtual void SetAlphaTestFunc(CompFunc func, float refValue);
@ -131,6 +138,8 @@ public:
virtual void SetFillMode(FillMode mode) ;
virtual FillMode GetFillMode();
virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height);
virtual void* GetFrameBufferPixels() const;

View File

@ -98,6 +98,7 @@ enum TexMagFilter
enum TexWrapMode
{
TEX_WRAP_CLAMP,
TEX_WRAP_CLAMP_TO_BORDER,
TEX_WRAP_REPEAT
};
@ -215,6 +216,54 @@ struct TextureStageParams
}
};
/**
* \struct TexGenMode
* \brief Texture generation mode
*/
enum TexGenMode
{
//! No texture generation
TEX_GEN_NONE,
//! Object linear mode
TEX_GEN_OBJECT_LINEAR,
//! Eye linear mode
TEX_GEN_EYE_LINEAR,
//! Spherical mapping mode
TEX_GEN_SPHERE_MAP,
//! Normal mapping mode
TEX_GEN_NORMAL_MAP,
//! Reflection mapping mode
TEX_GEN_REFLECTION_MAP
};
/**
* \struct TextureGenerationParams
* \brief Parameters for texture coordinate generation
*
* These params define the generation of texture coordinate for given texture unit.
*/
struct TextureGenerationParams
{
struct
{
TexGenMode mode;
float plane[4];
} coords[4];
TextureGenerationParams()
{
LoadDefault();
}
inline void LoadDefault()
{
for (int i = 0; i < 4; i++)
{
coords[i].mode = TEX_GEN_NONE;
}
}
};
/**
* \struct Texture
* \brief Info about a texture

View File

@ -116,6 +116,8 @@ CEngine::CEngine(CApplication *app)
m_textureQuality = 1;
m_textureMipmapLevel = 1;
m_textureAnisotropy = 1;
m_shadowMapping = false;
m_npotShadowMap = false;
m_totoMode = true;
m_lensMode = true;
m_waterMode = true;
@ -181,6 +183,12 @@ CEngine::CEngine(CApplication *app)
m_textureAnisotropy = value;
}
if (CProfile::GetInstance().GetIntProperty("Setup", "ShadowMapping", value))
{
m_shadowMapping = (value > 0);
m_npotShadowMap = (value > 1);
}
m_defaultTexParams.format = TEX_IMG_AUTO;
m_defaultTexParams.mipmap = mipmaps;
m_defaultTexParams.filter = filter;
@ -188,6 +196,13 @@ CEngine::CEngine(CApplication *app)
m_terrainTexParams.format = TEX_IMG_AUTO;
m_terrainTexParams.mipmap = mipmaps;
m_terrainTexParams.filter = filter;
// Compute bias matrix for shadow mapping
Math::Matrix temp1, temp2;
Math::LoadScaleMatrix(temp1, Math::Vector(0.5f, 0.5f, 0.5f));
Math::LoadTranslationMatrix(temp2, Math::Vector(1.0f, 1.0f, 1.0f));
//m_shadowBias = Math::MultiplyMatrices(m_shadowBias, temporary);
m_shadowBias = Math::MultiplyMatrices(temp1, temp2);
}
CEngine::~CEngine()
@ -2965,6 +2980,16 @@ int CEngine::GetTextureAnisotropyLevel()
return m_textureAnisotropy;
}
void CEngine::SetShadowMapping(bool value)
{
m_shadowMapping = value;
}
bool CEngine::GetShadowMapping()
{
return m_shadowMapping;
}
void CEngine::SetTotoMode(bool present)
{
m_totoMode = present;
@ -3165,6 +3190,9 @@ void CEngine::Render()
// Begin the scene
m_device->BeginScene();
if (m_shadowMapping)
RenderShadowMap();
if (m_drawWorld)
Draw3DScene();
@ -3207,6 +3235,38 @@ void CEngine::Draw3DScene()
m_lightMan->UpdateDeviceLights(ENG_OBJTYPE_TERRAIN);
// Enable shadow mapping
if (m_shadowMapping)
{
m_device->SetTextureEnabled(2, true);
m_device->SetTexture(2, m_shadowMap);
m_device->SetTextureMatrix(2, m_shadowTextureMat);
Math::Matrix identity;
identity.LoadIdentity();
m_device->SetTransform(TRANSFORM_WORLD, identity);
TextureStageParams params;
params.colorOperation = TEX_MIX_OPER_MODULATE;
params.wrapS = TEX_WRAP_CLAMP_TO_BORDER;
params.wrapT = TEX_WRAP_CLAMP_TO_BORDER;
m_device->SetTextureStageParams(2, params);
TextureGenerationParams genParams;
for (int i = 0; i < 4; i++)
{
genParams.coords[i].mode = TEX_GEN_EYE_LINEAR;
for (int j = 0; j < 4; j++)
{
genParams.coords[i].plane[j] = (i == j ? 1.0f : 0.0f);
}
}
m_device->SetTextureCoordGeneration(2, genParams);
}
for (int objRank = 0; objRank < static_cast<int>(m_objects.size()); objRank++)
{
if (! m_objects[objRank].used)
@ -3260,6 +3320,24 @@ void CEngine::Draw3DScene()
}
}
// Disable shadow mapping
if (m_shadowMapping)
{
Math::Matrix identity;
identity.LoadIdentity();
m_device->SetTexture(2, 0);
m_device->SetTextureEnabled(2, false);
m_device->SetTextureMatrix(2, identity);
TextureGenerationParams params;
for (int i = 0; i < 4; i++)
params.coords[i].mode = TEX_GEN_NONE;
m_device->SetTextureCoordGeneration(2, params);
}
// Draws the shadows , if shadows enabled
if (m_shadowVisible)
DrawShadow();
@ -3431,6 +3509,154 @@ void CEngine::Draw3DScene()
if (! m_overFront) DrawOverColor(); // draws the foreground color
}
void CEngine::RenderShadowMap()
{
if (!m_shadowMapping) return;
m_app->StartPerformanceCounter(PCNT_RENDER_SHADOW_MAP);
m_device->Clear();
// If no shadow map texture exists, create it
if (m_shadowMap.id == 0)
{
int width, height;
int depth = m_app->GetInstance().GetVideoConfig().depthSize;
if (m_npotShadowMap)
{
width = height = Math::Min(m_size.x, m_size.y);
}
else
{
int min = Math::Min(m_size.x, m_size.y);
for (int i = 0; i < 16; i++)
{
if (min < (1 << i)) break;
width = height = 1 << i;
}
}
m_shadowMap = m_device->CreateDepthTexture(width, height, depth);
GetLogger()->Info("Created shadow map texture: %dx%d, depth %d\n", width, height, depth);
}
// change state to rendering shadow maps
m_device->SetColorMask(false, false, false, false);
//m_device->SetDepthTestFunc(COMP_FUNC_LEQUAL);
m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, true);
m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, true);
m_device->SetRenderState(RENDER_STATE_BLENDING, false);
m_device->SetRenderState(RENDER_STATE_LIGHTING, false);
m_device->SetRenderState(RENDER_STATE_FOG, false);
m_device->SetRenderState(RENDER_STATE_CULLING, false);
m_device->SetRenderState(RENDER_STATE_ALPHA_TEST, true);
m_device->SetViewport(0, 0, m_shadowMap.size.x, m_shadowMap.size.y);
// recompute matrices
Math::Vector worldUp(1.0f, 0.0f, 0.0f);
Math::Vector dir = m_lookatPt - m_eyePt;
float change = Math::Max(1.0f, dir.Length() / 25.0f);
dir.Normalize();
Math::Vector pos = m_lookatPt + 40.0f * dir;
Math::Vector lightPos = pos + Math::Vector(3.0f, 30.0f, 3.0f);
Math::Vector lookAt = pos + Math::Vector(0.0, 100.0f, 0.0f);
float dist = 75.0f; // *change;
Math::LoadOrthoProjectionMatrix(m_shadowProjMat, -dist, dist, -dist, dist, -50.0f, 50.0f);
Math::LoadViewMatrix(m_shadowViewMat, lightPos, lookAt, worldUp);
Math::Matrix temporary = Math::MultiplyMatrices(m_shadowProjMat, m_shadowViewMat);
m_shadowTextureMat = Math::MultiplyMatrices(m_shadowBias, temporary);
m_device->SetTransform(TRANSFORM_PROJECTION, m_shadowProjMat);
m_device->SetTransform(TRANSFORM_VIEW, m_shadowViewMat);
m_device->SetTexture(0, 0);
m_device->SetTexture(1, 0);
//m_device->SetCullMode(CULL_CW);
//m_device->SetRenderState(RENDER_STATE_DEPTH_BIAS, true);
//m_device->SetDepthBias(2.0f, 4.0f);
// render objects into shadow map
for (int objRank = 0; objRank < static_cast<int>(m_objects.size()); objRank++)
{
if (!m_objects[objRank].used)
continue;
if (m_objects[objRank].type == ENG_OBJTYPE_TERRAIN)
continue;
//if (!m_objects[objRank].drawWorld)
// continue;
m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform);
// TODO: check proper object filtering
if (!IsVisible(objRank))
continue;
int baseObjRank = m_objects[objRank].baseObjRank;
if (baseObjRank == -1)
continue;
assert(baseObjRank >= 0 && baseObjRank < static_cast<int>(m_baseObjects.size()));
EngineBaseObject& p1 = m_baseObjects[baseObjRank];
if (!p1.used)
continue;
//m_lightMan->UpdateDeviceLights(m_objects[objRank].type);
for (int l2 = 0; l2 < static_cast<int>(p1.next.size()); l2++)
{
EngineBaseObjTexTier& p2 = p1.next[l2];
for (int l3 = 0; l3 < static_cast<int>(p2.next.size()); l3++)
{
EngineBaseObjLODTier& p3 = p2.next[l3];
if (!IsWithinLODLimit(m_objects[objRank].distance, p3.lodLevel))
continue;
for (int l4 = 0; l4 < static_cast<int>(p3.next.size()); l4++)
{
EngineBaseObjDataTier& p4 = p3.next[l4];
//if (m_objects[objRank].transparency != 0.0f) // transparent ?
// continue;
DrawObject(p4);
}
}
}
}
m_device->SetCullMode(CULL_CCW);
m_device->SetRenderState(RENDER_STATE_DEPTH_BIAS, false);
// copy depth buffer to shadow map
m_device->CopyFramebufferToTexture(m_shadowMap, 0, 0, 0, 0, m_shadowMap.size.x, m_shadowMap.size.y);
// restore default state
m_device->SetViewport(0, 0, m_size.x, m_size.y);
m_device->SetColorMask(true, true, true, true);
m_device->Clear();
m_app->StopPerformanceCounter(PCNT_RENDER_SHADOW_MAP);
m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, false);
}
void CEngine::DrawObject(const EngineBaseObjDataTier& p4)
{
if (p4.staticBufferId != 0)
@ -4406,8 +4632,8 @@ void CEngine::DrawStats()
if (!m_showStats)
return;
float height = m_text->GetAscent(FONT_COLOBOT, 12.0f);
float width = 0.2f;
float height = m_text->GetAscent(FONT_COLOBOT, 13.0f);
float width = 0.25f;
Math::Point pos(0.04f, 0.04f + 20 * height);
@ -4510,12 +4736,19 @@ void CEngine::DrawStats()
pos.y -= height;
str.str("");
str << "Shadow map render: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_RENDER_SHADOW_MAP);
m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f));
pos.y -= height;
float otherRender = m_app->GetPerformanceCounterData(PCNT_RENDER_ALL) -
m_app->GetPerformanceCounterData(PCNT_RENDER_PARTICLE) -
m_app->GetPerformanceCounterData(PCNT_RENDER_WATER) -
m_app->GetPerformanceCounterData(PCNT_RENDER_TERRAIN) -
m_app->GetPerformanceCounterData(PCNT_RENDER_OBJECTS) -
m_app->GetPerformanceCounterData(PCNT_RENDER_INTERFACE);
m_app->GetPerformanceCounterData(PCNT_RENDER_INTERFACE) -
m_app->GetPerformanceCounterData(PCNT_RENDER_SHADOW_MAP);
str.str("");
str << "Other render: " << std::fixed << std::setprecision(2) << otherRender;

View File

@ -1134,6 +1134,12 @@ public:
int GetTextureAnisotropyLevel();
//@}
//@{
//! Management of shadow mapping
void SetShadowMapping(bool value);
bool GetShadowMapping();
//@}
//@{
//! Management mode of toto
void SetTotoMode(bool present);
@ -1227,6 +1233,8 @@ public:
protected:
//! Prepares the interface for 3D scene
void Draw3DScene();
//! Renders shadow map
void RenderShadowMap();
//! Draw 3D object
void DrawObject(const EngineBaseObjDataTier& p4);
//! Draws the user interface over the scene
@ -1339,6 +1347,15 @@ protected:
//! Camera angle for 3D scene
float m_focus;
//! Projection matrix for rendering shadow maps
Math::Matrix m_shadowProjMat;
//! View matrix for rendering shadow maps
Math::Matrix m_shadowViewMat;
//! Texture matrix for rendering shadow maps
Math::Matrix m_shadowTextureMat;
//! Texture bias for sampling shadow maps
Math::Matrix m_shadowBias;
//! World matrix for 2D interface
Math::Matrix m_matWorldInterface;
//! Projection matrix for 2D interface
@ -1416,6 +1433,8 @@ protected:
int m_editIndentValue;
float m_tracePrecision;
Texture m_shadowMap;
//! Ranks of highlighted objects
int m_highlightRank[100];
//! Highlight visible?
@ -1436,6 +1455,10 @@ protected:
int m_textureMipmapLevel;
//! Requested texture anisotropy level
int m_textureAnisotropy;
//! true if shadow mapping enabled
bool m_shadowMapping;
//! Override for NPOT shadow map texture
bool m_npotShadowMap;
//! Map of loaded textures (by name)
std::map<std::string, Texture> m_texNameMap;

View File

@ -59,8 +59,8 @@ void GLDeviceConfig::LoadDefault()
vboMode = VBO_MODE_AUTO;
}
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 };
CGLDevice::CGLDevice(const GLDeviceConfig &config)
{
@ -72,6 +72,9 @@ CGLDevice::CGLDevice(const GLDeviceConfig &config)
m_vertexBufferType = VBT_DISPLAY_LIST;
m_anisotropyAvailable = false;
m_maxAnisotropy = 1;
m_glMajor = 1;
m_glMinor = 1;
m_shadowMappingSupport = SMS_NONE;
}
@ -204,10 +207,33 @@ bool CGLDevice::Create()
return false;
}
// Extract OpenGL version
const char *version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
sscanf(version, "%d.%d", &m_glMajor, &m_glMinor);
GetLogger()->Info("OpenGL %d.%d\n", m_glMajor, m_glMinor);
// Detect multitexture support
m_multitextureAvailable = glewIsSupported("GL_ARB_multitexture GL_ARB_texture_env_combine");
if (!m_multitextureAvailable)
GetLogger()->Warn("GLEW reports multitexturing not supported - graphics quality will be degraded!\n");
// Detect Shadow mapping support
if (m_glMajor >= 2 || m_glMinor >= 4) // Core depth texture+shadow, OpenGL 1.4+
{
m_shadowMappingSupport = SMS_CORE;
GetLogger()->Info("Shadow mapping available (core)\n");
}
else if (glewIsSupported("GL_ARB_depth_texture GL_ARB_shadow")) // ARB depth texture + shadow
{
m_shadowMappingSupport = SMS_ARB;
GetLogger()->Info("Shadow mapping available (ARB)\n");
}
else // No Shadow mapping
{
m_shadowMappingSupport = SMS_NONE;
GetLogger()->Info("Shadow mapping not available\n");
}
// Detect support of anisotropic filtering
m_anisotropyAvailable = glewIsSupported("GL_EXT_texture_filter_anisotropic");
if(m_anisotropyAvailable)
@ -239,30 +265,24 @@ bool CGLDevice::Create()
{
GetLogger()->Info("Auto-detecting VBO support\n");
// extracting OpenGL version
const char *version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
int major = 0, minor = 0;
sscanf(version, "%d.%d", &major, &minor);
// detecting VBO ARB extension
bool vboARB = glewIsSupported("GL_ARB_vertex_buffer_object");
// VBO is core OpenGL feature since 1.5
// everything below 1.5 means no VBO support
if(major > 1 || minor > 4)
if (m_glMajor > 1 || m_glMinor > 4)
{
GetLogger()->Info("OpenGL %d.%d, VBO supported\n", major, minor);
GetLogger()->Info("Core VBO supported\n", m_glMajor, m_glMinor);
SetVertexBufferType(VBT_VBO_CORE);
}
else if(vboARB) // VBO ARB extension available
{
GetLogger()->Info("OpenGL %d.%d with GL_ARB_vertex_buffer_object, VBO supported\n", major, minor);
GetLogger()->Info("ARB VBO supported\n");
SetVertexBufferType(VBT_VBO_ARB);
}
else // no VBO support
{
GetLogger()->Info("OpenGL %d.%d without GL_ARB_vertex_buffer_object, VBO not supported\n", major, minor);
GetLogger()->Info("VBO not supported\n");
SetVertexBufferType(VBT_DISPLAY_LIST);
}
}
@ -275,9 +295,10 @@ bool CGLDevice::Create()
// To avoid problems with scaling & lighting
glEnable(GL_RESCALE_NORMAL);
//glEnable(GL_NORMALIZE); // this needs some testing
// Minimal depth bias to avoid Z-fighting
SetDepthBias(0.001f);
//SetDepthBias(0.001f);
// Set just to be sure
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@ -380,12 +401,6 @@ void CGLDevice::SetTransform(TransformType type, const Math::Matrix &matrix)
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(m_projectionMat.Array());
}
else if (type == TRANSFORM_TEXTURE)
{
m_textureMat = matrix;
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(m_textureMat.Array());
}
else
{
assert(false);
@ -412,9 +427,9 @@ void CGLDevice::SetMaterial(const Material &material)
{
m_material = material;
glMaterialfv(GL_FRONT, GL_AMBIENT, m_material.ambient.Array());
glMaterialfv(GL_FRONT, GL_DIFFUSE, m_material.diffuse.Array());
glMaterialfv(GL_FRONT, GL_SPECULAR, m_material.specular.Array());
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, m_material.ambient.Array());
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, m_material.diffuse.Array());
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m_material.specular.Array());
}
int CGLDevice::GetMaxLightCount()
@ -715,6 +730,81 @@ Texture CGLDevice::CreateTexture(ImageData *data, const TextureCreateParams &par
return result;
}
Texture CGLDevice::CreateDepthTexture(int width, int height, int depth)
{
Texture result;
if (m_shadowMappingSupport == SMS_NONE)
{
result.id = 0;
return result;
}
result.alpha = false;
result.size.x = width;
result.size.y = height;
// Use & enable 1st texture stage
if (m_multitextureAvailable)
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &result.id);
glBindTexture(GL_TEXTURE_2D, result.id);
GLuint format = GL_DEPTH_COMPONENT;
if (m_shadowMappingSupport == SMS_CORE)
{
switch (depth)
{
case 16:
format = GL_DEPTH_COMPONENT16;
break;
case 24:
format = GL_DEPTH_COMPONENT24;
break;
case 32:
format = GL_DEPTH_COMPONENT32;
break;
}
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_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);
}
else
{
switch (depth)
{
case 16:
format = GL_DEPTH_COMPONENT16_ARB;
break;
case 24:
format = GL_DEPTH_COMPONENT24_ARB;
break;
case 32:
format = GL_DEPTH_COMPONENT32_ARB;
break;
}
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, 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, m_currentTextures[0].id);
return result;
}
void CGLDevice::DestroyTexture(const Texture &texture)
{
// Unbind the texture if in use anywhere
@ -833,6 +923,60 @@ void CGLDevice::SetTextureStageParams(int index, const TextureStageParams &param
UpdateTextureParams(index);
}
void CGLDevice::SetTextureCoordGeneration(int index, TextureGenerationParams &params)
{
if (!m_multitextureAvailable && index != 0)
return;
if (m_multitextureAvailable)
glActiveTexture(GL_TEXTURE0 + index);
for (int i = 0; i < 4; i++)
{
GLuint texCoordGen = textureCoordGen[i];
GLuint texCoord = textureCoordinates[i];
if (params.coords[i].mode == TEX_GEN_NONE)
{
glDisable(texCoordGen);
}
else
{
glEnable(texCoordGen);
switch (params.coords[i].mode)
{
case TEX_GEN_OBJECT_LINEAR:
glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGenfv(texCoord, GL_OBJECT_PLANE, params.coords[i].plane);
break;
case TEX_GEN_EYE_LINEAR:
glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(texCoord, GL_EYE_PLANE, params.coords[i].plane);
break;
case TEX_GEN_SPHERE_MAP:
glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
break;
case TEX_GEN_NORMAL_MAP:
glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
break;
case TEX_GEN_REFLECTION_MAP:
glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
break;
}
}
}
}
void CGLDevice::SetTextureMatrix(int index, Math::Matrix& matrix)
{
if (!m_multitextureAvailable && index != 0)
return;
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(matrix.Array());
}
void CGLDevice::UpdateTextureParams(int index)
{
assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() ));
@ -851,12 +995,16 @@ void CGLDevice::UpdateTextureParams(int index)
if (params.wrapS == TEX_WRAP_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
else if (params.wrapS == TEX_WRAP_CLAMP_TO_BORDER)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
else if (params.wrapS == TEX_WRAP_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
else assert(false);
if (params.wrapT == TEX_WRAP_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
else if (params.wrapT == TEX_WRAP_CLAMP_TO_BORDER)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
else if (params.wrapT == TEX_WRAP_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
else assert(false);
@ -987,15 +1135,19 @@ void CGLDevice::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wr
if (m_multitextureAvailable)
glActiveTexture(GL_TEXTURE0 + index);
if (wrapS == TEX_WRAP_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
else if (wrapS == TEX_WRAP_CLAMP_TO_BORDER)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
else if (wrapS == TEX_WRAP_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
else assert(false);
if (wrapT == TEX_WRAP_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
else if (wrapT == TEX_WRAP_CLAMP_TO_BORDER)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
else if (wrapT == TEX_WRAP_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
else assert(false);
@ -1546,6 +1698,11 @@ int CGLDevice::ComputeSphereVisibility(const Math::Vector &center, float radius)
return result;
}
void CGLDevice::SetViewport(int x, int y, int width, int height)
{
glViewport(x, y, width, height);
}
void CGLDevice::SetRenderState(RenderState state, bool enabled)
{
if (state == RENDER_STATE_DEPTH_WRITE)
@ -1580,6 +1737,7 @@ void CGLDevice::SetRenderState(RenderState state, bool enabled)
case RENDER_STATE_DEPTH_TEST: flag = GL_DEPTH_TEST; break;
case RENDER_STATE_ALPHA_TEST: flag = GL_ALPHA_TEST; break;
case RENDER_STATE_CULLING: flag = GL_CULL_FACE; break;
case RENDER_STATE_DEPTH_BIAS: flag = GL_POLYGON_OFFSET_FILL; break;
default: assert(false); break;
}
@ -1623,14 +1781,19 @@ GLenum TranslateGfxCompFunc(CompFunc func)
return 0;
}
void CGLDevice::SetColorMask(bool red, bool green, bool blue, bool alpha)
{
glColorMask(red, green, blue, alpha);
}
void CGLDevice::SetDepthTestFunc(CompFunc func)
{
glDepthFunc(TranslateGfxCompFunc(func));
}
void CGLDevice::SetDepthBias(float factor)
void CGLDevice::SetDepthBias(float factor, float units)
{
glPolygonOffset(factor, 0.0f);
glPolygonOffset(factor, units);
}
void CGLDevice::SetAlphaTestFunc(CompFunc func, float refValue)
@ -1731,6 +1894,21 @@ void CGLDevice::SetFillMode(FillMode mode)
else assert(false);
}
void CGLDevice::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
{
if (texture.id == 0) return;
// Use & enable 1st texture stage
if (m_multitextureAvailable)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.id);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height);
// Restore previous texture
glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
}
void* CGLDevice::GetFrameBufferPixels()const{
GLubyte* pixels = new GLubyte[4 * m_config.size.x * m_config.size.y];

View File

@ -58,6 +58,13 @@ enum VertexBufferType
VBT_VBO_ARB //! use ARB extension VBOs
};
enum ShadowMappingSupport
{
SMS_NONE, //! No support for depth textures
SMS_ARB, //! ARB extension
SMS_CORE //! Core support
};
/**
\struct GLDeviceConfig
\brief Additional config with OpenGL-specific settings */
@ -132,6 +139,7 @@ public:
virtual Texture CreateTexture(CImage *image, const TextureCreateParams &params) OVERRIDE;
virtual Texture CreateTexture(ImageData *data, const TextureCreateParams &params) OVERRIDE;
virtual Texture CreateDepthTexture(int width, int height, int depth) OVERRIDE;
virtual void DestroyTexture(const Texture &texture) OVERRIDE;
virtual void DestroyAllTextures() OVERRIDE;
@ -143,6 +151,8 @@ public:
virtual void SetTextureStageParams(int index, const TextureStageParams &params) OVERRIDE;
virtual void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) OVERRIDE;
virtual void SetTextureCoordGeneration(int index, TextureGenerationParams &params) OVERRIDE;
virtual void SetTextureMatrix(int index, Math::Matrix& matrix) OVERRIDE;
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) OVERRIDE;
@ -161,11 +171,15 @@ public:
virtual int ComputeSphereVisibility(const Math::Vector &center, float radius) OVERRIDE;
virtual void SetViewport(int x, int y, int width, int height) OVERRIDE;
virtual void SetRenderState(RenderState state, bool enabled) OVERRIDE;
virtual void SetColorMask(bool red, bool green, bool blue, bool alpha) OVERRIDE;
virtual void SetDepthTestFunc(CompFunc func) OVERRIDE;
virtual void SetDepthBias(float factor) OVERRIDE;
virtual void SetDepthBias(float factor, float units) OVERRIDE;
virtual void SetAlphaTestFunc(CompFunc func, float refValue) OVERRIDE;
@ -181,7 +195,9 @@ public:
virtual void SetShadeModel(ShadeModel model) OVERRIDE;
virtual void SetFillMode(FillMode mode) OVERRIDE;
virtual void SetFillMode(FillMode mode) OVERRIDE;
virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) OVERRIDE;
virtual void* GetFrameBufferPixels() const OVERRIDE;
@ -205,8 +221,6 @@ private:
Math::Matrix m_modelviewMat;
//! Current projection matrix
Math::Matrix m_projectionMat;
//! Current texture matrix
Math::Matrix m_textureMat;
//! The current material
Material m_material;
@ -245,6 +259,11 @@ private:
int vertexCount;
};
//! Detected capabilities
//! OpenGL version
int m_glMajor, m_glMinor;
//! Depth texture support
ShadowMappingSupport m_shadowMappingSupport;
//! Whether to use multitexturing
bool m_multitextureAvailable;
//! Whether to use VBOs or display lists