WINTERMUTE: Render shadow volume using VBOs and shaders
This commit is contained in:
parent
781608e2e9
commit
3864ad1dd8
17 changed files with 575 additions and 145 deletions
|
@ -576,7 +576,7 @@ bool AdObject3D::skipTo(int x, int y, bool tolerant) {
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
ShadowVolume *AdObject3D::getShadowVolume() {
|
ShadowVolume *AdObject3D::getShadowVolume() {
|
||||||
if (_shadowVolume == nullptr) {
|
if (_shadowVolume == nullptr) {
|
||||||
_shadowVolume = new ShadowVolume(_gameRef);
|
_shadowVolume = _gameRef->_renderer3D->createShadowVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _shadowVolume;
|
return _shadowVolume;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "engines/wintermute/base/gfx/opengl/camera3d.h"
|
#include "engines/wintermute/base/gfx/opengl/camera3d.h"
|
||||||
#include "engines/wintermute/base/gfx/opengl/mesh3ds_opengl.h"
|
#include "engines/wintermute/base/gfx/opengl/mesh3ds_opengl.h"
|
||||||
#include "engines/wintermute/base/gfx/opengl/meshx_opengl.h"
|
#include "engines/wintermute/base/gfx/opengl/meshx_opengl.h"
|
||||||
|
#include "engines/wintermute/base/gfx/opengl/shadow_volume_opengl.h"
|
||||||
#include "graphics/opengl/system_headers.h"
|
#include "graphics/opengl/system_headers.h"
|
||||||
#include "math/glmath.h"
|
#include "math/glmath.h"
|
||||||
|
|
||||||
|
@ -614,4 +615,8 @@ MeshX *BaseRenderOpenGL3D::createMeshX() {
|
||||||
return new MeshXOpenGL(_gameRef);
|
return new MeshXOpenGL(_gameRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShadowVolume *BaseRenderOpenGL3D::createShadowVolume() {
|
||||||
|
return new ShadowVolumeOpenGL(_gameRef);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Wintermute
|
} // namespace Wintermute
|
||||||
|
|
|
@ -179,6 +179,7 @@ public:
|
||||||
|
|
||||||
Mesh3DS *createMesh3DS() override;
|
Mesh3DS *createMesh3DS() override;
|
||||||
MeshX *createMeshX() override;
|
MeshX *createMeshX() override;
|
||||||
|
ShadowVolume *createShadowVolume() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Math::Matrix4 _lastProjectionMatrix;
|
Math::Matrix4 _lastProjectionMatrix;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "engines/wintermute/base/gfx/opengl/camera3d.h"
|
#include "engines/wintermute/base/gfx/opengl/camera3d.h"
|
||||||
#include "engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h"
|
#include "engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h"
|
||||||
#include "engines/wintermute/base/gfx/opengl/meshx_opengl_shader.h"
|
#include "engines/wintermute/base/gfx/opengl/meshx_opengl_shader.h"
|
||||||
|
#include "engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.h"
|
||||||
#include "graphics/opengl/system_headers.h"
|
#include "graphics/opengl/system_headers.h"
|
||||||
#include "math/glmath.h"
|
#include "math/glmath.h"
|
||||||
|
|
||||||
|
@ -279,6 +280,9 @@ bool BaseRenderOpenGL3DShader::setProjection2D() {
|
||||||
_projectionMatrix2d(3, 0) = -1.0f;
|
_projectionMatrix2d(3, 0) = -1.0f;
|
||||||
_projectionMatrix2d(3, 1) = -1.0f;
|
_projectionMatrix2d(3, 1) = -1.0f;
|
||||||
_projectionMatrix2d(3, 2) = -(farPlane + nearPlane) / (farPlane - nearPlane);
|
_projectionMatrix2d(3, 2) = -(farPlane + nearPlane) / (farPlane - nearPlane);
|
||||||
|
|
||||||
|
_shadowMaskShader->use();
|
||||||
|
_shadowMaskShader->setUniform("projMatrix", _projectionMatrix2d);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +306,9 @@ void BaseRenderOpenGL3DShader::pushWorldTransform(const Math::Matrix4 &transform
|
||||||
_modelXShader->use();
|
_modelXShader->use();
|
||||||
_modelXShader->setUniform("modelMatrix", newTop);
|
_modelXShader->setUniform("modelMatrix", newTop);
|
||||||
_modelXShader->setUniform("normalMatrix", newInvertedTranspose);
|
_modelXShader->setUniform("normalMatrix", newInvertedTranspose);
|
||||||
|
|
||||||
|
_shadowVolumeShader->use();
|
||||||
|
_shadowVolumeShader->setUniform("modelMatrix", newTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseRenderOpenGL3DShader::popWorldTransform() {
|
void BaseRenderOpenGL3DShader::popWorldTransform() {
|
||||||
|
@ -317,6 +324,9 @@ void BaseRenderOpenGL3DShader::popWorldTransform() {
|
||||||
_modelXShader->use();
|
_modelXShader->use();
|
||||||
_modelXShader->setUniform("modelMatrix", currentTransform);
|
_modelXShader->setUniform("modelMatrix", currentTransform);
|
||||||
_modelXShader->setUniform("normalMatrix", currentInvertedTranspose);
|
_modelXShader->setUniform("normalMatrix", currentInvertedTranspose);
|
||||||
|
|
||||||
|
_shadowVolumeShader->use();
|
||||||
|
_shadowVolumeShader->setUniform("modelMatrix", currentTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseRenderOpenGL3DShader::windowedBlt() {
|
bool BaseRenderOpenGL3DShader::windowedBlt() {
|
||||||
|
@ -350,6 +360,12 @@ bool BaseRenderOpenGL3DShader::initRenderer(int width, int height, bool windowed
|
||||||
static const char *geometryAttributes[] = { "position", nullptr };
|
static const char *geometryAttributes[] = { "position", nullptr };
|
||||||
_geometryShader = OpenGL::Shader::fromFiles("geometry", geometryAttributes);
|
_geometryShader = OpenGL::Shader::fromFiles("geometry", geometryAttributes);
|
||||||
|
|
||||||
|
static const char *shadowVolumeAttributes[] = { "position", nullptr };
|
||||||
|
_shadowVolumeShader = OpenGL::Shader::fromFiles("shadow_volume", shadowVolumeAttributes);
|
||||||
|
|
||||||
|
static const char *shadowMaskAttributes[] = { "position", nullptr };
|
||||||
|
_shadowMaskShader = OpenGL::Shader::fromFiles("shadow_mask", shadowMaskAttributes);
|
||||||
|
|
||||||
_transformStack.push_back(Math::Matrix4());
|
_transformStack.push_back(Math::Matrix4());
|
||||||
_transformStack.back().setToIdentity();
|
_transformStack.back().setToIdentity();
|
||||||
|
|
||||||
|
@ -496,6 +512,10 @@ bool BaseRenderOpenGL3DShader::setup3D(Camera3D *camera, bool force) {
|
||||||
_geometryShader->setUniform("viewMatrix", _lastViewMatrix);
|
_geometryShader->setUniform("viewMatrix", _lastViewMatrix);
|
||||||
_geometryShader->setUniform("projMatrix", _projectionMatrix3d);
|
_geometryShader->setUniform("projMatrix", _projectionMatrix3d);
|
||||||
|
|
||||||
|
_shadowVolumeShader->use();
|
||||||
|
_shadowVolumeShader->setUniform("viewMatrix", _lastViewMatrix);
|
||||||
|
_shadowVolumeShader->setUniform("projMatrix", _projectionMatrix3d);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,4 +677,8 @@ MeshX *BaseRenderOpenGL3DShader::createMeshX() {
|
||||||
return new MeshXOpenGLShader(_gameRef, _modelXShader);
|
return new MeshXOpenGLShader(_gameRef, _modelXShader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShadowVolume *BaseRenderOpenGL3DShader::createShadowVolume() {
|
||||||
|
return new ShadowVolumeOpenGLShader(_gameRef, _shadowVolumeShader, _shadowMaskShader);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Wintermute
|
} // namespace Wintermute
|
||||||
|
|
|
@ -180,6 +180,7 @@ public:
|
||||||
|
|
||||||
Mesh3DS *createMesh3DS() override;
|
Mesh3DS *createMesh3DS() override;
|
||||||
MeshX *createMeshX() override;
|
MeshX *createMeshX() override;
|
||||||
|
ShadowVolume *createShadowVolume() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Math::Matrix4 _lastViewMatrix;
|
Math::Matrix4 _lastViewMatrix;
|
||||||
|
@ -199,6 +200,8 @@ private:
|
||||||
OpenGL::Shader *_fadeShader;
|
OpenGL::Shader *_fadeShader;
|
||||||
OpenGL::Shader *_modelXShader;
|
OpenGL::Shader *_modelXShader;
|
||||||
OpenGL::Shader *_geometryShader;
|
OpenGL::Shader *_geometryShader;
|
||||||
|
OpenGL::Shader *_shadowVolumeShader;
|
||||||
|
OpenGL::Shader *_shadowMaskShader;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Wintermute
|
} // namespace Wintermute
|
||||||
|
|
|
@ -38,6 +38,7 @@ namespace Wintermute {
|
||||||
class BaseSurfaceOpenGL3D;
|
class BaseSurfaceOpenGL3D;
|
||||||
class Mesh3DS;
|
class Mesh3DS;
|
||||||
class MeshX;
|
class MeshX;
|
||||||
|
class ShadowVolume;
|
||||||
|
|
||||||
class BaseRenderer3D : public BaseRenderer {
|
class BaseRenderer3D : public BaseRenderer {
|
||||||
public:
|
public:
|
||||||
|
@ -74,6 +75,7 @@ public:
|
||||||
|
|
||||||
virtual Mesh3DS *createMesh3DS() = 0;
|
virtual Mesh3DS *createMesh3DS() = 0;
|
||||||
virtual MeshX *createMeshX() = 0;
|
virtual MeshX *createMeshX() = 0;
|
||||||
|
virtual ShadowVolume *createShadowVolume() = 0;
|
||||||
|
|
||||||
virtual bool drawSprite(BaseSurfaceOpenGL3D &tex, const Rect32 &rect, float zoomX, float zoomY, const Vector2 &pos,
|
virtual bool drawSprite(BaseSurfaceOpenGL3D &tex, const Rect32 &rect, float zoomX, float zoomY, const Vector2 &pos,
|
||||||
uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) = 0;
|
uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) = 0;
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
in vec4 Color;
|
||||||
|
|
||||||
|
OUTPUT
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
outColor = Color;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
in vec2 position;
|
||||||
|
|
||||||
|
uniform highp mat4 projMatrix;
|
||||||
|
uniform vec4 color;
|
||||||
|
|
||||||
|
out vec4 Color;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = projMatrix * vec4(position, 0.0f, 1.0f);
|
||||||
|
Color = color;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
in vec3 position;
|
||||||
|
|
||||||
|
uniform highp mat4 modelMatrix;
|
||||||
|
uniform highp mat4 viewMatrix;
|
||||||
|
uniform highp mat4 projMatrix;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = projMatrix * viewMatrix * modelMatrix * vec4(position, 1.0f);
|
||||||
|
}
|
|
@ -53,143 +53,6 @@ void ShadowVolume::addVertex(const Math::Vector3d &vertex) {
|
||||||
_vertices.add(vertex);
|
_vertices.add(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
bool ShadowVolume::render() {
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
glVertexPointer(3, GL_FLOAT, 0, _vertices.data());
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, _vertices.size());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
bool ShadowVolume::renderToStencilBuffer() {
|
|
||||||
// Disable z-buffer writes (note: z-testing still occurs), and enable the
|
|
||||||
// stencil-buffer
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
glEnable(GL_STENCIL_TEST);
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
|
|
||||||
// Set up stencil compare fuction, reference value, and masks.
|
|
||||||
// Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.
|
|
||||||
// Note: since we set up the stencil-test to always pass, the STENCILFAIL
|
|
||||||
// renderstate is really not needed.
|
|
||||||
glStencilFunc(GL_ALWAYS, 0x1, 0xFFFFFFFF);
|
|
||||||
|
|
||||||
glShadeModel(GL_FLAT);
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
|
|
||||||
// Make sure that no pixels get drawn to the frame buffer
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_ZERO, GL_ONE);
|
|
||||||
|
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
|
||||||
|
|
||||||
// Draw back-side of shadow volume in stencil/z only
|
|
||||||
glCullFace(GL_FRONT);
|
|
||||||
render();
|
|
||||||
|
|
||||||
// // Decrement stencil buffer value
|
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
|
|
||||||
|
|
||||||
// Draw front-side of shadow volume in stencil/z only
|
|
||||||
glCullFace(GL_BACK);
|
|
||||||
render();
|
|
||||||
|
|
||||||
// // Restore render states
|
|
||||||
glEnable(GL_LIGHTING);
|
|
||||||
glFrontFace(GL_CCW);
|
|
||||||
glShadeModel(GL_SMOOTH);
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
glDisable(GL_STENCIL_TEST);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
bool ShadowVolume::renderToScene() {
|
|
||||||
initMask();
|
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glEnable(GL_STENCIL_TEST);
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
|
|
||||||
// Only write where stencil val >= 1 (count indicates # of shadows that overlap that pixel)
|
|
||||||
glStencilFunc(GL_LEQUAL, 0x1, 0xFFFFFFFF);
|
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
|
||||||
|
|
||||||
glDisable(GL_FOG);
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
glDisable(GL_ALPHA_TEST);
|
|
||||||
|
|
||||||
_gameRef->_renderer3D->setProjection2D();
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
|
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
|
|
||||||
// Draw a big, gray square
|
|
||||||
glInterleavedArrays(GL_C4UB_V3F, 0, _shadowMask);
|
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
||||||
|
|
||||||
// Restore render states
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glDisable(GL_STENCIL_TEST);
|
|
||||||
|
|
||||||
_gameRef->_renderer3D->setup3D(nullptr, true);
|
|
||||||
|
|
||||||
// clear stencil buffer
|
|
||||||
glClearStencil(0);
|
|
||||||
glClear(GL_STENCIL_BUFFER_BIT);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
bool ShadowVolume::initMask() {
|
|
||||||
Rect32 viewport = _gameRef->_renderer->getViewPort();
|
|
||||||
|
|
||||||
_shadowMask[0].x = viewport.left;
|
|
||||||
_shadowMask[0].y = viewport.bottom;
|
|
||||||
_shadowMask[0].z = 0.0f;
|
|
||||||
|
|
||||||
_shadowMask[1].x = viewport.left;
|
|
||||||
_shadowMask[1].y = viewport.top;
|
|
||||||
_shadowMask[1].z = 0.0f;
|
|
||||||
|
|
||||||
_shadowMask[2].x = viewport.right;
|
|
||||||
_shadowMask[2].y = viewport.bottom;
|
|
||||||
_shadowMask[2].z = 0.0f;
|
|
||||||
|
|
||||||
_shadowMask[3].x = viewport.right;
|
|
||||||
_shadowMask[3].y = viewport.top;
|
|
||||||
_shadowMask[3].z = 0.0f;
|
|
||||||
|
|
||||||
byte a = RGBCOLGetA(_color);
|
|
||||||
byte r = RGBCOLGetR(_color);
|
|
||||||
byte g = RGBCOLGetG(_color);
|
|
||||||
byte b = RGBCOLGetB(_color);
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
|
||||||
_shadowMask[i].r = r;
|
|
||||||
_shadowMask[i].g = g;
|
|
||||||
_shadowMask[i].b = b;
|
|
||||||
_shadowMask[i].a = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
bool ShadowVolume::setColor(uint32 color) {
|
bool ShadowVolume::setColor(uint32 color) {
|
||||||
if (color != _color) {
|
if (color != _color) {
|
||||||
|
|
|
@ -58,17 +58,17 @@ public:
|
||||||
void addVertex(const Math::Vector3d &vertex);
|
void addVertex(const Math::Vector3d &vertex);
|
||||||
bool reset();
|
bool reset();
|
||||||
|
|
||||||
bool renderToStencilBuffer();
|
virtual bool renderToStencilBuffer() = 0;
|
||||||
bool renderToScene();
|
virtual bool renderToScene() = 0;
|
||||||
|
|
||||||
bool setColor(uint32 color);
|
bool setColor(uint32 color);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
bool render();
|
|
||||||
ShadowVertex _shadowMask[4];
|
|
||||||
uint32 _color;
|
|
||||||
bool initMask();
|
|
||||||
BaseArray<Math::Vector3d> _vertices; // Vertex data for rendering shadow volume
|
BaseArray<Math::Vector3d> _vertices; // Vertex data for rendering shadow volume
|
||||||
|
uint32 _color;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual bool initMask() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Wintermute
|
} // namespace Wintermute
|
||||||
|
|
182
engines/wintermute/base/gfx/opengl/shadow_volume_opengl.cpp
Normal file
182
engines/wintermute/base/gfx/opengl/shadow_volume_opengl.cpp
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is based on WME.
|
||||||
|
* http://dead-code.org/redir.php?target=wme
|
||||||
|
* Copyright (c) 2003-2013 Jan Nedoma and contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/wintermute/base/base_game.h"
|
||||||
|
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
|
||||||
|
#include "engines/wintermute/base/gfx/opengl/shadow_volume_opengl.h"
|
||||||
|
#include "engines/wintermute/dcgf.h"
|
||||||
|
#include "graphics/opengl/system_headers.h"
|
||||||
|
|
||||||
|
namespace Wintermute {
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
ShadowVolumeOpenGL::ShadowVolumeOpenGL(BaseGame *inGame) : ShadowVolume(inGame) {
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
ShadowVolumeOpenGL::~ShadowVolumeOpenGL() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
bool ShadowVolumeOpenGL::render() {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glVertexPointer(3, GL_FLOAT, 0, _vertices.data());
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, _vertices.size());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
bool ShadowVolumeOpenGL::renderToStencilBuffer() {
|
||||||
|
// Disable z-buffer writes (note: z-testing still occurs), and enable the
|
||||||
|
// stencil-buffer
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
// Set up stencil compare fuction, reference value, and masks.
|
||||||
|
// Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.
|
||||||
|
// Note: since we set up the stencil-test to always pass, the STENCILFAIL
|
||||||
|
// renderstate is really not needed.
|
||||||
|
glStencilFunc(GL_ALWAYS, 0x1, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
glShadeModel(GL_FLAT);
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
|
||||||
|
// Make sure that no pixels get drawn to the frame buffer
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_ZERO, GL_ONE);
|
||||||
|
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
||||||
|
|
||||||
|
// Draw back-side of shadow volume in stencil/z only
|
||||||
|
glCullFace(GL_FRONT);
|
||||||
|
render();
|
||||||
|
|
||||||
|
// // Decrement stencil buffer value
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
|
||||||
|
|
||||||
|
// Draw front-side of shadow volume in stencil/z only
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
render();
|
||||||
|
|
||||||
|
// // Restore render states
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
glFrontFace(GL_CCW);
|
||||||
|
glShadeModel(GL_SMOOTH);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
bool ShadowVolumeOpenGL::renderToScene() {
|
||||||
|
initMask();
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
// Only write where stencil val >= 1 (count indicates # of shadows that overlap that pixel)
|
||||||
|
glStencilFunc(GL_LEQUAL, 0x1, 0xFFFFFFFF);
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||||
|
|
||||||
|
glDisable(GL_FOG);
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
|
||||||
|
_gameRef->_renderer3D->setProjection2D();
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
|
// Draw a big, gray square
|
||||||
|
glInterleavedArrays(GL_C4UB_V3F, 0, _shadowMask);
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
// Restore render states
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
_gameRef->_renderer3D->setup3D(nullptr, true);
|
||||||
|
|
||||||
|
// clear stencil buffer
|
||||||
|
glClearStencil(0);
|
||||||
|
glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
bool ShadowVolumeOpenGL::initMask() {
|
||||||
|
Rect32 viewport = _gameRef->_renderer->getViewPort();
|
||||||
|
|
||||||
|
_shadowMask[0].x = viewport.left;
|
||||||
|
_shadowMask[0].y = viewport.bottom;
|
||||||
|
_shadowMask[0].z = 0.0f;
|
||||||
|
|
||||||
|
_shadowMask[1].x = viewport.left;
|
||||||
|
_shadowMask[1].y = viewport.top;
|
||||||
|
_shadowMask[1].z = 0.0f;
|
||||||
|
|
||||||
|
_shadowMask[2].x = viewport.right;
|
||||||
|
_shadowMask[2].y = viewport.bottom;
|
||||||
|
_shadowMask[2].z = 0.0f;
|
||||||
|
|
||||||
|
_shadowMask[3].x = viewport.right;
|
||||||
|
_shadowMask[3].y = viewport.top;
|
||||||
|
_shadowMask[3].z = 0.0f;
|
||||||
|
|
||||||
|
byte a = RGBCOLGetA(_color);
|
||||||
|
byte r = RGBCOLGetR(_color);
|
||||||
|
byte g = RGBCOLGetG(_color);
|
||||||
|
byte b = RGBCOLGetB(_color);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
_shadowMask[i].r = r;
|
||||||
|
_shadowMask[i].g = g;
|
||||||
|
_shadowMask[i].b = b;
|
||||||
|
_shadowMask[i].a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Wintermute
|
52
engines/wintermute/base/gfx/opengl/shadow_volume_opengl.h
Normal file
52
engines/wintermute/base/gfx/opengl/shadow_volume_opengl.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is based on WME.
|
||||||
|
* http://dead-code.org/redir.php?target=wme
|
||||||
|
* Copyright (c) 2003-2013 Jan Nedoma and contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WINTERMUTE_SHADOW_VOLUME_OPENGL_H
|
||||||
|
#define WINTERMUTE_SHADOW_VOLUME_OPENGL_H
|
||||||
|
|
||||||
|
#include "engines/wintermute/base/gfx/opengl/shadow_volume.h"
|
||||||
|
|
||||||
|
namespace Wintermute {
|
||||||
|
|
||||||
|
class ShadowVolumeOpenGL : public ShadowVolume {
|
||||||
|
public:
|
||||||
|
ShadowVolumeOpenGL(BaseGame *inGame);
|
||||||
|
virtual ~ShadowVolumeOpenGL();
|
||||||
|
|
||||||
|
bool renderToStencilBuffer() override;
|
||||||
|
bool renderToScene() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool render();
|
||||||
|
ShadowVertex _shadowMask[4];
|
||||||
|
bool initMask();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Wintermute
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,205 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is based on WME.
|
||||||
|
* http://dead-code.org/redir.php?target=wme
|
||||||
|
* Copyright (c) 2003-2013 Jan Nedoma and contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/wintermute/base/base_game.h"
|
||||||
|
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
|
||||||
|
#include "engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.h"
|
||||||
|
#include "engines/wintermute/dcgf.h"
|
||||||
|
#include "graphics/opengl/system_headers.h"
|
||||||
|
|
||||||
|
namespace Wintermute {
|
||||||
|
|
||||||
|
#include "common/pack-start.h"
|
||||||
|
|
||||||
|
struct ShadowVertexShader {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
} PACKED_STRUCT;
|
||||||
|
|
||||||
|
#include "common/pack-end.h"
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
ShadowVolumeOpenGLShader::ShadowVolumeOpenGLShader(BaseGame *inGame, OpenGL::Shader *volumeShader, OpenGL::Shader *maskShader)
|
||||||
|
: ShadowVolume(inGame), _color(0x7f000000), _volumeShader(volumeShader), _maskShader(maskShader) {
|
||||||
|
ShadowVertexShader shadowMask[4];
|
||||||
|
Rect32 viewport = _gameRef->_renderer->getViewPort();
|
||||||
|
|
||||||
|
shadowMask[0].x = viewport.left;
|
||||||
|
shadowMask[0].y = viewport.bottom;
|
||||||
|
|
||||||
|
shadowMask[1].x = viewport.left;
|
||||||
|
shadowMask[1].y = viewport.top;
|
||||||
|
|
||||||
|
shadowMask[2].x = viewport.right;
|
||||||
|
shadowMask[2].y = viewport.bottom;
|
||||||
|
|
||||||
|
shadowMask[3].x = viewport.right;
|
||||||
|
shadowMask[3].y = viewport.top;
|
||||||
|
|
||||||
|
glGenBuffers(1, &_shadowMaskVertexBuffer);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _shadowMaskVertexBuffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(ShadowVertexShader), shadowMask, GL_DYNAMIC_DRAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
ShadowVolumeOpenGLShader::~ShadowVolumeOpenGLShader() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
bool ShadowVolumeOpenGLShader::render() {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, _vertices.size());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
bool ShadowVolumeOpenGLShader::renderToStencilBuffer() {
|
||||||
|
// since the vertex count of the volume might change,
|
||||||
|
// we just create a new buffer per frame
|
||||||
|
// we might as well use the number of vertices of the mesh as an upper bound
|
||||||
|
// or get rid of this completely by moving everything onto the gpu
|
||||||
|
glDeleteBuffers(1, &_shadowVolumeVertexBuffer);
|
||||||
|
glGenBuffers(1, &_shadowVolumeVertexBuffer);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _shadowVolumeVertexBuffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, 12 * _vertices.size(), _vertices.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
_volumeShader->enableVertexAttribute("position", _shadowVolumeVertexBuffer, 3, GL_FLOAT, false, 12, 0);
|
||||||
|
_volumeShader->use(true);
|
||||||
|
|
||||||
|
// Disable z-buffer writes (note: z-testing still occurs), and enable the
|
||||||
|
// stencil-buffer
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
// Set up stencil compare fuction, reference value, and masks.
|
||||||
|
// Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.
|
||||||
|
// Note: since we set up the stencil-test to always pass, the STENCILFAIL
|
||||||
|
// renderstate is really not needed.
|
||||||
|
glStencilFunc(GL_ALWAYS, 0x1, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
glShadeModel(GL_FLAT);
|
||||||
|
|
||||||
|
// Make sure that no pixels get drawn to the frame buffer
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_ZERO, GL_ONE);
|
||||||
|
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
||||||
|
|
||||||
|
// Draw back-side of shadow volume in stencil/z only
|
||||||
|
glCullFace(GL_FRONT);
|
||||||
|
render();
|
||||||
|
|
||||||
|
// // Decrement stencil buffer value
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
|
||||||
|
|
||||||
|
// Draw front-side of shadow volume in stencil/z only
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
render();
|
||||||
|
|
||||||
|
// // Restore render states
|
||||||
|
glFrontFace(GL_CCW);
|
||||||
|
glShadeModel(GL_SMOOTH);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
bool ShadowVolumeOpenGLShader::renderToScene() {
|
||||||
|
initMask();
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
// Only write where stencil val >= 1 (count indicates # of shadows that overlap that pixel)
|
||||||
|
glStencilFunc(GL_LEQUAL, 0x1, 0xFFFFFFFF);
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||||
|
|
||||||
|
_gameRef->_renderer3D->setProjection2D();
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
_maskShader->enableVertexAttribute("position", _shadowMaskVertexBuffer, 2, GL_FLOAT, false, 8, 0);
|
||||||
|
_maskShader->use(true);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
// Restore render states
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
_gameRef->_renderer3D->setup3D(nullptr, true);
|
||||||
|
|
||||||
|
// clear stencil buffer
|
||||||
|
glClearStencil(0);
|
||||||
|
glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
bool ShadowVolumeOpenGLShader::initMask() {
|
||||||
|
Rect32 viewport = _gameRef->_renderer->getViewPort();
|
||||||
|
|
||||||
|
ShadowVertexShader shadowMask[4];
|
||||||
|
|
||||||
|
shadowMask[0].x = viewport.left;
|
||||||
|
shadowMask[0].y = viewport.bottom;
|
||||||
|
|
||||||
|
shadowMask[1].x = viewport.left;
|
||||||
|
shadowMask[1].y = viewport.top;
|
||||||
|
|
||||||
|
shadowMask[2].x = viewport.right;
|
||||||
|
shadowMask[2].y = viewport.bottom;
|
||||||
|
|
||||||
|
shadowMask[3].x = viewport.right;
|
||||||
|
shadowMask[3].y = viewport.top;
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, _shadowMaskVertexBuffer);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * sizeof(ShadowVertexShader), shadowMask);
|
||||||
|
|
||||||
|
Math::Vector4d color;
|
||||||
|
|
||||||
|
color.x() = RGBCOLGetR(_color) / 255.0f;
|
||||||
|
color.y() = RGBCOLGetG(_color) / 255.0f;
|
||||||
|
color.z() = RGBCOLGetB(_color) / 255.0f;
|
||||||
|
color.w() = RGBCOLGetA(_color) / 255.0f;
|
||||||
|
|
||||||
|
_maskShader->use();
|
||||||
|
_maskShader->setUniform("color", color);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Wintermute
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* 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 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is based on WME.
|
||||||
|
* http://dead-code.org/redir.php?target=wme
|
||||||
|
* Copyright (c) 2003-2013 Jan Nedoma and contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WINTERMUTE_SHADOW_VOLUME_OPENGL_SHADER_H
|
||||||
|
#define WINTERMUTE_SHADOW_VOLUME_OPENGL_SHADER_H
|
||||||
|
|
||||||
|
#include "engines/wintermute/base/gfx/opengl/shadow_volume.h"
|
||||||
|
#include "graphics/opengl/shader.h"
|
||||||
|
#include "graphics/opengl/system_headers.h"
|
||||||
|
|
||||||
|
namespace Wintermute {
|
||||||
|
|
||||||
|
class ShadowVolumeOpenGLShader : public ShadowVolume {
|
||||||
|
public:
|
||||||
|
ShadowVolumeOpenGLShader(BaseGame *inGame, OpenGL::Shader *volumeShader, OpenGL::Shader *maskShader);
|
||||||
|
virtual ~ShadowVolumeOpenGLShader();
|
||||||
|
|
||||||
|
bool renderToStencilBuffer() override;
|
||||||
|
bool renderToScene() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool render();
|
||||||
|
uint32 _color;
|
||||||
|
bool initMask() override;
|
||||||
|
GLuint _shadowVolumeVertexBuffer;
|
||||||
|
GLuint _shadowMaskVertexBuffer;
|
||||||
|
OpenGL::Shader *_volumeShader;
|
||||||
|
OpenGL::Shader *_maskShader;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Wintermute
|
||||||
|
|
||||||
|
#endif
|
|
@ -87,6 +87,8 @@ MODULE_OBJS := \
|
||||||
base/gfx/opengl/mesh3ds_opengl_shader.o \
|
base/gfx/opengl/mesh3ds_opengl_shader.o \
|
||||||
base/gfx/opengl/loader3ds.o \
|
base/gfx/opengl/loader3ds.o \
|
||||||
base/gfx/opengl/shadow_volume.o \
|
base/gfx/opengl/shadow_volume.o \
|
||||||
|
base/gfx/opengl/shadow_volume_opengl.o \
|
||||||
|
base/gfx/opengl/shadow_volume_opengl_shader.o \
|
||||||
base/gfx/x/active_animation.o \
|
base/gfx/x/active_animation.o \
|
||||||
base/gfx/x/animation.o \
|
base/gfx/x/animation.o \
|
||||||
base/gfx/x/animation_channel.o \
|
base/gfx/x/animation_channel.o \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue