1 /***********************************************************************
2 created: Tue Mar 3 2009
3 author: Paul D Turner (parts based on original code by Thomas Suter)
4 *************************************************************************/
5 /***************************************************************************
6 * Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 ***************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include "CEGUI/RendererModules/Irrlicht/GeometryBuffer.h"
32 #include "CEGUI/RenderEffect.h"
33 #include "CEGUI/RendererModules/Irrlicht/Texture.h"
34 #include "CEGUI/Vertex.h"
35 #include "CEGUI/Quaternion.h"
36
37 // Start of CEGUI namespace section
38 namespace CEGUI
39 {
40 //----------------------------------------------------------------------------//
IrrlichtGeometryBuffer(irr::video::IVideoDriver & driver)41 IrrlichtGeometryBuffer::IrrlichtGeometryBuffer(irr::video::IVideoDriver& driver):
42 d_driver(driver),
43 d_activeTexture(0),
44 d_clipRect(0, 0, 0, 0),
45 d_clippingActive(true),
46 d_translation(0, 0, 0),
47 d_rotation(0, 0, 0),
48 d_pivot(0, 0, 0),
49 d_effect(0),
50 d_matrixValid(false),
51 #if IRRLICHT_VERSION_MAJOR > 1 || (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8)
52 d_xViewDir(1.0f),
53 #else
54 d_xViewDir(driver.getDriverType() != irr::video::EDT_OPENGL ? 1.0f : -1.0f),
55 #endif
56 d_texelOffset(driver.getDriverType() != irr::video::EDT_OPENGL ? -0.5f : 0.0f)
57 {
58 d_material.BackfaceCulling = false;
59 d_material.Lighting = false;
60 d_material.ZBuffer = 0;
61 d_material.ZWriteEnable = false;
62
63 // force upate of blending options to suit the default 'normal' mode
64 d_blendMode = BM_INVALID;
65 setBlendMode(BM_NORMAL);
66 }
67
68 //----------------------------------------------------------------------------//
draw() const69 void IrrlichtGeometryBuffer::draw() const
70 {
71 if (!d_matrixValid)
72 updateMatrix();
73
74 d_driver.setTransform(irr::video::ETS_WORLD, d_matrix);
75
76 const int pass_count = d_effect ? d_effect->getPassCount() : 1;
77 for (int pass = 0; pass < pass_count; ++pass)
78 {
79 // set up RenderEffect
80 if (d_effect)
81 d_effect->performPreRenderFunctions(pass);
82
83 // draw the batches
84 size_t pos = 0;
85 BatchList::const_iterator i = d_batches.begin();
86 for ( ; i != d_batches.end(); ++i)
87 {
88 if (i->clip)
89 setupClipping();
90
91 d_material.setTexture(0, i->texture);
92 d_driver.setMaterial(d_material);
93 d_driver.drawIndexedTriangleList(&d_vertices[pos], i->vertexCount,
94 &d_indices[pos], i->vertexCount / 3);
95 pos += i->vertexCount;
96
97 if (i->clip)
98 cleanupClipping();
99 }
100 }
101
102 // clean up RenderEffect
103 if (d_effect)
104 d_effect->performPostRenderFunctions();
105 }
106
107 //----------------------------------------------------------------------------//
setupClipping() const108 void IrrlichtGeometryBuffer::setupClipping() const
109 {
110 // NB: This is done via viewport & projection manipulation because Irrlicht
111 // does not expose scissoring facilities of underlying APIs. This has the
112 // unfortunate side effect of being much more expensive to set up.
113 d_savedViewport = d_driver.getViewPort();
114 d_savedProjection = d_driver.getTransform(irr::video::ETS_PROJECTION);
115
116 const Sizef csz(d_clipRect.getSize());
117 const Sizef tsz(static_cast<float>(d_savedViewport.getWidth()),
118 static_cast<float>(d_savedViewport.getHeight()));
119
120 // set modified projection 'scissor' matix that negates scale and
121 // translation that would be done by setting the viewport to the clip area.
122 irr::core::matrix4 scsr(irr::core::matrix4::EM4CONST_IDENTITY);
123 scsr(0, 0) = tsz.d_width / csz.d_width;
124 scsr(1, 1) = tsz.d_height / csz.d_height;
125 scsr(3, 0) = d_xViewDir * (tsz.d_width + 2.0f *
126 (d_savedViewport.UpperLeftCorner.X -
127 (d_clipRect.left() + csz.d_width * 0.5f))) / csz.d_width;
128 scsr(3, 1) = -(tsz.d_height + 2.0f *
129 (d_savedViewport.UpperLeftCorner.Y -
130 (d_clipRect.top() + csz.d_height * 0.5f))) / csz.d_height;
131
132 scsr *= d_savedProjection;
133 d_driver.setTransform(irr::video::ETS_PROJECTION, scsr);
134
135 // set new viewport for the clipping area
136 const irr::core::rect<irr::s32> vp(
137 static_cast<irr::s32>(d_clipRect.left()),
138 static_cast<irr::s32>(d_clipRect.top()),
139 static_cast<irr::s32>(d_clipRect.right()),
140 static_cast<irr::s32>(d_clipRect.bottom()));
141 d_driver.setViewPort(vp);
142 }
143
144 //----------------------------------------------------------------------------//
cleanupClipping() const145 void IrrlichtGeometryBuffer::cleanupClipping() const
146 {
147 d_driver.setTransform(irr::video::ETS_PROJECTION, d_savedProjection);
148 d_driver.setViewPort(d_savedViewport);
149 }
150
151 //----------------------------------------------------------------------------//
setTranslation(const Vector3f & v)152 void IrrlichtGeometryBuffer::setTranslation(const Vector3f& v)
153 {
154 d_translation.X = v.d_x;
155 d_translation.Y = v.d_y;
156 d_translation.Z = v.d_z;
157 d_matrixValid = false;
158 }
159
160 //----------------------------------------------------------------------------//
setRotation(const Quaternion & r)161 void IrrlichtGeometryBuffer::setRotation(const Quaternion& r)
162 {
163 d_rotation.W = -r.d_w;
164 d_rotation.X = r.d_x;
165 d_rotation.Y = r.d_y;
166 d_rotation.Z = r.d_z;
167 d_matrixValid = false;
168 }
169
170 //----------------------------------------------------------------------------//
setPivot(const Vector3f & p)171 void IrrlichtGeometryBuffer::setPivot(const Vector3f& p)
172 {
173 d_pivot.X = p.d_x;
174 d_pivot.Y = p.d_y;
175 d_pivot.Z = p.d_z;
176 d_matrixValid = false;
177 }
178
179 //----------------------------------------------------------------------------//
setClippingRegion(const Rectf & region)180 void IrrlichtGeometryBuffer::setClippingRegion(const Rectf& region)
181 {
182 d_clipRect.top(ceguimax(0.0f, region.top()));
183 d_clipRect.bottom(ceguimax(0.0f, region.bottom()));
184 d_clipRect.left(ceguimax(0.0f, region.left()));
185 d_clipRect.right(ceguimax(0.0f, region.right()));
186 }
187
188 //----------------------------------------------------------------------------//
appendVertex(const Vertex & vertex)189 void IrrlichtGeometryBuffer::appendVertex(const Vertex& vertex)
190 {
191 appendGeometry(&vertex, 1);
192 }
193
194 //----------------------------------------------------------------------------//
appendGeometry(const Vertex * const vbuff,uint vertex_count)195 void IrrlichtGeometryBuffer::appendGeometry(const Vertex* const vbuff,
196 uint vertex_count)
197 {
198 // see if we should start a new batch
199 irr::video::ITexture* t =
200 d_activeTexture ? d_activeTexture->getIrrlichtTexture() : 0;
201
202 if (d_batches.empty() ||
203 d_batches.back().texture != t ||
204 d_batches.back().clip != d_clippingActive)
205 {
206 const BatchInfo batch = {t, 0, d_clippingActive};
207 d_batches.push_back(batch);
208 }
209
210 // buffer these vertices
211 const irr::u16 idx_start = d_batches.back().vertexCount;
212 irr::video::S3DVertex v;
213 for (uint i = 0; i < vertex_count; ++i)
214 {
215 const Vertex& vs = vbuff[i];
216 v.Pos.X = vs.position.d_x + d_texelOffset;
217 v.Pos.Y = vs.position.d_y + d_texelOffset;
218 v.Pos.Z = vs.position.d_z;
219 v.TCoords.X = vs.tex_coords.d_x;
220 v.TCoords.Y = vs.tex_coords.d_y;
221 v.Color.set(vs.colour_val.getARGB());
222 d_vertices.push_back(v);
223 d_indices.push_back(idx_start + i);
224 }
225
226 // update size of current batch
227 d_batches.back().vertexCount += vertex_count;
228 }
229
230 //----------------------------------------------------------------------------//
setActiveTexture(Texture * texture)231 void IrrlichtGeometryBuffer::setActiveTexture(Texture* texture)
232 {
233 d_activeTexture = static_cast<IrrlichtTexture*>(texture);
234 }
235
236 //----------------------------------------------------------------------------//
reset()237 void IrrlichtGeometryBuffer::reset()
238 {
239 d_vertices.clear();
240 d_indices.clear();
241 d_batches.clear();
242 d_activeTexture = 0;
243 }
244
245 //----------------------------------------------------------------------------//
getActiveTexture() const246 Texture* IrrlichtGeometryBuffer::getActiveTexture() const
247 {
248 return d_activeTexture;
249 }
250
251 //----------------------------------------------------------------------------//
getVertexCount() const252 uint IrrlichtGeometryBuffer::getVertexCount() const
253 {
254 return d_vertices.size();
255 }
256
257 //----------------------------------------------------------------------------//
getBatchCount() const258 uint IrrlichtGeometryBuffer::getBatchCount() const
259 {
260 return d_batches.size();
261 }
262
263 //----------------------------------------------------------------------------//
setRenderEffect(RenderEffect * effect)264 void IrrlichtGeometryBuffer::setRenderEffect(RenderEffect* effect)
265 {
266 d_effect = effect;
267 }
268
269 //----------------------------------------------------------------------------//
getRenderEffect()270 RenderEffect* IrrlichtGeometryBuffer::getRenderEffect()
271 {
272 return d_effect;
273 }
274
275 //----------------------------------------------------------------------------//
setBlendMode(const BlendMode mode)276 void IrrlichtGeometryBuffer::setBlendMode(const BlendMode mode)
277 {
278 // if blend mode is already set to this, ignore.
279 if (d_blendMode == mode)
280 return;
281
282 // call default to set mode field (in case we change how that's done)
283 GeometryBuffer::setBlendMode(mode);
284
285 #if CEGUI_IRR_SDK_VERSION >= 16
286 // FIXME: Here we just use the 'best of a bad situation' option
287 // FIXME: which results in incorrect accumulation of alpha values
288 // FIXME: in texture based targets. There is no fix for this that is
289 // FIXME: possible with the stock Irrlicht; while we could creata an
290 // FIXME: appropriate custom material, it would involve directly linking
291 // FIXME: with the various underlying rendering APIs - which is fine for
292 // FIXME: an end user, but is definitely not what _we_ want to be doing.
293 //
294 // If anybody knows the above information to be incorrect, and has a fix
295 // for this issue, please let us know! :)
296
297 /* if (d_blendMode == BM_RTT_PREMULTIPLIED)
298 {
299 d_material.MaterialType = irr::video::EMT_ONETEXTURE_BLEND;
300 d_material.MaterialTypeParam = irr::video::pack_texureBlendFunc(
301 irr::video::EBF_ONE,
302 irr::video::EBF_ONE_MINUS_SRC_ALPHA,
303 irr::video::EMFN_MODULATE_1X,
304 irr::video::EAS_NONE);
305 }
306 else */
307 {
308 d_material.MaterialType = irr::video::EMT_ONETEXTURE_BLEND;
309 d_material.MaterialTypeParam =
310 #if IRRLICHT_VERSION_MAJOR > 1 || (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8)
311 irr::video::pack_textureBlendFunc(
312 #else
313 irr::video::pack_texureBlendFunc(
314 #endif
315 irr::video::EBF_SRC_ALPHA,
316 irr::video::EBF_ONE_MINUS_SRC_ALPHA,
317 irr::video::EMFN_MODULATE_1X,
318 irr::video::EAS_NONE);
319 }
320 #else
321 d_material.MaterialType = irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL;
322 d_material.MaterialTypeParam = 0;
323 #endif
324 }
325
326 //----------------------------------------------------------------------------//
getMatrix() const327 const irr::core::matrix4& IrrlichtGeometryBuffer::getMatrix() const
328 {
329 return d_matrix;
330 }
331
332 //----------------------------------------------------------------------------//
updateMatrix() const333 void IrrlichtGeometryBuffer::updateMatrix() const
334 {
335 d_matrix.makeIdentity();
336 d_matrix.setTranslation(d_translation + d_pivot);
337
338 irr::core::matrix4 ptrans;
339 ptrans.setTranslation(-d_pivot);
340
341 d_matrix *= d_rotation.getMatrix();
342 d_matrix *= ptrans;
343
344 d_matrixValid = true;
345 }
346
347 //----------------------------------------------------------------------------//
getMaterial()348 irr::video::SMaterial& IrrlichtGeometryBuffer::getMaterial()
349 {
350 return const_cast<irr::video::SMaterial&>(
351 static_cast<const IrrlichtGeometryBuffer*>(this)->getMaterial());
352 }
353
354 //----------------------------------------------------------------------------//
getMaterial() const355 const irr::video::SMaterial& IrrlichtGeometryBuffer::getMaterial() const
356 {
357 return d_material;
358 }
359
360 //----------------------------------------------------------------------------//
setClippingActive(const bool active)361 void IrrlichtGeometryBuffer::setClippingActive(const bool active)
362 {
363 d_clippingActive = active;
364 }
365
366 //----------------------------------------------------------------------------//
isClippingActive() const367 bool IrrlichtGeometryBuffer::isClippingActive() const
368 {
369 return d_clippingActive;
370 }
371
372 //----------------------------------------------------------------------------//
373 //
374 } // End of CEGUI namespace section
375