1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 /*
24 * This file is based on WME.
25 * http://dead-code.org/redir.php?target=wme
26 * Copyright (c) 2003-2013 Jan Nedoma and contributors
27 */
28
29 #include "engines/wintermute/base/base_game.h"
30 #include "engines/wintermute/dcgf.h"
31 #include "graphics/opengl/system_headers.h"
32
33 #if (defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)) && !defined(USE_GLES2)
34
35 #include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
36 #include "engines/wintermute/base/gfx/opengl/shadow_volume_opengl.h"
37
38 namespace Wintermute {
39
40 //////////////////////////////////////////////////////////////////////////
ShadowVolumeOpenGL(BaseGame * inGame)41 ShadowVolumeOpenGL::ShadowVolumeOpenGL(BaseGame *inGame) : ShadowVolume(inGame) {
42 }
43
44 //////////////////////////////////////////////////////////////////////////
~ShadowVolumeOpenGL()45 ShadowVolumeOpenGL::~ShadowVolumeOpenGL() {
46 }
47
48 //////////////////////////////////////////////////////////////////////////
render()49 bool ShadowVolumeOpenGL::render() {
50 glBindTexture(GL_TEXTURE_2D, 0);
51
52 glEnableClientState(GL_VERTEX_ARRAY);
53 glDisableClientState(GL_COLOR_ARRAY);
54 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
55 glVertexPointer(3, GL_FLOAT, 0, _vertices.data());
56 glDrawArrays(GL_TRIANGLES, 0, _vertices.size());
57
58 return true;
59 }
60
61 //////////////////////////////////////////////////////////////////////////
renderToStencilBuffer()62 bool ShadowVolumeOpenGL::renderToStencilBuffer() {
63 // Disable z-buffer writes (note: z-testing still occurs), and enable the
64 // stencil-buffer
65 glDepthMask(GL_FALSE);
66 glEnable(GL_STENCIL_TEST);
67 glEnable(GL_CULL_FACE);
68
69 // Set up stencil compare fuction, reference value, and masks.
70 // Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.
71 // Note: since we set up the stencil-test to always pass, the STENCILFAIL
72 // renderstate is really not needed.
73 glStencilFunc(GL_ALWAYS, 0x1, 0xFFFFFFFF);
74
75 glShadeModel(GL_FLAT);
76 glDisable(GL_LIGHTING);
77
78 // Make sure that no pixels get drawn to the frame buffer
79 glEnable(GL_BLEND);
80 glBlendFunc(GL_ZERO, GL_ONE);
81
82 glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
83
84 // Draw back-side of shadow volume in stencil/z only
85 glCullFace(GL_FRONT);
86 render();
87
88 // Decrement stencil buffer value
89 glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
90
91 // Draw front-side of shadow volume in stencil/z only
92 glCullFace(GL_BACK);
93 render();
94
95 // Restore render states
96 glEnable(GL_LIGHTING);
97 glFrontFace(GL_CCW);
98 glShadeModel(GL_SMOOTH);
99 glDepthMask(GL_TRUE);
100 glDisable(GL_STENCIL_TEST);
101 glDisable(GL_BLEND);
102
103 return true;
104 }
105
106 //////////////////////////////////////////////////////////////////////////
renderToScene()107 bool ShadowVolumeOpenGL::renderToScene() {
108 initMask();
109
110 glDisable(GL_DEPTH_TEST);
111 glEnable(GL_STENCIL_TEST);
112 glEnable(GL_BLEND);
113 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
114
115 // Only write where stencil val >= 1 (count indicates # of shadows that overlap that pixel)
116 glStencilFunc(GL_LEQUAL, 0x1, 0xFFFFFFFF);
117 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
118
119 glDisable(GL_FOG);
120 glDisable(GL_LIGHTING);
121 glDisable(GL_ALPHA_TEST);
122
123 _gameRef->_renderer3D->setProjection2D();
124
125 glBindTexture(GL_TEXTURE_2D, 0);
126
127 glEnableClientState(GL_COLOR_ARRAY);
128 glEnableClientState(GL_VERTEX_ARRAY);
129 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
130 glDisableClientState(GL_NORMAL_ARRAY);
131
132 // Draw a big, gray square
133 glVertexPointer(3, GL_FLOAT, sizeof(ShadowVertex), &_shadowMask[0].x);
134 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ShadowVertex), &_shadowMask[0].r);
135
136 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
137
138 // Restore render states
139 glEnable(GL_DEPTH_TEST);
140 glDisable(GL_STENCIL_TEST);
141
142 _gameRef->_renderer3D->setup3D(nullptr, true);
143
144 // clear stencil buffer
145 glClearStencil(0);
146 glClear(GL_STENCIL_BUFFER_BIT);
147
148 return true;
149 }
150
151 //////////////////////////////////////////////////////////////////////////
initMask()152 bool ShadowVolumeOpenGL::initMask() {
153 Rect32 viewport = _gameRef->_renderer->getViewPort();
154
155 _shadowMask[0].x = viewport.left;
156 _shadowMask[0].y = viewport.bottom;
157 _shadowMask[0].z = 0.0f;
158
159 _shadowMask[1].x = viewport.left;
160 _shadowMask[1].y = viewport.top;
161 _shadowMask[1].z = 0.0f;
162
163 _shadowMask[2].x = viewport.right;
164 _shadowMask[2].y = viewport.bottom;
165 _shadowMask[2].z = 0.0f;
166
167 _shadowMask[3].x = viewport.right;
168 _shadowMask[3].y = viewport.top;
169 _shadowMask[3].z = 0.0f;
170
171 byte a = RGBCOLGetA(_color);
172 byte r = RGBCOLGetR(_color);
173 byte g = RGBCOLGetG(_color);
174 byte b = RGBCOLGetB(_color);
175
176 for (int i = 0; i < 4; ++i) {
177 _shadowMask[i].r = r;
178 _shadowMask[i].g = g;
179 _shadowMask[i].b = b;
180 _shadowMask[i].a = a;
181 }
182
183 return true;
184 }
185
186 } // namespace Wintermute
187
188 #endif // defined(USE_OPENGL) && !defined(USE_GLES2)
189
190