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