1 /***********************************************************************
2 created: Sun Jan 11 2009
3 author: Paul D Turner
4 *************************************************************************/
5 /***************************************************************************
6 * Copyright (C) 2004 - 2009 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 #include "CEGUI/RendererModules/OpenGLES/Renderer.h"
28 #include "CEGUI/RendererModules/OpenGLES/Texture.h"
29 #include "CEGUI/Exceptions.h"
30 #include "CEGUI/EventArgs.h"
31 #include "CEGUI/ImageCodec.h"
32 #include "CEGUI/DynamicModule.h"
33 #include "CEGUI/RendererModules/OpenGLES/ViewportTarget.h"
34 #include "CEGUI/RendererModules/OpenGLES/GeometryBuffer.h"
35 #include "CEGUI/RendererModules/OpenGLES/FBOTextureTarget.h"
36 #include "CEGUI/Logger.h"
37 #include "CEGUI/System.h"
38 #include "CEGUI/DefaultResourceProvider.h"
39
40 #include <sstream>
41 #include <algorithm>
42
43 #include "CEGUI/RendererModules/OpenGLES/FBOTextureTarget.h"
44
45 // Start of CEGUI namespace section
46 namespace CEGUI
47 {
48 //----------------------------------------------------------------------------//
49 // The following are some GL extension / version dependant related items.
50 // This is all done totally internally here; no need for external interface
51 // to show any of this.
52 //----------------------------------------------------------------------------//
53 // we only really need this with MSVC / Windows(?) and by now it should already
54 // be defined on that platform, so we just define it as empty macro so the
55 // compile does not break on other systems.
56 #ifndef APIENTRY
57 # define APIENTRY
58 #endif
59 //! Dummy function for if real ones are not present (saves testing each render)
activeTextureDummy(GLenum)60 void APIENTRY activeTextureDummy(GLenum) {}
61
62 //----------------------------------------------------------------------------//
63 //
64 // Here we have an internal class that allows us to implement a factory template
65 // for creating / destroying any type of TextureTarget. The code that detects
66 // the computer's abilities will generate an appropriate factory for a
67 // TextureTarget based on what the host system can provide - or use the default
68 // 'null' factory if no suitable TextureTargets are available.
69 //
70 // base factory class - mainly used as a polymorphic interface
71 class OGLTextureTargetFactory
72 {
73 public:
OGLTextureTargetFactory()74 OGLTextureTargetFactory() {}
~OGLTextureTargetFactory()75 virtual ~OGLTextureTargetFactory() {}
create(OpenGLESRenderer &) const76 virtual TextureTarget* create(OpenGLESRenderer&) const
77 { return 0; }
destory(TextureTarget * target) const78 virtual void destory(TextureTarget* target) const
79 { delete target; }
80 };
81
82 // template specialised class that does the real work for us
83 template<typename T>
84 class OGLTemplateTargetFactory : public OGLTextureTargetFactory
85 {
create(OpenGLESRenderer & r) const86 virtual TextureTarget* create(OpenGLESRenderer& r) const
87 { return new T(r); }
88 };
89
90 //----------------------------------------------------------------------------//
91 String OpenGLESRenderer::d_rendererID(
92 "CEGUI::OpenGLESRenderer - Official OpenGLES based 2nd generation renderer module.");
93
94 //----------------------------------------------------------------------------//
bootstrapSystem(const TextureTargetType tt_type,const int abi)95 OpenGLESRenderer& OpenGLESRenderer::bootstrapSystem(
96 const TextureTargetType tt_type,
97 const int abi)
98 {
99 System::performVersionTest(CEGUI_VERSION_ABI, abi, CEGUI_FUNCTION_NAME);
100
101 if (System::getSingletonPtr())
102 CEGUI_THROW(InvalidRequestException(
103 "CEGUI::System object is already initialised."));
104
105 OpenGLESRenderer& renderer(create(tt_type));
106 DefaultResourceProvider* rp = new CEGUI::DefaultResourceProvider();
107 System::create(renderer, rp);
108
109 return renderer;
110 }
111
112 //----------------------------------------------------------------------------//
bootstrapSystem(const Sizef & display_size,const TextureTargetType tt_type,const int abi)113 OpenGLESRenderer& OpenGLESRenderer::bootstrapSystem(
114 const Sizef& display_size,
115 const TextureTargetType tt_type,
116 const int abi)
117 {
118 System::performVersionTest(CEGUI_VERSION_ABI, abi, CEGUI_FUNCTION_NAME);
119
120 if (System::getSingletonPtr())
121 CEGUI_THROW(InvalidRequestException(
122 "CEGUI::System object is already initialised."));
123
124 OpenGLESRenderer& renderer(create(display_size, tt_type));
125 DefaultResourceProvider* rp = new CEGUI::DefaultResourceProvider();
126 System::create(renderer, rp);
127
128 return renderer;
129 }
130
131 //----------------------------------------------------------------------------//
destroySystem()132 void OpenGLESRenderer::destroySystem()
133 {
134 System* sys;
135 if (!(sys = System::getSingletonPtr()))
136 CEGUI_THROW(InvalidRequestException(
137 "CEGUI::System object is not created or was already destroyed."));
138
139 OpenGLESRenderer* renderer =
140 static_cast<OpenGLESRenderer*>(sys->getRenderer());
141 DefaultResourceProvider* rp =
142 static_cast<DefaultResourceProvider*>(sys->getResourceProvider());
143
144 System::destroy();
145 delete rp;
146 destroy(*renderer);
147 }
148
149 //----------------------------------------------------------------------------//
create(const TextureTargetType tt_type,const int abi)150 OpenGLESRenderer& OpenGLESRenderer::create(const TextureTargetType tt_type,
151 const int abi)
152 {
153 System::performVersionTest(CEGUI_VERSION_ABI, abi, CEGUI_FUNCTION_NAME);
154
155 return *new OpenGLESRenderer(tt_type);
156 }
157
158 //----------------------------------------------------------------------------//
create(const Sizef & display_size,const TextureTargetType tt_type,const int abi)159 OpenGLESRenderer& OpenGLESRenderer::create(const Sizef& display_size,
160 const TextureTargetType tt_type,
161 const int abi)
162 {
163 System::performVersionTest(CEGUI_VERSION_ABI, abi, CEGUI_FUNCTION_NAME);
164
165 return *new OpenGLESRenderer(display_size, tt_type);
166 }
167
168 //----------------------------------------------------------------------------//
destroy(OpenGLESRenderer & renderer)169 void OpenGLESRenderer::destroy(OpenGLESRenderer& renderer)
170 {
171 delete &renderer;
172 }
173
174 //----------------------------------------------------------------------------//
isGLExtensionSupported(const char * extension)175 bool OpenGLESRenderer::isGLExtensionSupported( const char* extension )
176 {
177 const GLubyte *extensions = NULL;
178 const GLubyte *start;
179 GLubyte *where, *terminator;
180
181 /* Extension names should not have spaces. */
182 where = (GLubyte *) strchr(extension, ' ');
183 if (where || *extension == '\0')
184 return 0;
185
186 extensions = glGetString(GL_EXTENSIONS);
187
188 start = extensions;
189 for (;;)
190 {
191 where = (GLubyte *) strstr((const char *) start, extension);
192 if (!where)
193 break;
194 terminator = where + strlen(extension);
195 if (where == start || *(where - 1) == ' ')
196 if (*terminator == ' ' || *terminator == '\0')
197 return true;
198 start = terminator;
199 }
200 return false;
201 }
202
203 //----------------------------------------------------------------------------//
OpenGLESRenderer(const TextureTargetType tt_type)204 OpenGLESRenderer::OpenGLESRenderer(const TextureTargetType tt_type) :
205 d_displayDPI(96, 96),
206 d_initExtraStates(false)
207 {
208 // get rough max texture size
209 GLint max_tex_size;
210 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
211 d_maxTextureSize = max_tex_size;
212
213 // initialise display size
214 GLint vp[4];
215 glGetIntegerv(GL_VIEWPORT, vp);
216 d_displaySize = Sizef(static_cast<float>(vp[2]), static_cast<float>(vp[3]));
217
218 initialiseTextureTargetFactory(tt_type);
219
220 d_defaultTarget = new OpenGLESViewportTarget(*this);
221 }
222
223 //----------------------------------------------------------------------------//
OpenGLESRenderer(const Sizef & display_size,const TextureTargetType tt_type)224 OpenGLESRenderer::OpenGLESRenderer(const Sizef& display_size,
225 const TextureTargetType tt_type) :
226 d_displaySize(display_size),
227 d_displayDPI(96, 96),
228 d_initExtraStates(false)
229 {
230 // get rough max texture size
231 GLint max_tex_size;
232 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
233 d_maxTextureSize = max_tex_size;
234
235 initialiseTextureTargetFactory(tt_type);
236
237 d_defaultTarget = new OpenGLESViewportTarget(*this);
238 }
239
240 //----------------------------------------------------------------------------//
~OpenGLESRenderer()241 OpenGLESRenderer::~OpenGLESRenderer()
242 {
243 destroyAllGeometryBuffers();
244 destroyAllTextureTargets();
245 destroyAllTextures();
246
247 delete d_defaultTarget;
248 delete d_textureTargetFactory;
249 }
250
251 //----------------------------------------------------------------------------//
getDefaultRenderTarget()252 RenderTarget& OpenGLESRenderer::getDefaultRenderTarget()
253 {
254 return *d_defaultTarget;
255 }
256
257 //----------------------------------------------------------------------------//
createGeometryBuffer()258 GeometryBuffer& OpenGLESRenderer::createGeometryBuffer()
259 {
260 OpenGLESGeometryBuffer* b= new OpenGLESGeometryBuffer;
261 d_geometryBuffers.push_back(b);
262 return *b;
263 }
264
265 //----------------------------------------------------------------------------//
destroyGeometryBuffer(const GeometryBuffer & buffer)266 void OpenGLESRenderer::destroyGeometryBuffer(const GeometryBuffer& buffer)
267 {
268 GeometryBufferList::iterator i = std::find(d_geometryBuffers.begin(),
269 d_geometryBuffers.end(),
270 &buffer);
271
272 if (d_geometryBuffers.end() != i)
273 {
274 d_geometryBuffers.erase(i);
275 delete &buffer;
276 }
277 }
278
279 //----------------------------------------------------------------------------//
destroyAllGeometryBuffers()280 void OpenGLESRenderer::destroyAllGeometryBuffers()
281 {
282 while (!d_geometryBuffers.empty())
283 destroyGeometryBuffer(**d_geometryBuffers.begin());
284 }
285
286 //----------------------------------------------------------------------------//
createTextureTarget()287 TextureTarget* OpenGLESRenderer::createTextureTarget()
288 {
289 TextureTarget* t = d_textureTargetFactory->create(*this);
290 d_textureTargets.push_back(t);
291 return t;
292 }
293
294 //----------------------------------------------------------------------------//
destroyTextureTarget(TextureTarget * target)295 void OpenGLESRenderer::destroyTextureTarget(TextureTarget* target)
296 {
297 TextureTargetList::iterator i = std::find(d_textureTargets.begin(),
298 d_textureTargets.end(),
299 target);
300
301 if (d_textureTargets.end() != i)
302 {
303 d_textureTargets.erase(i);
304 d_textureTargetFactory->destory(target);
305 }
306 }
307
308 //----------------------------------------------------------------------------//
destroyAllTextureTargets()309 void OpenGLESRenderer::destroyAllTextureTargets()
310 {
311 while (!d_textureTargets.empty())
312 destroyTextureTarget(*d_textureTargets.begin());
313 }
314
315 //----------------------------------------------------------------------------//
createTexture(const String & name)316 Texture& OpenGLESRenderer::createTexture(const String& name)
317 {
318 OpenGLESTexture* tex = new OpenGLESTexture(*this, name);
319 d_textures[name] = tex;
320 return *tex;
321 }
322
323 //----------------------------------------------------------------------------//
createTexture(const String & name,const String & filename,const String & resourceGroup)324 Texture& OpenGLESRenderer::createTexture(const String& name,
325 const String& filename,
326 const String& resourceGroup)
327 {
328 OpenGLESTexture* tex = new OpenGLESTexture(*this, name, filename,
329 resourceGroup);
330 d_textures[name] = tex;
331 return *tex;
332 }
333
334 //----------------------------------------------------------------------------//
createTexture(const String & name,const Sizef & size)335 Texture& OpenGLESRenderer::createTexture(const String& name, const Sizef& size)
336 {
337 OpenGLESTexture* tex = new OpenGLESTexture(*this, name, size);
338 d_textures[name] = tex;
339 return *tex;
340 }
341
342 //----------------------------------------------------------------------------//
destroyTexture(const String & name)343 void OpenGLESRenderer::destroyTexture(const String& name)
344 {
345 TextureMap::iterator i = d_textures.find(name);
346
347 if (d_textures.end() != i)
348 {
349 logTextureDestruction(name);
350 delete i->second;
351 d_textures.erase(i);
352 }
353 }
354
355 //----------------------------------------------------------------------------//
logTextureDestruction(const String & name)356 void OpenGLESRenderer::logTextureDestruction(const String& name)
357 {
358 Logger* logger = Logger::getSingletonPtr();
359 if (logger)
360 logger->logEvent("[OpenGLESRenderer] Destroyed texture: " + name);
361 }
362
363 //----------------------------------------------------------------------------//
destroyTexture(Texture & texture)364 void OpenGLESRenderer::destroyTexture(Texture& texture)
365 {
366 destroyTexture(texture.getName());
367 }
368
369 //----------------------------------------------------------------------------//
destroyAllTextures()370 void OpenGLESRenderer::destroyAllTextures()
371 {
372 while (!d_textures.empty())
373 destroyTexture(d_textures.begin()->first);
374 }
375
376 //----------------------------------------------------------------------------//
getTexture(const String & name) const377 Texture& OpenGLESRenderer::getTexture(const String& name) const
378 {
379 TextureMap::const_iterator i = d_textures.find(name);
380
381 if (i == d_textures.end())
382 CEGUI_THROW(UnknownObjectException(
383 "No texture named '" + name + "' is available."));
384
385 return *i->second;
386 }
387
388 //----------------------------------------------------------------------------//
isTextureDefined(const String & name) const389 bool OpenGLESRenderer::isTextureDefined(const String& name) const
390 {
391 return d_textures.find(name) != d_textures.end();
392 }
393
394 //----------------------------------------------------------------------------//
beginRendering()395 void OpenGLESRenderer::beginRendering()
396 {
397 //save current attributes
398
399 // Unsupported by OpenGL ES
400 //glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
401 //glPushAttrib(GL_ALL_ATTRIB_BITS);
402
403 // save current matrices
404 //glMatrixMode(GL_PROJECTION);
405 //glPushMatrix(); -- causes gl stack overflow error
406
407 glMatrixMode(GL_MODELVIEW);
408 glPushMatrix();
409
410 // Save at least something
411 glPreRenderStates.glScissorTest = glIsEnabled(GL_SCISSOR_TEST);
412 glPreRenderStates.texturing = glIsEnabled(GL_TEXTURE_2D);
413 glPreRenderStates.blend = glIsEnabled(GL_BLEND);
414 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &glPreRenderStates.arrayBuffer);
415 glGetIntegerv(GL_TEXTURE_BINDING_2D, &glPreRenderStates.texture);
416 glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &glPreRenderStates.texEnvParam);
417
418 // do required set-up. yes, it really is this minimal ;)
419 glEnable(GL_SCISSOR_TEST);
420 glEnable(GL_TEXTURE_2D);
421 glEnable(GL_BLEND);
422 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
423
424 glBindBuffer(GL_ARRAY_BUFFER, 0);
425 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
426
427 // enable arrays that we'll be using in the batches
428 glEnableClientState(GL_VERTEX_ARRAY);
429 glEnableClientState(GL_COLOR_ARRAY);
430 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
431 glDisableClientState(GL_NORMAL_ARRAY);
432
433 // if enabled, restores a subset of the GL state back to default values.
434 if (d_initExtraStates)
435 setupExtraStates();
436 }
437
438 //----------------------------------------------------------------------------//
endRendering()439 void OpenGLESRenderer::endRendering()
440 {
441 if (d_initExtraStates)
442 cleanupExtraStates();
443
444 // restore former matrices
445 // FIXME: If the push ops failed, the following could mess things up!
446 //glMatrixMode(GL_PROJECTION);
447 //glPopMatrix();
448 glMatrixMode(GL_MODELVIEW);
449 glPopMatrix();
450
451 if (!glPreRenderStates.glScissorTest)
452 glDisable(GL_SCISSOR_TEST);
453 if (!glPreRenderStates.texturing)
454 glDisable(GL_TEXTURE_2D);
455 if (!glPreRenderStates.blend)
456 glDisable(GL_BLEND);
457
458 if (glPreRenderStates.arrayBuffer)
459 glBindBuffer(GL_ARRAY_BUFFER, glPreRenderStates.arrayBuffer);
460 glBindTexture(GL_TEXTURE_2D, glPreRenderStates.texture);
461 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, glPreRenderStates.texEnvParam);
462
463 glDisableClientState(GL_VERTEX_ARRAY);
464 glDisableClientState(GL_COLOR_ARRAY);
465 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
466
467 //restore former attributes
468 //still unsupported
469 //glPopAttrib();
470 //glPopClientAttrib();
471 }
472
473 //----------------------------------------------------------------------------//
getDisplaySize() const474 const Sizef& OpenGLESRenderer::getDisplaySize() const
475 {
476 return d_displaySize;
477 }
478
479 //----------------------------------------------------------------------------//
getDisplayDPI() const480 const Vector2f& OpenGLESRenderer::getDisplayDPI() const
481 {
482 return d_displayDPI;
483 }
484
485 //----------------------------------------------------------------------------//
getMaxTextureSize() const486 uint OpenGLESRenderer::getMaxTextureSize() const
487 {
488 return d_maxTextureSize;
489 }
490
491 //----------------------------------------------------------------------------//
getIdentifierString() const492 const String& OpenGLESRenderer::getIdentifierString() const
493 {
494 return d_rendererID;
495 }
496
497 //----------------------------------------------------------------------------//
createTexture(const String & name,GLuint tex,const Sizef & sz)498 Texture& OpenGLESRenderer::createTexture(const String& name, GLuint tex,
499 const Sizef& sz)
500 {
501 OpenGLESTexture* t = new OpenGLESTexture(*this, name, tex, sz);
502 d_textures[name] = t;
503 return *t;
504 }
505
506 //----------------------------------------------------------------------------//
setDisplaySize(const Sizef & sz)507 void OpenGLESRenderer::setDisplaySize(const Sizef& sz)
508 {
509 if (sz != d_displaySize)
510 {
511 d_displaySize = sz;
512
513 // update the default target's area
514 Rectf area(d_defaultTarget->getArea());
515 area.setSize(sz);
516 d_defaultTarget->setArea(area);
517 }
518 }
519
520 //----------------------------------------------------------------------------//
enableExtraStateSettings(bool setting)521 void OpenGLESRenderer::enableExtraStateSettings(bool setting)
522 {
523 d_initExtraStates = setting;
524 }
525
526 //----------------------------------------------------------------------------//
setupExtraStates()527 void OpenGLESRenderer::setupExtraStates()
528 {
529 glMatrixMode(GL_TEXTURE);
530 glPushMatrix();
531 glLoadIdentity();
532
533 glActiveTexture(GL_TEXTURE0);
534 glClientActiveTexture(GL_TEXTURE0);
535
536 //glPolygonMode(GL_FRONT, GL_FILL);
537 //glPolygonMode(GL_BACK, GL_FILL);
538
539 glDisable(GL_LIGHTING);
540 glDisable(GL_FOG);
541 glDisable(GL_CULL_FACE);
542 glDisable(GL_DEPTH_TEST);
543
544 //glDisable(GL_TEXTURE_GEN_S);
545 //glDisable(GL_TEXTURE_GEN_T);
546 //glDisable(GL_TEXTURE_GEN_R);
547
548 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
549 }
550
551 //----------------------------------------------------------------------------//
cleanupExtraStates()552 void OpenGLESRenderer::cleanupExtraStates()
553 {
554 glMatrixMode(GL_TEXTURE);
555 glPopMatrix();
556 }
557
558 //----------------------------------------------------------------------------//
grabTextures()559 void OpenGLESRenderer::grabTextures()
560 {
561 for(TextureMap::iterator i = d_textures.begin();
562 i != d_textures.end();
563 ++i)
564 i->second->grabTexture();
565 }
566
567 //----------------------------------------------------------------------------//
restoreTextures()568 void OpenGLESRenderer::restoreTextures()
569 {
570 for(TextureMap::iterator i = d_textures.begin();
571 i != d_textures.end();
572 ++i)
573 i->second->restoreTexture();
574 }
575
576 //----------------------------------------------------------------------------//
initialiseTextureTargetFactory(const TextureTargetType tt_type)577 void OpenGLESRenderer::initialiseTextureTargetFactory(
578 const TextureTargetType tt_type)
579 {
580 if (isGLExtensionSupported("GL_OES_framebuffer_object"))
581 {
582 d_rendererID += " TextureTarget support enabled via"
583 "GL_OES_framebuffer_object extension.";
584 OpenGLESFBOTextureTarget::initializedFBOExtension();
585 d_textureTargetFactory =
586 new OGLTemplateTargetFactory<OpenGLESFBOTextureTarget>;
587 }
588 else
589 {
590 d_rendererID += " TextureTarget support is not available :(";
591 d_textureTargetFactory = new OGLTextureTargetFactory;
592 }
593 }
594
595 //----------------------------------------------------------------------------//
getAdjustedTextureSize(const Sizef & sz) const596 Sizef OpenGLESRenderer::getAdjustedTextureSize(const Sizef& sz) const
597 {
598 Sizef out(sz);
599 out.d_width = getNextPOTSize(out.d_width);
600 out.d_height = getNextPOTSize(out.d_height);
601 return out;
602 }
603
604 //----------------------------------------------------------------------------//
getNextPOTSize(const float f)605 float OpenGLESRenderer::getNextPOTSize(const float f)
606 {
607 uint size = static_cast<uint>(f);
608
609 // if not power of 2
610 if ((size & (size - 1)) || !size)
611 {
612 int log = 0;
613
614 // get integer log of 'size' to base 2
615 while (size >>= 1)
616 ++log;
617
618 // use log to calculate value to use as size.
619 size = (2 << log);
620 }
621
622 return static_cast<float>(size);
623 }
624
625 //----------------------------------------------------------------------------//
626
627 } // End of CEGUI namespace section
628
629