]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/COGLESDriver.cpp
Fix `getViewPort` returning incorrect results
[irrlicht.git] / source / Irrlicht / COGLESDriver.cpp
1 // Copyright (C) 2002-2008 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "COGLESDriver.h"\r
6 #include "CNullDriver.h"\r
7 #include "IContextManager.h"\r
8 \r
9 #ifdef _IRR_COMPILE_WITH_OGLES1_\r
10 \r
11 #include "COpenGLCoreTexture.h"\r
12 #include "COpenGLCoreRenderTarget.h"\r
13 #include "COpenGLCoreCacheHandler.h"\r
14 \r
15 #include "COGLESMaterialRenderer.h"\r
16 \r
17 #include "EVertexAttributes.h"\r
18 #include "CImage.h"\r
19 #include "os.h"\r
20 #include "EProfileIDs.h"\r
21 #include "IProfiler.h"\r
22 \r
23 #ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_\r
24 #include "android_native_app_glue.h"\r
25 #endif\r
26 \r
27 namespace irr\r
28 {\r
29 namespace video\r
30 {\r
31 \r
32 COGLES1Driver::COGLES1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager) :\r
33     CNullDriver(io, params.WindowSize), COGLES1ExtensionHandler(), CacheHandler(0), CurrentRenderMode(ERM_NONE),\r
34     ResetRenderStates(true), Transformation3DChanged(true), AntiAlias(params.AntiAlias),\r
35     ColorFormat(ECF_R8G8B8), Params(params), ContextManager(contextManager)\r
36 {\r
37 #ifdef _DEBUG\r
38         setDebugName("COGLESDriver");\r
39 #endif\r
40 \r
41     core::dimension2d<u32> windowSize(0, 0);\r
42 \r
43         if (!ContextManager)\r
44                 return;\r
45 \r
46         ContextManager->grab();\r
47         ContextManager->generateSurface();\r
48         ContextManager->generateContext();\r
49         ExposedData = ContextManager->getContext();\r
50         ContextManager->activateContext(ExposedData, false);\r
51 \r
52         windowSize = params.WindowSize;\r
53 \r
54     genericDriverInit(windowSize, params.Stencilbuffer);\r
55 }\r
56 \r
57 COGLES1Driver::~COGLES1Driver()\r
58 {\r
59         RequestedLights.clear();\r
60 \r
61         deleteMaterialRenders();\r
62 \r
63         CacheHandler->getTextureCache().clear();\r
64 \r
65         removeAllRenderTargets();\r
66         deleteAllTextures();\r
67         removeAllOcclusionQueries();\r
68         removeAllHardwareBuffers();\r
69 \r
70         delete CacheHandler;\r
71 \r
72         if (ContextManager)\r
73         {\r
74                 ContextManager->destroyContext();\r
75                 ContextManager->destroySurface();\r
76                 ContextManager->terminate();\r
77                 ContextManager->drop();\r
78         }\r
79 }\r
80 \r
81 // -----------------------------------------------------------------------\r
82 // METHODS\r
83 // -----------------------------------------------------------------------\r
84 \r
85 bool COGLES1Driver::genericDriverInit(const core::dimension2d<u32>& screenSize, bool stencilBuffer)\r
86 {\r
87         Name=glGetString(GL_VERSION);\r
88         printVersion();\r
89 \r
90         // print renderer information\r
91         VendorName = glGetString(GL_VENDOR);\r
92         os::Printer::log(VendorName.c_str(), ELL_INFORMATION);\r
93 \r
94         // load extensions\r
95         initExtensions();\r
96 \r
97         // reset cache handler\r
98         delete CacheHandler;\r
99         CacheHandler = new COGLES1CacheHandler(this);\r
100 \r
101         StencilBuffer = stencilBuffer;\r
102 \r
103         DriverAttributes->setAttribute("MaxTextures", (s32)Feature.MaxTextureUnits);\r
104         DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Feature.MaxTextureUnits);\r
105         DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy);\r
106         DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices);\r
107         DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize);\r
108         DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias);\r
109         DriverAttributes->setAttribute("Version", Version);\r
110         DriverAttributes->setAttribute("AntiAlias", AntiAlias);\r
111 \r
112         glPixelStorei(GL_PACK_ALIGNMENT, 1);\r
113 \r
114         UserClipPlane.reallocate(MaxUserClipPlanes);\r
115         UserClipPlaneEnabled.reallocate(MaxUserClipPlanes);\r
116 \r
117         for (s32 i = 0; i < MaxUserClipPlanes; ++i)\r
118         {\r
119                 UserClipPlane.push_back(core::plane3df());\r
120                 UserClipPlaneEnabled.push_back(false);\r
121         }\r
122 \r
123         for (s32 i = 0; i < ETS_COUNT; ++i)\r
124                 setTransform(static_cast<E_TRANSFORMATION_STATE>(i), core::IdentityMatrix);\r
125 \r
126         setAmbientLight(SColorf(0.0f, 0.0f, 0.0f, 0.0f));\r
127         glClearDepthf(1.0f);\r
128 \r
129         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);\r
130         glHint(GL_GENERATE_MIPMAP_HINT, GL_FASTEST);\r
131         glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);\r
132         glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);\r
133         glDepthFunc(GL_LEQUAL);\r
134         glFrontFace(GL_CW);\r
135         glAlphaFunc(GL_GREATER, 0.f);\r
136 \r
137         // create material renderers\r
138         createMaterialRenderers();\r
139 \r
140         // set the renderstates\r
141         setRenderStates3DMode();\r
142 \r
143         // set fog mode\r
144         setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog);\r
145 \r
146         // create matrix for flipping textures\r
147         TextureFlipMatrix.buildTextureTransform(0.0f, core::vector2df(0, 0), core::vector2df(0, 1.0f), core::vector2df(1.0f, -1.0f));\r
148 \r
149         // We need to reset once more at the beginning of the first rendering.\r
150         // This fixes problems with intermediate changes to the material during texture load.\r
151         ResetRenderStates = true;\r
152 \r
153         testGLError(__LINE__);\r
154 \r
155         return true;\r
156 }\r
157 \r
158 \r
159 void COGLES1Driver::createMaterialRenderers()\r
160 {\r
161         // create OGLES1 material renderers\r
162 \r
163         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this));\r
164         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID_2_LAYER(this));\r
165 \r
166         // add the same renderer for all lightmap types\r
167         COGLES1MaterialRenderer_LIGHTMAP* lmr = new COGLES1MaterialRenderer_LIGHTMAP(this);\r
168         addMaterialRenderer(lmr); // for EMT_LIGHTMAP:\r
169         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_ADD:\r
170         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M2:\r
171         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M4:\r
172         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING:\r
173         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M2:\r
174         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M4:\r
175         lmr->drop();\r
176 \r
177         // add remaining material renderer\r
178         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_DETAIL_MAP(this));\r
179         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SPHERE_MAP(this));\r
180         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_REFLECTION_2_LAYER(this));\r
181         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_TRANSPARENT_ADD_COLOR(this));\r
182         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(this));\r
183         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(this));\r
184         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_TRANSPARENT_VERTEX_ALPHA(this));\r
185         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(this));\r
186 \r
187         // add normal map renderers\r
188 // TODO ogl-es\r
189         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this));\r
190         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this));\r
191         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this));\r
192 \r
193         // add parallax map renderers\r
194         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this));\r
195         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this));\r
196         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this));\r
197 \r
198         // add basic 1 texture blending\r
199         addAndDropMaterialRenderer(new COGLES1MaterialRenderer_ONETEXTURE_BLEND(this));\r
200 }\r
201 \r
202 bool COGLES1Driver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect<s32>* sourceRect)\r
203 {\r
204         IRR_PROFILE(CProfileScope p1(EPID_ES2_BEGIN_SCENE);)\r
205 \r
206         CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect);\r
207 \r
208         if (ContextManager)\r
209                 ContextManager->activateContext(videoData, true);\r
210 \r
211         clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);\r
212 \r
213         return true;\r
214 }\r
215 \r
216 bool COGLES1Driver::endScene()\r
217 {\r
218         IRR_PROFILE(CProfileScope p1(EPID_ES2_END_SCENE);)\r
219 \r
220         CNullDriver::endScene();\r
221 \r
222         glFlush();\r
223 \r
224         if (ContextManager)\r
225                 return ContextManager->swapBuffers();\r
226 \r
227         return false;\r
228 }\r
229 \r
230 \r
231 //! Returns the transformation set by setTransform\r
232 const core::matrix4& COGLES1Driver::getTransform(E_TRANSFORMATION_STATE state) const\r
233 {\r
234         return Matrices[state];\r
235 }\r
236 \r
237 \r
238 //! sets transformation\r
239 void COGLES1Driver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)\r
240 {\r
241         Matrices[state] = mat;\r
242         Transformation3DChanged = true;\r
243 \r
244         switch(state)\r
245         {\r
246         case ETS_VIEW:\r
247         case ETS_WORLD:\r
248                 {\r
249                         // OGLES1 only has a model matrix, view and world is not existent. so lets fake these two.\r
250                         glMatrixMode(GL_MODELVIEW);\r
251                         glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer());\r
252                         // we have to update the clip planes to the latest view matrix\r
253                         for (u32 i=0; i<MaxUserClipPlanes; ++i)\r
254                                 if (UserClipPlaneEnabled[i])\r
255                                         uploadClipPlane(i);\r
256                 }\r
257                 break;\r
258         case ETS_PROJECTION:\r
259                 {\r
260                         GLfloat glmat[16];\r
261                         getGLMatrix(glmat, mat);\r
262                         // flip z to compensate OGLES1s right-hand coordinate system\r
263                         glmat[12] *= -1.0f;\r
264                         glMatrixMode(GL_PROJECTION);\r
265                         glLoadMatrixf(glmat);\r
266                 }\r
267                 break;\r
268         default:\r
269                 break;\r
270         }\r
271 }\r
272 \r
273 bool COGLES1Driver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)\r
274 {\r
275         if (!HWBuffer)\r
276                 return false;\r
277 \r
278         const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;\r
279         const void* vertices=mb->getVertices();\r
280         const u32 vertexCount=mb->getVertexCount();\r
281         const E_VERTEX_TYPE vType=mb->getVertexType();\r
282         const u32 vertexSize = getVertexPitchFromType(vType);\r
283 \r
284         //buffer vertex data, and convert colours...\r
285         core::array<c8> buffer(vertexSize * vertexCount);\r
286         memcpy(buffer.pointer(), vertices, vertexSize * vertexCount);\r
287 \r
288         // in order to convert the colors into opengl format (RGBA)\r
289         switch (vType)\r
290         {\r
291                 case EVT_STANDARD:\r
292                 {\r
293                         S3DVertex* pb = reinterpret_cast<S3DVertex*>(buffer.pointer());\r
294                         const S3DVertex* po = static_cast<const S3DVertex*>(vertices);\r
295                         for (u32 i=0; i<vertexCount; i++)\r
296                         {\r
297                                 po[i].Color.toOpenGLColor((u8*)&(pb[i].Color.color));\r
298                         }\r
299                 }\r
300                 break;\r
301                 case EVT_2TCOORDS:\r
302                 {\r
303                         S3DVertex2TCoords* pb = reinterpret_cast<S3DVertex2TCoords*>(buffer.pointer());\r
304                         const S3DVertex2TCoords* po = static_cast<const S3DVertex2TCoords*>(vertices);\r
305                         for (u32 i=0; i<vertexCount; i++)\r
306                         {\r
307                                 po[i].Color.toOpenGLColor((u8*)&(pb[i].Color.color));\r
308                         }\r
309                 }\r
310                 break;\r
311                 case EVT_TANGENTS:\r
312                 {\r
313                         S3DVertexTangents* pb = reinterpret_cast<S3DVertexTangents*>(buffer.pointer());\r
314                         const S3DVertexTangents* po = static_cast<const S3DVertexTangents*>(vertices);\r
315                         for (u32 i=0; i<vertexCount; i++)\r
316                         {\r
317                                 po[i].Color.toOpenGLColor((u8*)&(pb[i].Color.color));\r
318                         }\r
319                 }\r
320                 break;\r
321                 default:\r
322                 {\r
323                         return false;\r
324                 }\r
325         }\r
326 \r
327         //get or create buffer\r
328         bool newBuffer=false;\r
329         if (!HWBuffer->vbo_verticesID)\r
330         {\r
331                 glGenBuffers(1, &HWBuffer->vbo_verticesID);\r
332                 if (!HWBuffer->vbo_verticesID) return false;\r
333                 newBuffer=true;\r
334         }\r
335         else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize)\r
336         {\r
337                 newBuffer=true;\r
338         }\r
339 \r
340         glBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID );\r
341 \r
342         // copy data to graphics card\r
343         if (!newBuffer)\r
344                 glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, buffer.const_pointer());\r
345         else\r
346         {\r
347                 HWBuffer->vbo_verticesSize = vertexCount*vertexSize;\r
348 \r
349                 if (HWBuffer->Mapped_Vertex==scene::EHM_STATIC)\r
350                         glBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_STATIC_DRAW);\r
351                 else\r
352                         glBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_DYNAMIC_DRAW);\r
353         }\r
354 \r
355         glBindBuffer(GL_ARRAY_BUFFER, 0);\r
356 \r
357         return (!testGLError(__LINE__));\r
358 }\r
359 \r
360 \r
361 bool COGLES1Driver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)\r
362 {\r
363         if (!HWBuffer)\r
364                 return false;\r
365 \r
366         const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;\r
367 \r
368         const void* indices=mb->getIndices();\r
369         u32 indexCount= mb->getIndexCount();\r
370 \r
371         GLenum indexSize;\r
372         switch (mb->getIndexType())\r
373         {\r
374                 case (EIT_16BIT):\r
375                 {\r
376                         indexSize=sizeof(u16);\r
377                         break;\r
378                 }\r
379                 case (EIT_32BIT):\r
380                 {\r
381                         indexSize=sizeof(u32);\r
382                         break;\r
383                 }\r
384                 default:\r
385                 {\r
386                         return false;\r
387                 }\r
388         }\r
389 \r
390 \r
391         //get or create buffer\r
392         bool newBuffer=false;\r
393         if (!HWBuffer->vbo_indicesID)\r
394         {\r
395                 glGenBuffers(1, &HWBuffer->vbo_indicesID);\r
396                 if (!HWBuffer->vbo_indicesID) return false;\r
397                 newBuffer=true;\r
398         }\r
399         else if (HWBuffer->vbo_indicesSize < indexCount*indexSize)\r
400         {\r
401                 newBuffer=true;\r
402         }\r
403 \r
404         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID);\r
405 \r
406         // copy data to graphics card\r
407         if (!newBuffer)\r
408                 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices);\r
409         else\r
410         {\r
411                 HWBuffer->vbo_indicesSize = indexCount*indexSize;\r
412 \r
413                 if (HWBuffer->Mapped_Index==scene::EHM_STATIC)\r
414                         glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW);\r
415                 else\r
416                         glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW);\r
417         }\r
418 \r
419         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\r
420 \r
421         return (!testGLError(__LINE__));\r
422 }\r
423 \r
424 \r
425 //! updates hardware buffer if needed\r
426 bool COGLES1Driver::updateHardwareBuffer(SHWBufferLink *HWBuffer)\r
427 {\r
428         if (!HWBuffer)\r
429                 return false;\r
430 \r
431         if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)\r
432         {\r
433                 if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex()\r
434                         || !static_cast<SHWBufferLink_opengl*>(HWBuffer)->vbo_verticesID)\r
435                 {\r
436 \r
437                         HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex();\r
438 \r
439                         if (!updateVertexHardwareBuffer(static_cast<SHWBufferLink_opengl*>(HWBuffer)))\r
440                                 return false;\r
441                 }\r
442         }\r
443 \r
444         if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)\r
445         {\r
446                 if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index()\r
447                         || !((SHWBufferLink_opengl*)HWBuffer)->vbo_indicesID)\r
448                 {\r
449 \r
450                         HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index();\r
451 \r
452                         if (!updateIndexHardwareBuffer(static_cast<SHWBufferLink_opengl*>(HWBuffer)))\r
453                                 return false;\r
454                 }\r
455         }\r
456 \r
457         return true;\r
458 }\r
459 \r
460 \r
461 //! Create hardware buffer from meshbuffer\r
462 COGLES1Driver::SHWBufferLink *COGLES1Driver::createHardwareBuffer(const scene::IMeshBuffer* mb)\r
463 {\r
464         if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))\r
465                 return 0;\r
466 \r
467         SHWBufferLink_opengl *HWBuffer=new SHWBufferLink_opengl(mb);\r
468 \r
469         //add to map\r
470         HWBufferMap.insert(HWBuffer->MeshBuffer, HWBuffer);\r
471 \r
472         HWBuffer->ChangedID_Vertex=HWBuffer->MeshBuffer->getChangedID_Vertex();\r
473         HWBuffer->ChangedID_Index=HWBuffer->MeshBuffer->getChangedID_Index();\r
474         HWBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex();\r
475         HWBuffer->Mapped_Index=mb->getHardwareMappingHint_Index();\r
476         HWBuffer->LastUsed=0;\r
477         HWBuffer->vbo_verticesID=0;\r
478         HWBuffer->vbo_indicesID=0;\r
479         HWBuffer->vbo_verticesSize=0;\r
480         HWBuffer->vbo_indicesSize=0;\r
481 \r
482         if (!updateHardwareBuffer(HWBuffer))\r
483         {\r
484                 deleteHardwareBuffer(HWBuffer);\r
485                 return 0;\r
486         }\r
487 \r
488         return HWBuffer;\r
489 }\r
490 \r
491 \r
492 void COGLES1Driver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer)\r
493 {\r
494         if (!_HWBuffer)\r
495                 return;\r
496 \r
497         SHWBufferLink_opengl *HWBuffer=static_cast<SHWBufferLink_opengl*>(_HWBuffer);\r
498         if (HWBuffer->vbo_verticesID)\r
499         {\r
500                 glDeleteBuffers(1, &HWBuffer->vbo_verticesID);\r
501                 HWBuffer->vbo_verticesID=0;\r
502         }\r
503         if (HWBuffer->vbo_indicesID)\r
504         {\r
505                 glDeleteBuffers(1, &HWBuffer->vbo_indicesID);\r
506                 HWBuffer->vbo_indicesID=0;\r
507         }\r
508 \r
509         CNullDriver::deleteHardwareBuffer(_HWBuffer);\r
510 }\r
511 \r
512 \r
513 //! Draw hardware buffer\r
514 void COGLES1Driver::drawHardwareBuffer(SHWBufferLink *_HWBuffer)\r
515 {\r
516         if (!_HWBuffer)\r
517                 return;\r
518 \r
519         SHWBufferLink_opengl *HWBuffer=static_cast<SHWBufferLink_opengl*>(_HWBuffer);\r
520 \r
521         updateHardwareBuffer(HWBuffer); //check if update is needed\r
522 \r
523         HWBuffer->LastUsed=0;//reset count\r
524 \r
525         const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;\r
526         const void *vertices=mb->getVertices();\r
527         const void *indexList=mb->getIndices();\r
528 \r
529         if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)\r
530         {\r
531                 glBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID);\r
532                 vertices=0;\r
533         }\r
534 \r
535         if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)\r
536         {\r
537                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID);\r
538                 indexList=0;\r
539         }\r
540 \r
541 \r
542         drawVertexPrimitiveList(vertices, mb->getVertexCount(), indexList,\r
543                         mb->getPrimitiveCount(), mb->getVertexType(),\r
544                         mb->getPrimitiveType(), mb->getIndexType());\r
545 \r
546         if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)\r
547                 glBindBuffer(GL_ARRAY_BUFFER, 0);\r
548 \r
549         if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)\r
550                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\r
551 }\r
552 \r
553 \r
554 IRenderTarget* COGLES1Driver::addRenderTarget()\r
555 {\r
556         COGLES1RenderTarget* renderTarget = new COGLES1RenderTarget(this);\r
557         RenderTargets.push_back(renderTarget);\r
558 \r
559         return renderTarget;\r
560 }\r
561 \r
562 \r
563 // small helper function to create vertex buffer object adress offsets\r
564 static inline u8* buffer_offset(const long offset)\r
565 {\r
566         return ((u8*)0 + offset);\r
567 }\r
568 \r
569 \r
570 //! draws a vertex primitive list\r
571 void COGLES1Driver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount,\r
572                 const void* indexList, u32 primitiveCount,\r
573                 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)\r
574 {\r
575         if (!checkPrimitiveCount(primitiveCount))\r
576                 return;\r
577 \r
578         setRenderStates3DMode();\r
579 \r
580         drawVertexPrimitiveList2d3d(vertices, vertexCount, (const u16*)indexList, primitiveCount, vType, pType, iType);\r
581 }\r
582 \r
583 \r
584 void COGLES1Driver::drawVertexPrimitiveList2d3d(const void* vertices, u32 vertexCount,\r
585                 const void* indexList, u32 primitiveCount,\r
586                 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType, bool threed)\r
587 {\r
588         if (!primitiveCount || !vertexCount)\r
589                 return;\r
590 \r
591         if (!threed && !checkPrimitiveCount(primitiveCount))\r
592                 return;\r
593 \r
594         CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);\r
595 \r
596         if (vertices)\r
597         {\r
598                 // convert colors to gl color format.\r
599                 vertexCount *= 4; //reused as color component count\r
600                 ColorBuffer.set_used(vertexCount);\r
601                 u32 i;\r
602 \r
603                 switch (vType)\r
604                 {\r
605                         case EVT_STANDARD:\r
606                         {\r
607                                 const S3DVertex* p = static_cast<const S3DVertex*>(vertices);\r
608                                 for ( i=0; i<vertexCount; i+=4)\r
609                                 {\r
610                                         p->Color.toOpenGLColor(&ColorBuffer[i]);\r
611                                         ++p;\r
612                                 }\r
613                         }\r
614                         break;\r
615                         case EVT_2TCOORDS:\r
616                         {\r
617                                 const S3DVertex2TCoords* p = static_cast<const S3DVertex2TCoords*>(vertices);\r
618                                 for ( i=0; i<vertexCount; i+=4)\r
619                                 {\r
620                                         p->Color.toOpenGLColor(&ColorBuffer[i]);\r
621                                         ++p;\r
622                                 }\r
623                         }\r
624                         break;\r
625                         case EVT_TANGENTS:\r
626                         {\r
627                                 const S3DVertexTangents* p = static_cast<const S3DVertexTangents*>(vertices);\r
628                                 for ( i=0; i<vertexCount; i+=4)\r
629                                 {\r
630                                         p->Color.toOpenGLColor(&ColorBuffer[i]);\r
631                                         ++p;\r
632                                 }\r
633                         }\r
634                         break;\r
635                 }\r
636         }\r
637 \r
638         // draw everything\r
639         glClientActiveTexture(GL_TEXTURE0);\r
640         glEnableClientState(GL_COLOR_ARRAY);\r
641         glEnableClientState(GL_VERTEX_ARRAY);\r
642         if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES))\r
643                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);\r
644 #ifdef GL_OES_point_size_array\r
645         else if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_point_size_array] && (Material.Thickness==0.0f))\r
646                 glEnableClientState(GL_POINT_SIZE_ARRAY_OES);\r
647 #endif\r
648         if (threed && (pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES))\r
649                 glEnableClientState(GL_NORMAL_ARRAY);\r
650 \r
651         if (vertices)\r
652                 glColorPointer(4, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
653 \r
654         switch (vType)\r
655         {\r
656                 case EVT_STANDARD:\r
657                         if (vertices)\r
658                         {\r
659                                 if (threed)\r
660                                         glNormalPointer(GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Normal);\r
661                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);\r
662                                 glVertexPointer((threed ? 3 : 2), GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);\r
663                         }\r
664                         else\r
665                         {\r
666                                 glNormalPointer(GL_FLOAT, sizeof(S3DVertex), buffer_offset(12));\r
667                                 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24));\r
668                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));\r
669                                 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), 0);\r
670                         }\r
671 \r
672                         if (Feature.MaxTextureUnits > 0 && CacheHandler->getTextureCache().get(1))\r
673                         {\r
674                                 glClientActiveTexture(GL_TEXTURE0 + 1);\r
675                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);\r
676                                 if (vertices)\r
677                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);\r
678                                 else\r
679                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));\r
680                         }\r
681                         break;\r
682                 case EVT_2TCOORDS:\r
683                         if (vertices)\r
684                         {\r
685                                 if (threed)\r
686                                         glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Normal);\r
687                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords);\r
688                                 glVertexPointer((threed ? 3 : 2), GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Pos);\r
689                         }\r
690                         else\r
691                         {\r
692                                 glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(12));\r
693                                 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24));\r
694                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28));\r
695                                 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0));\r
696                         }\r
697 \r
698                         if (Feature.MaxTextureUnits > 0)\r
699                         {\r
700                                 glClientActiveTexture(GL_TEXTURE0 + 1);\r
701                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);\r
702                                 if (vertices)\r
703                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords2);\r
704                                 else\r
705                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36));\r
706                         }\r
707                         break;\r
708                 case EVT_TANGENTS:\r
709                         if (vertices)\r
710                         {\r
711                                 if (threed)\r
712                                         glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Normal);\r
713                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].TCoords);\r
714                                 glVertexPointer((threed ? 3 : 2), GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Pos);\r
715                         }\r
716                         else\r
717                         {\r
718                                 glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(12));\r
719                                 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24));\r
720                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28));\r
721                                 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0));\r
722                         }\r
723 \r
724                         if (Feature.MaxTextureUnits > 0)\r
725                         {\r
726                                 glClientActiveTexture(GL_TEXTURE0 + 1);\r
727                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);\r
728                                 if (vertices)\r
729                                         glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Tangent);\r
730                                 else\r
731                                         glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36));\r
732 \r
733                                 glClientActiveTexture(GL_TEXTURE0 + 2);\r
734                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);\r
735                                 if (vertices)\r
736                                         glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Binormal);\r
737                                 else\r
738                                         glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48));\r
739                         }\r
740                         break;\r
741         }\r
742 \r
743         GLenum indexSize=0;\r
744 \r
745         switch (iType)\r
746         {\r
747                 case (EIT_16BIT):\r
748                 {\r
749                         indexSize=GL_UNSIGNED_SHORT;\r
750                         break;\r
751                 }\r
752                 case (EIT_32BIT):\r
753                 {\r
754 #ifdef GL_OES_element_index_uint\r
755 #ifndef GL_UNSIGNED_INT\r
756 #define GL_UNSIGNED_INT                   0x1405\r
757 #endif\r
758                         if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_element_index_uint])\r
759                                 indexSize=GL_UNSIGNED_INT;\r
760                         else\r
761 #endif\r
762                         indexSize=GL_UNSIGNED_SHORT;\r
763                         break;\r
764                 }\r
765         }\r
766 \r
767         switch (pType)\r
768         {\r
769                 case scene::EPT_POINTS:\r
770                 case scene::EPT_POINT_SPRITES:\r
771                 {\r
772 #ifdef GL_OES_point_sprite\r
773                         if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_point_sprite])\r
774                                 glEnable(GL_POINT_SPRITE_OES);\r
775 #endif\r
776                         // if ==0 we use the point size array\r
777                         if (Material.Thickness!=0.f)\r
778                         {\r
779                                 float quadratic[] = {0.0f, 0.0f, 10.01f};\r
780                                 glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, quadratic);\r
781                                 float maxParticleSize=1.0f;\r
782                                 glGetFloatv(GL_POINT_SIZE_MAX, &maxParticleSize);\r
783 //                              maxParticleSize=maxParticleSize<Material.Thickness?maxParticleSize:Material.Thickness;\r
784 //                              extGlPointParameterf(GL_POINT_SIZE_MAX,maxParticleSize);\r
785 //                              extGlPointParameterf(GL_POINT_SIZE_MIN,Material.Thickness);\r
786                                 glPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE, 60.0f);\r
787                                 glPointSize(Material.Thickness);\r
788                         }\r
789 #ifdef GL_OES_point_sprite\r
790                         if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_point_sprite])\r
791                                 glTexEnvf(GL_POINT_SPRITE_OES,GL_COORD_REPLACE_OES, GL_TRUE);\r
792 #endif\r
793                         glDrawArrays(GL_POINTS, 0, primitiveCount);\r
794 #ifdef GL_OES_point_sprite\r
795                         if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_point_sprite])\r
796                         {\r
797                                 glDisable(GL_POINT_SPRITE_OES);\r
798                                 glTexEnvf(GL_POINT_SPRITE_OES,GL_COORD_REPLACE_OES, GL_FALSE);\r
799                         }\r
800 #endif\r
801                 }\r
802                         break;\r
803                 case scene::EPT_LINE_STRIP:\r
804                         glDrawElements(GL_LINE_STRIP, primitiveCount+1, indexSize, indexList);\r
805                         break;\r
806                 case scene::EPT_LINE_LOOP:\r
807                         glDrawElements(GL_LINE_LOOP, primitiveCount, indexSize, indexList);\r
808                         break;\r
809                 case scene::EPT_LINES:\r
810                         glDrawElements(GL_LINES, primitiveCount*2, indexSize, indexList);\r
811                         break;\r
812                 case scene::EPT_TRIANGLE_STRIP:\r
813                         glDrawElements(GL_TRIANGLE_STRIP, primitiveCount+2, indexSize, indexList);\r
814                         break;\r
815                 case scene::EPT_TRIANGLE_FAN:\r
816                         glDrawElements(GL_TRIANGLE_FAN, primitiveCount+2, indexSize, indexList);\r
817                         break;\r
818                 case scene::EPT_TRIANGLES:\r
819                         glDrawElements((LastMaterial.Wireframe)?GL_LINES:(LastMaterial.PointCloud)?GL_POINTS:GL_TRIANGLES, primitiveCount*3, indexSize, indexList);\r
820                         break;\r
821                 case scene::EPT_QUAD_STRIP:\r
822                 case scene::EPT_QUADS:\r
823                 case scene::EPT_POLYGON:\r
824                         break;\r
825         }\r
826 \r
827         if (Feature.MaxTextureUnits > 0)\r
828         {\r
829                 if (vType == EVT_TANGENTS)\r
830                 {\r
831                         glClientActiveTexture(GL_TEXTURE0 + 2);\r
832                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);\r
833                 }\r
834                 if ((vType != EVT_STANDARD) || CacheHandler->getTextureCache().get(1))\r
835                 {\r
836                         glClientActiveTexture(GL_TEXTURE0 + 1);\r
837                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);\r
838                 }\r
839                 glClientActiveTexture(GL_TEXTURE0);\r
840         }\r
841 \r
842 #ifdef GL_OES_point_size_array\r
843         if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_point_size_array] && (Material.Thickness==0.0f))\r
844                 glDisableClientState(GL_POINT_SIZE_ARRAY_OES);\r
845 #endif\r
846 \r
847         glDisableClientState(GL_COLOR_ARRAY);\r
848         glDisableClientState(GL_VERTEX_ARRAY);\r
849         glDisableClientState(GL_NORMAL_ARRAY);\r
850         glDisableClientState(GL_TEXTURE_COORD_ARRAY);\r
851 }\r
852 \r
853 \r
854 //! draws a 2d image, using a color and the alpha channel of the texture\r
855 void COGLES1Driver::draw2DImage(const video::ITexture* texture,\r
856                                 const core::position2d<s32>& pos,\r
857                                 const core::rect<s32>& sourceRect,\r
858                                 const core::rect<s32>* clipRect, SColor color,\r
859                                 bool useAlphaChannelOfTexture)\r
860 {\r
861         if (!texture)\r
862                 return;\r
863 \r
864         if (!sourceRect.isValid())\r
865                 return;\r
866 \r
867         core::position2d<s32> targetPos(pos);\r
868         core::position2d<s32> sourcePos(sourceRect.UpperLeftCorner);\r
869         core::dimension2d<s32> sourceSize(sourceRect.getSize());\r
870         if (clipRect)\r
871         {\r
872                 if (targetPos.X < clipRect->UpperLeftCorner.X)\r
873                 {\r
874                         sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X;\r
875                         if (sourceSize.Width <= 0)\r
876                                 return;\r
877 \r
878                         sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X;\r
879                         targetPos.X = clipRect->UpperLeftCorner.X;\r
880                 }\r
881 \r
882                 if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X)\r
883                 {\r
884                         sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X;\r
885                         if (sourceSize.Width <= 0)\r
886                                 return;\r
887                 }\r
888 \r
889                 if (targetPos.Y < clipRect->UpperLeftCorner.Y)\r
890                 {\r
891                         sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y;\r
892                         if (sourceSize.Height <= 0)\r
893                                 return;\r
894 \r
895                         sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y;\r
896                         targetPos.Y = clipRect->UpperLeftCorner.Y;\r
897                 }\r
898 \r
899                 if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y)\r
900                 {\r
901                         sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y;\r
902                         if (sourceSize.Height <= 0)\r
903                                 return;\r
904                 }\r
905         }\r
906 \r
907         // clip these coordinates\r
908 \r
909         if (targetPos.X<0)\r
910         {\r
911                 sourceSize.Width += targetPos.X;\r
912                 if (sourceSize.Width <= 0)\r
913                         return;\r
914 \r
915                 sourcePos.X -= targetPos.X;\r
916                 targetPos.X = 0;\r
917         }\r
918 \r
919         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
920 \r
921         if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width)\r
922         {\r
923                 sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width;\r
924                 if (sourceSize.Width <= 0)\r
925                         return;\r
926         }\r
927 \r
928         if (targetPos.Y<0)\r
929         {\r
930                 sourceSize.Height += targetPos.Y;\r
931                 if (sourceSize.Height <= 0)\r
932                         return;\r
933 \r
934                 sourcePos.Y -= targetPos.Y;\r
935                 targetPos.Y = 0;\r
936         }\r
937 \r
938         if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height)\r
939         {\r
940                 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height;\r
941                 if (sourceSize.Height <= 0)\r
942                         return;\r
943         }\r
944 \r
945         // ok, we've clipped everything.\r
946         // now draw it.\r
947 \r
948         // texcoords need to be flipped horizontally for RTTs\r
949         const bool isRTT = texture->isRenderTarget();\r
950         const core::dimension2d<u32>& ss = texture->getOriginalSize();\r
951         const f32 invW = 1.f / static_cast<f32>(ss.Width);\r
952         const f32 invH = 1.f / static_cast<f32>(ss.Height);\r
953         const core::rect<f32> tcoords(\r
954                         sourcePos.X * invW,\r
955                         (isRTT?(sourcePos.Y + sourceSize.Height):sourcePos.Y) * invH,\r
956                         (sourcePos.X + sourceSize.Width) * invW,\r
957                         (isRTT?sourcePos.Y:(sourcePos.Y + sourceSize.Height)) * invH);\r
958 \r
959         const core::rect<s32> poss(targetPos, sourceSize);\r
960 \r
961         if (!CacheHandler->getTextureCache().set(0, texture))\r
962                 return;\r
963 \r
964         setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);\r
965 \r
966         u16 indices[] = {0,1,2,3};\r
967         S3DVertex vertices[4];\r
968         vertices[0] = S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);\r
969         vertices[1] = S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);\r
970         vertices[2] = S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);\r
971         vertices[3] = S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);\r
972         drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false);\r
973 }\r
974 \r
975 \r
976 //! The same, but with a four element array of colors, one for each vertex\r
977 void COGLES1Driver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,\r
978                 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,\r
979                 const video::SColor* const colors, bool useAlphaChannelOfTexture)\r
980 {\r
981         if (!texture)\r
982                 return;\r
983 \r
984         // texcoords need to be flipped horizontally for RTTs\r
985         const bool isRTT = texture->isRenderTarget();\r
986         const core::dimension2du& ss = texture->getOriginalSize();\r
987         const f32 invW = 1.f / static_cast<f32>(ss.Width);\r
988         const f32 invH = 1.f / static_cast<f32>(ss.Height);\r
989         const core::rect<f32> tcoords(\r
990                         sourceRect.UpperLeftCorner.X * invW,\r
991                         (isRTT?sourceRect.LowerRightCorner.Y:sourceRect.UpperLeftCorner.Y) * invH,\r
992                         sourceRect.LowerRightCorner.X * invW,\r
993                         (isRTT?sourceRect.UpperLeftCorner.Y:sourceRect.LowerRightCorner.Y) *invH);\r
994 \r
995         const video::SColor temp[4] =\r
996         {\r
997                 0xFFFFFFFF,\r
998                 0xFFFFFFFF,\r
999                 0xFFFFFFFF,\r
1000                 0xFFFFFFFF\r
1001         };\r
1002 \r
1003         const video::SColor* const useColor = colors ? colors : temp;\r
1004 \r
1005         if (!CacheHandler->getTextureCache().set(0, texture))\r
1006                 return;\r
1007 \r
1008         setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 ||\r
1009                         useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255,\r
1010                         true, useAlphaChannelOfTexture);\r
1011 \r
1012         if (clipRect)\r
1013         {\r
1014                 if (!clipRect->isValid())\r
1015                         return;\r
1016 \r
1017                 glEnable(GL_SCISSOR_TEST);\r
1018                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1019                 glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y,\r
1020                         clipRect->getWidth(), clipRect->getHeight());\r
1021         }\r
1022 \r
1023         u16 indices[] = {0,1,2,3};\r
1024         S3DVertex vertices[4];\r
1025         vertices[0] = S3DVertex((f32)destRect.UpperLeftCorner.X, (f32)destRect.UpperLeftCorner.Y, 0, 0,0,1, useColor[0], tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);\r
1026         vertices[1] = S3DVertex((f32)destRect.LowerRightCorner.X, (f32)destRect.UpperLeftCorner.Y, 0, 0,0,1, useColor[3], tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);\r
1027         vertices[2] = S3DVertex((f32)destRect.LowerRightCorner.X, (f32)destRect.LowerRightCorner.Y, 0, 0,0,1, useColor[2], tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);\r
1028         vertices[3] = S3DVertex((f32)destRect.UpperLeftCorner.X, (f32)destRect.LowerRightCorner.Y, 0, 0,0,1, useColor[1], tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);\r
1029         drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false);\r
1030 \r
1031         if (clipRect)\r
1032                 glDisable(GL_SCISSOR_TEST);\r
1033 }\r
1034 \r
1035 void COGLES1Driver::draw2DImage(const video::ITexture* texture, u32 layer, bool flip)\r
1036 {\r
1037         if (!texture || !CacheHandler->getTextureCache().set(0, texture))\r
1038                 return;\r
1039 \r
1040         setRenderStates2DMode(false, true, true);\r
1041 \r
1042         glMatrixMode(GL_PROJECTION);\r
1043         glLoadIdentity();\r
1044         glMatrixMode(GL_MODELVIEW);\r
1045         glLoadIdentity();\r
1046 \r
1047         Transformation3DChanged = true;\r
1048 \r
1049         u16 indices[] = { 0,1,2,3 };\r
1050         S3DVertex vertices[4];\r
1051 \r
1052         vertices[0].Pos = core::vector3df(-1.f, 1.f, 0.f);\r
1053         vertices[1].Pos = core::vector3df(1.f, 1.f, 0.f);\r
1054         vertices[2].Pos = core::vector3df(1.f, -1.f, 0.f);\r
1055         vertices[3].Pos = core::vector3df(-1.f, -1.f, 0.f);\r
1056 \r
1057         f32 modificator = (flip) ? 1.f : 0.f;\r
1058 \r
1059         vertices[0].TCoords = core::vector2df(0.f, 0.f + modificator);\r
1060         vertices[1].TCoords = core::vector2df(1.f, 0.f + modificator);\r
1061         vertices[2].TCoords = core::vector2df(1.f, 1.f - modificator);\r
1062         vertices[3].TCoords = core::vector2df(0.f, 1.f - modificator);\r
1063 \r
1064         vertices[0].Color = 0xFFFFFFFF;\r
1065         vertices[1].Color = 0xFFFFFFFF;\r
1066         vertices[2].Color = 0xFFFFFFFF;\r
1067         vertices[3].Color = 0xFFFFFFFF;\r
1068 \r
1069         drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false);\r
1070 }\r
1071 \r
1072 \r
1073 //! draws a set of 2d images, using a color and the alpha channel\r
1074 void COGLES1Driver::draw2DImageBatch(const video::ITexture* texture,\r
1075                                 const core::position2d<s32>& pos,\r
1076                                 const core::array<core::rect<s32> >& sourceRects,\r
1077                                 const core::array<s32>& indices, s32 kerningWidth,\r
1078                                 const core::rect<s32>* clipRect, SColor color,\r
1079                                 bool useAlphaChannelOfTexture)\r
1080 {\r
1081         if (!texture)\r
1082                 return;\r
1083 \r
1084         if (!CacheHandler->getTextureCache().set(0, texture))\r
1085                 return;\r
1086 \r
1087         setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);\r
1088 \r
1089         if (clipRect)\r
1090         {\r
1091                 if (!clipRect->isValid())\r
1092                         return;\r
1093 \r
1094                 glEnable(GL_SCISSOR_TEST);\r
1095                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1096                 glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y,\r
1097                         clipRect->getWidth(),clipRect->getHeight());\r
1098         }\r
1099 \r
1100         const core::dimension2du& ss = texture->getOriginalSize();\r
1101         core::position2d<s32> targetPos(pos);\r
1102         // texcoords need to be flipped horizontally for RTTs\r
1103         const bool isRTT = texture->isRenderTarget();\r
1104         const f32 invW = 1.f / static_cast<f32>(ss.Width);\r
1105         const f32 invH = 1.f / static_cast<f32>(ss.Height);\r
1106 \r
1107         core::array<S3DVertex> vertices;\r
1108         core::array<u16> quadIndices;\r
1109         vertices.reallocate(indices.size()*4);\r
1110         quadIndices.reallocate(indices.size()*6);\r
1111         for (u32 i=0; i<indices.size(); ++i)\r
1112         {\r
1113                 const s32 currentIndex = indices[i];\r
1114                 if (!sourceRects[currentIndex].isValid())\r
1115                         break;\r
1116 \r
1117                 const core::rect<f32> tcoords(\r
1118                                 sourceRects[currentIndex].UpperLeftCorner.X * invW,\r
1119                                 (isRTT?sourceRects[currentIndex].LowerRightCorner.Y:sourceRects[currentIndex].UpperLeftCorner.Y) * invH,\r
1120                                 sourceRects[currentIndex].LowerRightCorner.X * invW,\r
1121                                 (isRTT?sourceRects[currentIndex].UpperLeftCorner.Y:sourceRects[currentIndex].LowerRightCorner.Y) * invH);\r
1122 \r
1123                 const core::rect<s32> poss(targetPos, sourceRects[currentIndex].getSize());\r
1124 \r
1125                 const u32 vstart = vertices.size();\r
1126 \r
1127                 vertices.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y));\r
1128                 vertices.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y));\r
1129                 vertices.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y));\r
1130                 vertices.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y));\r
1131 \r
1132                 quadIndices.push_back(vstart);\r
1133                 quadIndices.push_back(vstart+1);\r
1134                 quadIndices.push_back(vstart+2);\r
1135                 quadIndices.push_back(vstart);\r
1136                 quadIndices.push_back(vstart+2);\r
1137                 quadIndices.push_back(vstart+3);\r
1138 \r
1139                 targetPos.X += sourceRects[currentIndex].getWidth();\r
1140         }\r
1141         if (vertices.size())\r
1142                 drawVertexPrimitiveList2d3d(vertices.pointer(), vertices.size(),\r
1143                                 quadIndices.pointer(), vertices.size()/2,\r
1144                                 video::EVT_STANDARD, scene::EPT_TRIANGLES,\r
1145                                 EIT_16BIT, false);\r
1146         if (clipRect)\r
1147                 glDisable(GL_SCISSOR_TEST);\r
1148 }\r
1149 \r
1150 \r
1151 //! draws a set of 2d images, using a color and the alpha channel of the texture if desired.\r
1152 void COGLES1Driver::draw2DImageBatch(const video::ITexture* texture,\r
1153                                 const core::array<core::position2d<s32> >& positions,\r
1154                                 const core::array<core::rect<s32> >& sourceRects,\r
1155                                 const core::rect<s32>* clipRect,\r
1156                                 SColor color,\r
1157                                 bool useAlphaChannelOfTexture)\r
1158 {\r
1159         if (!texture)\r
1160                 return;\r
1161 \r
1162         const u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());\r
1163         if (!drawCount)\r
1164                 return;\r
1165 \r
1166         const core::dimension2d<u32>& ss = texture->getOriginalSize();\r
1167         if (!ss.Width || !ss.Height)\r
1168                 return;\r
1169         const f32 invW = 1.f / static_cast<f32>(ss.Width);\r
1170         const f32 invH = 1.f / static_cast<f32>(ss.Height);\r
1171         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1172 \r
1173         if (!CacheHandler->getTextureCache().set(0, texture))\r
1174                 return;\r
1175 \r
1176         setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);\r
1177 \r
1178         core::array<S3DVertex> vertices;\r
1179         core::array<u16> quadIndices;\r
1180         vertices.reallocate(drawCount*4);\r
1181         quadIndices.reallocate(drawCount*6);\r
1182 \r
1183         for (u32 i=0; i<drawCount; ++i)\r
1184         {\r
1185                 if (!sourceRects[i].isValid())\r
1186                         continue;\r
1187 \r
1188                 core::position2d<s32> targetPos(positions[i]);\r
1189                 core::position2d<s32> sourcePos(sourceRects[i].UpperLeftCorner);\r
1190                 // This needs to be signed as it may go negative.\r
1191                 core::dimension2d<s32> sourceSize(sourceRects[i].getSize());\r
1192                 if (clipRect)\r
1193                 {\r
1194                         if (targetPos.X < clipRect->UpperLeftCorner.X)\r
1195                         {\r
1196                                 sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X;\r
1197                                 if (sourceSize.Width <= 0)\r
1198                                         continue;\r
1199 \r
1200                                 sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X;\r
1201                                 targetPos.X = clipRect->UpperLeftCorner.X;\r
1202                         }\r
1203 \r
1204                         if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X)\r
1205                         {\r
1206                                 sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X;\r
1207                                 if (sourceSize.Width <= 0)\r
1208                                         continue;\r
1209                         }\r
1210 \r
1211                         if (targetPos.Y < clipRect->UpperLeftCorner.Y)\r
1212                         {\r
1213                                 sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y;\r
1214                                 if (sourceSize.Height <= 0)\r
1215                                         continue;\r
1216 \r
1217                                 sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y;\r
1218                                 targetPos.Y = clipRect->UpperLeftCorner.Y;\r
1219                         }\r
1220 \r
1221                         if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y)\r
1222                         {\r
1223                                 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y;\r
1224                                 if (sourceSize.Height <= 0)\r
1225                                         continue;\r
1226                         }\r
1227                 }\r
1228 \r
1229                 // clip these coordinates\r
1230 \r
1231                 if (targetPos.X<0)\r
1232                 {\r
1233                         sourceSize.Width += targetPos.X;\r
1234                         if (sourceSize.Width <= 0)\r
1235                                 continue;\r
1236 \r
1237                         sourcePos.X -= targetPos.X;\r
1238                         targetPos.X = 0;\r
1239                 }\r
1240 \r
1241                 if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width)\r
1242                 {\r
1243                         sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width;\r
1244                         if (sourceSize.Width <= 0)\r
1245                                 continue;\r
1246                 }\r
1247 \r
1248                 if (targetPos.Y<0)\r
1249                 {\r
1250                         sourceSize.Height += targetPos.Y;\r
1251                         if (sourceSize.Height <= 0)\r
1252                                 continue;\r
1253 \r
1254                         sourcePos.Y -= targetPos.Y;\r
1255                         targetPos.Y = 0;\r
1256                 }\r
1257 \r
1258                 if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height)\r
1259                 {\r
1260                         sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height;\r
1261                         if (sourceSize.Height <= 0)\r
1262                                 continue;\r
1263                 }\r
1264 \r
1265                 // ok, we've clipped everything.\r
1266 \r
1267                 const core::rect<f32> tcoords(\r
1268                                 sourcePos.X * invW,\r
1269                                 sourcePos.Y * invH,\r
1270                                 (sourcePos.X + sourceSize.Width) * invW,\r
1271                                 (sourcePos.Y + sourceSize.Height) * invH);\r
1272 \r
1273                 const core::rect<s32> poss(targetPos, sourceSize);\r
1274 \r
1275                 const u32 vstart = vertices.size();\r
1276 \r
1277                 vertices.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y));\r
1278                 vertices.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y));\r
1279                 vertices.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y));\r
1280                 vertices.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y));\r
1281 \r
1282                 quadIndices.push_back(vstart);\r
1283                 quadIndices.push_back(vstart+1);\r
1284                 quadIndices.push_back(vstart+2);\r
1285                 quadIndices.push_back(vstart);\r
1286                 quadIndices.push_back(vstart+2);\r
1287                 quadIndices.push_back(vstart+3);\r
1288         }\r
1289         if (vertices.size())\r
1290                 drawVertexPrimitiveList2d3d(vertices.pointer(), vertices.size(),\r
1291                                 quadIndices.pointer(), vertices.size()/2,\r
1292                                 video::EVT_STANDARD, scene::EPT_TRIANGLES,\r
1293                                 EIT_16BIT, false);\r
1294 }\r
1295 \r
1296 \r
1297 //! draw a 2d rectangle\r
1298 void COGLES1Driver::draw2DRectangle(SColor color, const core::rect<s32>& position,\r
1299                 const core::rect<s32>* clip)\r
1300 {\r
1301         setRenderStates2DMode(color.getAlpha() < 255, false, false);\r
1302 \r
1303         core::rect<s32> pos = position;\r
1304 \r
1305         if (clip)\r
1306                 pos.clipAgainst(*clip);\r
1307 \r
1308         if (!pos.isValid())\r
1309                 return;\r
1310 \r
1311         u16 indices[] = {0,1,2,3};\r
1312         S3DVertex vertices[4];\r
1313         vertices[0] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.UpperLeftCorner.Y, 0, 0,0,1, color, 0,0);\r
1314         vertices[1] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.UpperLeftCorner.Y, 0, 0,0,1, color, 0,0);\r
1315         vertices[2] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.LowerRightCorner.Y, 0, 0,0,1, color, 0,0);\r
1316         vertices[3] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.LowerRightCorner.Y, 0, 0,0,1, color, 0,0);\r
1317         drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false);\r
1318 }\r
1319 \r
1320 \r
1321 //! draw an 2d rectangle\r
1322 void COGLES1Driver::draw2DRectangle(const core::rect<s32>& position,\r
1323                         SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,\r
1324                         const core::rect<s32>* clip)\r
1325 {\r
1326         core::rect<s32> pos = position;\r
1327 \r
1328         if (clip)\r
1329                 pos.clipAgainst(*clip);\r
1330 \r
1331         if (!pos.isValid())\r
1332                 return;\r
1333 \r
1334         setRenderStates2DMode(colorLeftUp.getAlpha() < 255 ||\r
1335                 colorRightUp.getAlpha() < 255 ||\r
1336                 colorLeftDown.getAlpha() < 255 ||\r
1337                 colorRightDown.getAlpha() < 255, false, false);\r
1338 \r
1339         u16 indices[] = {0,1,2,3};\r
1340         S3DVertex vertices[4];\r
1341         vertices[0] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.UpperLeftCorner.Y, 0, 0,0,1, colorLeftUp, 0,0);\r
1342         vertices[1] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.UpperLeftCorner.Y, 0, 0,0,1, colorRightUp, 0,0);\r
1343         vertices[2] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.LowerRightCorner.Y, 0, 0,0,1, colorRightDown, 0,0);\r
1344         vertices[3] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.LowerRightCorner.Y, 0, 0,0,1, colorLeftDown, 0,0);\r
1345         drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false);\r
1346 }\r
1347 \r
1348 \r
1349 //! Draws a 2d line.\r
1350 void COGLES1Driver::draw2DLine(const core::position2d<s32>& start,\r
1351                                 const core::position2d<s32>& end,\r
1352                                 SColor color)\r
1353 {\r
1354         setRenderStates2DMode(color.getAlpha() < 255, false, false);\r
1355 \r
1356         u16 indices[] = {0,1};\r
1357         S3DVertex vertices[2];\r
1358         vertices[0] = S3DVertex((f32)start.X, (f32)start.Y, 0, 0,0,1, color, 0,0);\r
1359         vertices[1] = S3DVertex((f32)end.X, (f32)end.Y, 0, 0,0,1, color, 1,1);\r
1360         drawVertexPrimitiveList2d3d(vertices, 2, indices, 1, video::EVT_STANDARD, scene::EPT_LINES, EIT_16BIT, false);\r
1361 }\r
1362 \r
1363 \r
1364 //! Draws a pixel\r
1365 void COGLES1Driver::drawPixel(u32 x, u32 y, const SColor &color)\r
1366 {\r
1367         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1368         if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height)\r
1369                 return;\r
1370 \r
1371         setRenderStates2DMode(color.getAlpha() < 255, false, false);\r
1372 \r
1373         u16 indices[] = {0};\r
1374         S3DVertex vertices[1];\r
1375         vertices[0] = S3DVertex((f32)x, (f32)y, 0, 0, 0, 1, color, 0, 0);\r
1376         drawVertexPrimitiveList2d3d(vertices, 1, indices, 1, video::EVT_STANDARD, scene::EPT_POINTS, EIT_16BIT, false);\r
1377 }\r
1378 \r
1379 \r
1380 //! creates a matrix in supplied GLfloat array to pass to OGLES1\r
1381 inline void COGLES1Driver::getGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m)\r
1382 {\r
1383         memcpy(gl_matrix, m.pointer(), 16 * sizeof(f32));\r
1384 }\r
1385 \r
1386 \r
1387 //! creates a opengltexturematrix from a D3D style texture matrix\r
1388 inline void COGLES1Driver::getGLTextureMatrix(GLfloat *o, const core::matrix4& m)\r
1389 {\r
1390         o[0] = m[0];\r
1391         o[1] = m[1];\r
1392         o[2] = 0.f;\r
1393         o[3] = 0.f;\r
1394 \r
1395         o[4] = m[4];\r
1396         o[5] = m[5];\r
1397         o[6] = 0.f;\r
1398         o[7] = 0.f;\r
1399 \r
1400         o[8] = 0.f;\r
1401         o[9] = 0.f;\r
1402         o[10] = 1.f;\r
1403         o[11] = 0.f;\r
1404 \r
1405         o[12] = m[8];\r
1406         o[13] = m[9];\r
1407         o[14] = 0.f;\r
1408         o[15] = 1.f;\r
1409 }\r
1410 \r
1411 ITexture* COGLES1Driver::createDeviceDependentTexture(const io::path& name, IImage* image)\r
1412 {\r
1413         core::array<IImage*> imageArray(1);\r
1414         imageArray.push_back(image);\r
1415 \r
1416         COGLES1Texture* texture = new COGLES1Texture(name, imageArray, ETT_2D, this);\r
1417 \r
1418         return texture;\r
1419 }\r
1420 \r
1421 ITexture* COGLES1Driver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)\r
1422 {\r
1423         COGLES1Texture* texture = new COGLES1Texture(name, image, ETT_CUBEMAP, this);\r
1424 \r
1425         return texture;\r
1426 }\r
1427 \r
1428 //! Sets a material. All 3d drawing functions draw geometry now using this material.\r
1429 void COGLES1Driver::setMaterial(const SMaterial& material)\r
1430 {\r
1431         Material = material;\r
1432         OverrideMaterial.apply(Material);\r
1433 \r
1434         for (u32 i = 0; i < Feature.MaxTextureUnits; ++i)\r
1435                 setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i));\r
1436 }\r
1437 \r
1438 \r
1439 //! prints error if an error happened.\r
1440 bool COGLES1Driver::testGLError(int code)\r
1441 {\r
1442 #ifdef _DEBUG\r
1443         GLenum g = glGetError();\r
1444         switch(g)\r
1445         {\r
1446         case GL_NO_ERROR:\r
1447                 return false;\r
1448         case GL_INVALID_ENUM:\r
1449                 os::Printer::log("GL_INVALID_ENUM", core::stringc(code).c_str(), ELL_ERROR); break;\r
1450         case GL_INVALID_VALUE:\r
1451                 os::Printer::log("GL_INVALID_VALUE", core::stringc(code).c_str(), ELL_ERROR); break;\r
1452         case GL_INVALID_OPERATION:\r
1453                 os::Printer::log("GL_INVALID_OPERATION", core::stringc(code).c_str(), ELL_ERROR); break;\r
1454         case GL_STACK_OVERFLOW:\r
1455                 os::Printer::log("GL_STACK_OVERFLOW", core::stringc(code).c_str(), ELL_ERROR); break;\r
1456         case GL_STACK_UNDERFLOW:\r
1457                 os::Printer::log("GL_STACK_UNDERFLOW", core::stringc(code).c_str(), ELL_ERROR); break;\r
1458         case GL_OUT_OF_MEMORY:\r
1459                 os::Printer::log("GL_OUT_OF_MEMORY", core::stringc(code).c_str(), ELL_ERROR); break;\r
1460         };\r
1461 //      _IRR_DEBUG_BREAK_IF(true);\r
1462         return true;\r
1463 #else\r
1464         return false;\r
1465 #endif\r
1466 }\r
1467 \r
1468 \r
1469 //! sets the needed renderstates\r
1470 void COGLES1Driver::setRenderStates3DMode()\r
1471 {\r
1472         if (CurrentRenderMode != ERM_3D)\r
1473         {\r
1474                 // Reset Texture Stages\r
1475                 CacheHandler->setBlend(false);\r
1476                 glDisable(GL_ALPHA_TEST);\r
1477                 CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
1478 \r
1479                 // switch back the matrices\r
1480                 glMatrixMode(GL_MODELVIEW);\r
1481                 glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer());\r
1482 \r
1483                 GLfloat glmat[16];\r
1484                 getGLMatrix(glmat, Matrices[ETS_PROJECTION]);\r
1485                 glmat[12] *= -1.0f;\r
1486                 glMatrixMode(GL_PROJECTION);\r
1487                 glLoadMatrixf(glmat);\r
1488 \r
1489                 ResetRenderStates = true;\r
1490         }\r
1491 \r
1492         if ( ResetRenderStates || LastMaterial != Material)\r
1493         {\r
1494                 // unset old material\r
1495 \r
1496                 if (LastMaterial.MaterialType != Material.MaterialType &&\r
1497                                 static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())\r
1498                         MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();\r
1499 \r
1500                 // set new material.\r
1501                 if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())\r
1502                         MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial(\r
1503                                 Material, LastMaterial, ResetRenderStates, this);\r
1504 \r
1505                 LastMaterial = Material;\r
1506                 CacheHandler->correctCacheMaterial(LastMaterial);\r
1507                 ResetRenderStates = false;\r
1508         }\r
1509 \r
1510         if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())\r
1511                 MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD);\r
1512 \r
1513         CurrentRenderMode = ERM_3D;\r
1514 }\r
1515 \r
1516 \r
1517 GLint COGLES1Driver::getTextureWrapMode(u8 clamp) const\r
1518 {\r
1519         switch (clamp)\r
1520         {\r
1521                 case ETC_CLAMP:\r
1522                         //      return GL_CLAMP; not supported in ogl-es\r
1523                         return GL_CLAMP_TO_EDGE;\r
1524                         break;\r
1525                 case ETC_CLAMP_TO_EDGE:\r
1526                         return GL_CLAMP_TO_EDGE;\r
1527                         break;\r
1528                 case ETC_CLAMP_TO_BORDER:\r
1529                         //      return GL_CLAMP_TO_BORDER; not supported in ogl-es\r
1530                         return GL_CLAMP_TO_EDGE;\r
1531                         break;\r
1532                 case ETC_MIRROR:\r
1533 #ifdef GL_OES_texture_mirrored_repeat\r
1534                         if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_texture_mirrored_repeat])\r
1535                                 return GL_MIRRORED_REPEAT_OES;\r
1536                         else\r
1537 #endif\r
1538                         return GL_REPEAT;\r
1539                         break;\r
1540                 // the next three are not yet supported at all\r
1541                 case ETC_MIRROR_CLAMP:\r
1542                 case ETC_MIRROR_CLAMP_TO_EDGE:\r
1543                 case ETC_MIRROR_CLAMP_TO_BORDER:\r
1544 #ifdef GL_OES_texture_mirrored_repeat\r
1545                         if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_texture_mirrored_repeat])\r
1546                                 return GL_MIRRORED_REPEAT_OES;\r
1547                         else\r
1548 #endif\r
1549                         return GL_CLAMP_TO_EDGE;\r
1550                         break;\r
1551                 case ETC_REPEAT:\r
1552                 default:\r
1553                         return GL_REPEAT;\r
1554                         break;\r
1555         }\r
1556 }\r
1557 \r
1558 \r
1559 //! Can be called by an IMaterialRenderer to make its work easier.\r
1560 void COGLES1Driver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial,\r
1561         bool resetAllRenderStates)\r
1562 {\r
1563         if (resetAllRenderStates ||\r
1564                 lastmaterial.ColorMaterial != material.ColorMaterial)\r
1565         {\r
1566                 // we only have diffuse_and_ambient in ogl-es\r
1567                 if (material.ColorMaterial == ECM_DIFFUSE_AND_AMBIENT)\r
1568                         glEnable(GL_COLOR_MATERIAL);\r
1569                 else\r
1570                         glDisable(GL_COLOR_MATERIAL);\r
1571         }\r
1572 \r
1573         if (resetAllRenderStates ||\r
1574                 lastmaterial.AmbientColor != material.AmbientColor ||\r
1575                 lastmaterial.DiffuseColor != material.DiffuseColor ||\r
1576                 lastmaterial.EmissiveColor != material.EmissiveColor ||\r
1577                 lastmaterial.ColorMaterial != material.ColorMaterial)\r
1578         {\r
1579                 GLfloat color[4];\r
1580 \r
1581                 const f32 inv = 1.0f / 255.0f;\r
1582 \r
1583                 if ((material.ColorMaterial != video::ECM_AMBIENT) &&\r
1584                         (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT))\r
1585                 {\r
1586                         color[0] = material.AmbientColor.getRed() * inv;\r
1587                         color[1] = material.AmbientColor.getGreen() * inv;\r
1588                         color[2] = material.AmbientColor.getBlue() * inv;\r
1589                         color[3] = material.AmbientColor.getAlpha() * inv;\r
1590                         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);\r
1591                 }\r
1592 \r
1593                 if ((material.ColorMaterial != video::ECM_DIFFUSE) &&\r
1594                         (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT))\r
1595                 {\r
1596                         color[0] = material.DiffuseColor.getRed() * inv;\r
1597                         color[1] = material.DiffuseColor.getGreen() * inv;\r
1598                         color[2] = material.DiffuseColor.getBlue() * inv;\r
1599                         color[3] = material.DiffuseColor.getAlpha() * inv;\r
1600                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);\r
1601                 }\r
1602 \r
1603                 if (material.ColorMaterial != video::ECM_EMISSIVE)\r
1604                 {\r
1605                         color[0] = material.EmissiveColor.getRed() * inv;\r
1606                         color[1] = material.EmissiveColor.getGreen() * inv;\r
1607                         color[2] = material.EmissiveColor.getBlue() * inv;\r
1608                         color[3] = material.EmissiveColor.getAlpha() * inv;\r
1609                         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color);\r
1610                 }\r
1611         }\r
1612 \r
1613         if (resetAllRenderStates ||\r
1614                 lastmaterial.SpecularColor != material.SpecularColor ||\r
1615                 lastmaterial.Shininess != material.Shininess)\r
1616         {\r
1617                 GLfloat color[]={0.f,0.f,0.f,1.f};\r
1618                 const f32 inv = 1.0f / 255.0f;\r
1619 \r
1620                 // disable Specular colors if no shininess is set\r
1621                 if ((material.Shininess != 0.0f) &&\r
1622                         (material.ColorMaterial != video::ECM_SPECULAR))\r
1623                 {\r
1624 #ifdef GL_EXT_separate_specular_color\r
1625                         if (FeatureAvailable[IRR_EXT_separate_specular_color])\r
1626                                 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);\r
1627 #endif\r
1628                         glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess);\r
1629                         color[0] = material.SpecularColor.getRed() * inv;\r
1630                         color[1] = material.SpecularColor.getGreen() * inv;\r
1631                         color[2] = material.SpecularColor.getBlue() * inv;\r
1632                         color[3] = material.SpecularColor.getAlpha() * inv;\r
1633                         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color);\r
1634                 }\r
1635 #ifdef GL_EXT_separate_specular_color\r
1636                 else\r
1637                         if (FeatureAvailable[IRR_EXT_separate_specular_color])\r
1638                                 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);\r
1639 #endif\r
1640         }\r
1641 \r
1642 // TODO ogl-es\r
1643         // fillmode\r
1644 //      if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud))\r
1645 //              glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL);\r
1646 \r
1647         // shademode\r
1648         if (resetAllRenderStates || (lastmaterial.GouraudShading != material.GouraudShading))\r
1649         {\r
1650                 if (material.GouraudShading)\r
1651                         glShadeModel(GL_SMOOTH);\r
1652                 else\r
1653                         glShadeModel(GL_FLAT);\r
1654         }\r
1655 \r
1656         // lighting\r
1657         if (resetAllRenderStates || (lastmaterial.Lighting != material.Lighting))\r
1658         {\r
1659                 if (material.Lighting)\r
1660                         glEnable(GL_LIGHTING);\r
1661                 else\r
1662                         glDisable(GL_LIGHTING);\r
1663         }\r
1664 \r
1665         // zbuffer\r
1666         if (resetAllRenderStates || lastmaterial.ZBuffer != material.ZBuffer)\r
1667         {\r
1668                 switch (material.ZBuffer)\r
1669                 {\r
1670                         case ECFN_DISABLED:\r
1671                                 glDisable(GL_DEPTH_TEST);\r
1672                                 break;\r
1673                         case ECFN_LESSEQUAL:\r
1674                                 glEnable(GL_DEPTH_TEST);\r
1675                                 glDepthFunc(GL_LEQUAL);\r
1676                                 break;\r
1677                         case ECFN_EQUAL:\r
1678                                 glEnable(GL_DEPTH_TEST);\r
1679                                 glDepthFunc(GL_EQUAL);\r
1680                                 break;\r
1681                         case ECFN_LESS:\r
1682                                 glEnable(GL_DEPTH_TEST);\r
1683                                 glDepthFunc(GL_LESS);\r
1684                                 break;\r
1685                         case ECFN_NOTEQUAL:\r
1686                                 glEnable(GL_DEPTH_TEST);\r
1687                                 glDepthFunc(GL_NOTEQUAL);\r
1688                                 break;\r
1689                         case ECFN_GREATEREQUAL:\r
1690                                 glEnable(GL_DEPTH_TEST);\r
1691                                 glDepthFunc(GL_GEQUAL);\r
1692                                 break;\r
1693                         case ECFN_GREATER:\r
1694                                 glEnable(GL_DEPTH_TEST);\r
1695                                 glDepthFunc(GL_GREATER);\r
1696                                 break;\r
1697                         case ECFN_ALWAYS:\r
1698                                 glEnable(GL_DEPTH_TEST);\r
1699                                 glDepthFunc(GL_ALWAYS);\r
1700                                 break;\r
1701                         case ECFN_NEVER:\r
1702                                 glEnable(GL_DEPTH_TEST);\r
1703                                 glDepthFunc(GL_NEVER);\r
1704                                 break;\r
1705                 }\r
1706         }\r
1707 \r
1708         // zwrite\r
1709         if (getWriteZBuffer(material))\r
1710         {\r
1711                 glDepthMask(GL_TRUE);\r
1712         }\r
1713         else\r
1714         {\r
1715                 glDepthMask(GL_FALSE);\r
1716         }\r
1717 \r
1718         // back face culling\r
1719         if (resetAllRenderStates || (lastmaterial.FrontfaceCulling != material.FrontfaceCulling) || (lastmaterial.BackfaceCulling != material.BackfaceCulling))\r
1720         {\r
1721                 if ((material.FrontfaceCulling) && (material.BackfaceCulling))\r
1722                 {\r
1723                         glCullFace(GL_FRONT_AND_BACK);\r
1724                         glEnable(GL_CULL_FACE);\r
1725                 }\r
1726                 else\r
1727                 if (material.BackfaceCulling)\r
1728                 {\r
1729                         glCullFace(GL_BACK);\r
1730                         glEnable(GL_CULL_FACE);\r
1731                 }\r
1732                 else\r
1733                 if (material.FrontfaceCulling)\r
1734                 {\r
1735                         glCullFace(GL_FRONT);\r
1736                         glEnable(GL_CULL_FACE);\r
1737                 }\r
1738                 else\r
1739                         glDisable(GL_CULL_FACE);\r
1740         }\r
1741 \r
1742         // fog\r
1743         if (resetAllRenderStates || lastmaterial.FogEnable != material.FogEnable)\r
1744         {\r
1745                 if (material.FogEnable)\r
1746                         glEnable(GL_FOG);\r
1747                 else\r
1748                         glDisable(GL_FOG);\r
1749         }\r
1750 \r
1751         // normalization\r
1752         if (resetAllRenderStates || lastmaterial.NormalizeNormals != material.NormalizeNormals)\r
1753         {\r
1754                 if (material.NormalizeNormals)\r
1755                         glEnable(GL_NORMALIZE);\r
1756                 else\r
1757                         glDisable(GL_NORMALIZE);\r
1758         }\r
1759 \r
1760         // Color Mask\r
1761         if (resetAllRenderStates || lastmaterial.ColorMask != material.ColorMask)\r
1762         {\r
1763                 glColorMask(\r
1764                         (material.ColorMask & ECP_RED)?GL_TRUE:GL_FALSE,\r
1765                         (material.ColorMask & ECP_GREEN)?GL_TRUE:GL_FALSE,\r
1766                         (material.ColorMask & ECP_BLUE)?GL_TRUE:GL_FALSE,\r
1767                         (material.ColorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE);\r
1768         }\r
1769 \r
1770         // Blend Equation\r
1771         if (material.BlendOperation == EBO_NONE)\r
1772                 CacheHandler->setBlend(false);\r
1773         else\r
1774         {\r
1775                 CacheHandler->setBlend(true);\r
1776 \r
1777                 if (queryFeature(EVDF_BLEND_OPERATIONS))\r
1778                 {\r
1779                         switch (material.BlendOperation)\r
1780                         {\r
1781                         case EBO_ADD:\r
1782 #if defined(GL_OES_blend_subtract)\r
1783                                 CacheHandler->setBlendEquation(GL_FUNC_ADD_OES);\r
1784 #endif\r
1785                                 break;\r
1786                         case EBO_SUBTRACT:\r
1787 #if defined(GL_OES_blend_subtract)\r
1788                                 CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT_OES);\r
1789 #endif\r
1790                                 break;\r
1791                         case EBO_REVSUBTRACT:\r
1792 #if defined(GL_OES_blend_subtract)\r
1793                                 CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT_OES);\r
1794 #endif\r
1795                                 break;\r
1796                         default:\r
1797                                 break;\r
1798                         }\r
1799                 }\r
1800         }\r
1801 \r
1802     // Blend Factor\r
1803         if (IR(material.BlendFactor) & 0xFFFFFFFF       // TODO: why the & 0xFFFFFFFF?\r
1804                         && material.MaterialType != EMT_ONETEXTURE_BLEND\r
1805                 )\r
1806         {\r
1807         E_BLEND_FACTOR srcRGBFact = EBF_ZERO;\r
1808         E_BLEND_FACTOR dstRGBFact = EBF_ZERO;\r
1809         E_BLEND_FACTOR srcAlphaFact = EBF_ZERO;\r
1810         E_BLEND_FACTOR dstAlphaFact = EBF_ZERO;\r
1811         E_MODULATE_FUNC modulo = EMFN_MODULATE_1X;\r
1812         u32 alphaSource = 0;\r
1813 \r
1814         unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulo, alphaSource, material.BlendFactor);\r
1815 \r
1816         if (queryFeature(EVDF_BLEND_SEPARATE))\r
1817         {\r
1818                         CacheHandler->setBlendFuncSeparate(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact),\r
1819                 getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact));\r
1820         }\r
1821         else\r
1822         {\r
1823                         CacheHandler->setBlendFunc(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact));\r
1824         }\r
1825         }\r
1826 \r
1827         // TODO: Polygon Offset. Not sure if it was left out deliberately or if it won't work with this driver.\r
1828 \r
1829         // thickness\r
1830         if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness)\r
1831         {\r
1832                 if (AntiAlias)\r
1833                 {\r
1834 //                      glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimSmoothedPoint[0], DimSmoothedPoint[1]));\r
1835                         // we don't use point smoothing\r
1836                         glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1]));\r
1837                 }\r
1838                 else\r
1839                 {\r
1840                         glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1]));\r
1841                         glLineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedLine[0], DimAliasedLine[1]));\r
1842                 }\r
1843         }\r
1844 \r
1845         // Anti aliasing\r
1846         if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing)\r
1847         {\r
1848 //              if (FeatureAvailable[IRR_ARB_multisample])\r
1849                 {\r
1850                         if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)\r
1851                                 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);\r
1852                         else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)\r
1853                                 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);\r
1854 \r
1855                         if ((AntiAlias >= 2) && (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY)))\r
1856                                 glEnable(GL_MULTISAMPLE);\r
1857                         else\r
1858                                 glDisable(GL_MULTISAMPLE);\r
1859                 }\r
1860                 if ((material.AntiAliasing & EAAM_LINE_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH))\r
1861                 {\r
1862                         if (material.AntiAliasing & EAAM_LINE_SMOOTH)\r
1863                                 glEnable(GL_LINE_SMOOTH);\r
1864                         else if (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH)\r
1865                                 glDisable(GL_LINE_SMOOTH);\r
1866                 }\r
1867                 if ((material.AntiAliasing & EAAM_POINT_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH))\r
1868                 {\r
1869                         if (material.AntiAliasing & EAAM_POINT_SMOOTH)\r
1870                                 // often in software, and thus very slow\r
1871                                 glEnable(GL_POINT_SMOOTH);\r
1872                         else if (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH)\r
1873                                 glDisable(GL_POINT_SMOOTH);\r
1874                 }\r
1875         }\r
1876 \r
1877         // Texture parameters\r
1878         setTextureRenderStates(material, resetAllRenderStates);\r
1879 }\r
1880 \r
1881 //! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call.\r
1882 void COGLES1Driver::setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates)\r
1883 {\r
1884         // Set textures to TU/TIU and apply filters to them\r
1885 \r
1886         for (s32 i = Feature.MaxTextureUnits - 1; i >= 0; --i)\r
1887         {\r
1888                 CacheHandler->getTextureCache().set(i, material.TextureLayer[i].Texture);\r
1889 \r
1890                 const COGLES1Texture* tmpTexture = CacheHandler->getTextureCache().get(i);\r
1891 \r
1892                 if (!tmpTexture)\r
1893                         continue;\r
1894 \r
1895                 GLenum tmpTextureType = tmpTexture->getOpenGLTextureType();\r
1896 \r
1897                 CacheHandler->setActiveTexture(GL_TEXTURE0 + i);\r
1898 \r
1899                 {\r
1900                         const bool isRTT = tmpTexture->isRenderTarget();\r
1901 \r
1902                         glMatrixMode(GL_TEXTURE);\r
1903 \r
1904                         if (!isRTT && Matrices[ETS_TEXTURE_0 + i].isIdentity())\r
1905                                 glLoadIdentity();\r
1906                         else\r
1907                         {\r
1908                                 GLfloat glmat[16];\r
1909                                 if (isRTT)\r
1910                                         getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i] * TextureFlipMatrix);\r
1911                                 else\r
1912                                         getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i]);\r
1913                                 glLoadMatrixf(glmat);\r
1914                         }\r
1915                 }\r
1916 \r
1917                 COGLES1Texture::SStatesCache& statesCache = tmpTexture->getStatesCache();\r
1918 \r
1919                 if (resetAllRenderstates)\r
1920                         statesCache.IsCached = false;\r
1921 \r
1922 #ifdef GL_VERSION_2_1\r
1923                 if (Version >= 210)\r
1924                 {\r
1925                         if (!statesCache.IsCached || material.TextureLayer[i].LODBias != statesCache.LODBias)\r
1926                         {\r
1927                                 if (material.TextureLayer[i].LODBias)\r
1928                                 {\r
1929                                         const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);\r
1930                                         glTexParameterf(tmpTextureType, GL_TEXTURE_LOD_BIAS, tmp);\r
1931                                 }\r
1932                                 else\r
1933                                         glTexParameterf(tmpTextureType, GL_TEXTURE_LOD_BIAS, 0.f);\r
1934 \r
1935                                 statesCache.LODBias = material.TextureLayer[i].LODBias;\r
1936                         }\r
1937                 }\r
1938                 else if (FeatureAvailable[IRR_EXT_texture_lod_bias])\r
1939                 {\r
1940                         if (material.TextureLayer[i].LODBias)\r
1941                         {\r
1942                                 const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);\r
1943                                 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp);\r
1944                         }\r
1945                         else\r
1946                                 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f);\r
1947                 }\r
1948 #elif defined(GL_EXT_texture_lod_bias)\r
1949                 if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_EXT_texture_lod_bias])\r
1950                 {\r
1951                         if (material.TextureLayer[i].LODBias)\r
1952                         {\r
1953                                 const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);\r
1954                                 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp);\r
1955                         }\r
1956                         else\r
1957                                 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f);\r
1958                 }\r
1959 #endif\r
1960 \r
1961                 if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||\r
1962                         material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter)\r
1963                 {\r
1964                         glTexParameteri(tmpTextureType, GL_TEXTURE_MAG_FILTER,\r
1965                                 (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);\r
1966 \r
1967                         statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
1968                         statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
1969                 }\r
1970 \r
1971                 if (material.UseMipMaps && tmpTexture->hasMipMaps())\r
1972                 {\r
1973                         if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||\r
1974                                 material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || !statesCache.MipMapStatus)\r
1975                         {\r
1976                                 glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,\r
1977                                         material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR :\r
1978                                         material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST :\r
1979                                         GL_NEAREST_MIPMAP_NEAREST);\r
1980 \r
1981                                 statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
1982                                 statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
1983                                 statesCache.MipMapStatus = true;\r
1984                         }\r
1985                 }\r
1986                 else\r
1987                 {\r
1988                         if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||\r
1989                                 material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || statesCache.MipMapStatus)\r
1990                         {\r
1991                                 glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,\r
1992                                         (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);\r
1993 \r
1994                                 statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
1995                                 statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
1996                                 statesCache.MipMapStatus = false;\r
1997                         }\r
1998                 }\r
1999 \r
2000 #ifdef GL_EXT_texture_filter_anisotropic\r
2001                 if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_EXT_texture_filter_anisotropic] &&\r
2002                         (!statesCache.IsCached || material.TextureLayer[i].AnisotropicFilter != statesCache.AnisotropicFilter))\r
2003                 {\r
2004                         glTexParameteri(tmpTextureType, GL_TEXTURE_MAX_ANISOTROPY_EXT,\r
2005                                 material.TextureLayer[i].AnisotropicFilter>1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1);\r
2006 \r
2007                         statesCache.AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter;\r
2008                 }\r
2009 #endif\r
2010 \r
2011                 if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapU != statesCache.WrapU)\r
2012                 {\r
2013                         glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU));\r
2014                         statesCache.WrapU = material.TextureLayer[i].TextureWrapU;\r
2015                 }\r
2016 \r
2017                 if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapV != statesCache.WrapV)\r
2018                 {\r
2019                         glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV));\r
2020                         statesCache.WrapV = material.TextureLayer[i].TextureWrapV;\r
2021                 }\r
2022 \r
2023                 statesCache.IsCached = true;\r
2024         }\r
2025 \r
2026         // be sure to leave in texture stage 0\r
2027         CacheHandler->setActiveTexture(GL_TEXTURE0);\r
2028 }\r
2029 \r
2030 \r
2031 //! sets the needed renderstates\r
2032 void COGLES1Driver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel)\r
2033 {\r
2034         if (CurrentRenderMode != ERM_2D || Transformation3DChanged)\r
2035         {\r
2036                 // unset last 3d material\r
2037                 if (CurrentRenderMode == ERM_3D)\r
2038                 {\r
2039                         if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())\r
2040                                 MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();\r
2041                 }\r
2042                 if (Transformation3DChanged)\r
2043                 {\r
2044                         glMatrixMode(GL_PROJECTION);\r
2045 \r
2046                         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
2047                         core::matrix4 m(core::matrix4::EM4CONST_NOTHING);\r
2048                         m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0f, 1.0f);\r
2049                         m.setTranslation(core::vector3df(-1, 1, 0));\r
2050                         glLoadMatrixf(m.pointer());\r
2051 \r
2052                         glMatrixMode(GL_MODELVIEW);\r
2053                         glLoadIdentity();\r
2054 \r
2055                         Transformation3DChanged = false;\r
2056                 }\r
2057         }\r
2058 \r
2059         Material = (OverrideMaterial2DEnabled) ? OverrideMaterial2D : InitMaterial2D;\r
2060         Material.Lighting = false;\r
2061         Material.TextureLayer[0].Texture = (texture) ? const_cast<COGLES1Texture*>(CacheHandler->getTextureCache().get(0)) : 0;\r
2062         setTransform(ETS_TEXTURE_0, core::IdentityMatrix);\r
2063 \r
2064         setBasicRenderStates(Material, LastMaterial, false);\r
2065 \r
2066         LastMaterial = Material;\r
2067         CacheHandler->correctCacheMaterial(LastMaterial);\r
2068 \r
2069         // no alphaChannel without texture\r
2070         alphaChannel &= texture;\r
2071 \r
2072         if (alphaChannel || alpha)\r
2073         {\r
2074                 CacheHandler->setBlend(true);\r
2075                 CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
2076                 glEnable(GL_ALPHA_TEST);\r
2077                 glAlphaFunc(GL_GREATER, 0.f);\r
2078         }\r
2079         else\r
2080         {\r
2081                 CacheHandler->setBlend(false);\r
2082                 glDisable(GL_ALPHA_TEST);\r
2083         }\r
2084 \r
2085         if (texture)\r
2086         {\r
2087                 // Due to the transformation change, the previous line would call a reset each frame\r
2088                 // but we can safely reset the variable as it was false before\r
2089                 Transformation3DChanged = false;\r
2090 \r
2091                 if (alphaChannel)\r
2092                 {\r
2093                         // if alpha and alpha texture just modulate, otherwise use only the alpha channel\r
2094                         if (alpha)\r
2095                         {\r
2096                                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
2097                         }\r
2098                         else\r
2099                         {\r
2100                                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);\r
2101                                 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);\r
2102                                 glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);\r
2103                                 // rgb always modulates\r
2104                                 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);\r
2105                                 glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);\r
2106                                 glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);\r
2107                         }\r
2108                 }\r
2109                 else\r
2110                 {\r
2111                         if (alpha)\r
2112                         {\r
2113                                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);\r
2114                                 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);\r
2115                                 glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR);\r
2116                                 // rgb always modulates\r
2117                                 glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);\r
2118                                 glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);\r
2119                                 glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);\r
2120                         }\r
2121                         else\r
2122                         {\r
2123                                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
2124                         }\r
2125                 }\r
2126         }\r
2127 \r
2128         CurrentRenderMode = ERM_2D;\r
2129 }\r
2130 \r
2131 \r
2132 //! \return Returns the name of the video driver.\r
2133 const wchar_t* COGLES1Driver::getName() const\r
2134 {\r
2135         return Name.c_str();\r
2136 }\r
2137 \r
2138 \r
2139 //! deletes all dynamic lights there are\r
2140 void COGLES1Driver::deleteAllDynamicLights()\r
2141 {\r
2142         for (s32 i=0; i<MaxLights; ++i)\r
2143                 glDisable(GL_LIGHT0 + i);\r
2144 \r
2145         RequestedLights.clear();\r
2146 \r
2147         CNullDriver::deleteAllDynamicLights();\r
2148 }\r
2149 \r
2150 \r
2151 //! adds a dynamic light\r
2152 s32 COGLES1Driver::addDynamicLight(const SLight& light)\r
2153 {\r
2154         CNullDriver::addDynamicLight(light);\r
2155 \r
2156         RequestedLights.push_back(RequestedLight(light));\r
2157 \r
2158         u32 newLightIndex = RequestedLights.size() - 1;\r
2159 \r
2160         // Try and assign a hardware light just now, but don't worry if I can't\r
2161         assignHardwareLight(newLightIndex);\r
2162 \r
2163         return (s32)newLightIndex;\r
2164 }\r
2165 \r
2166 \r
2167 void COGLES1Driver::assignHardwareLight(u32 lightIndex)\r
2168 {\r
2169         setTransform(ETS_WORLD, core::matrix4());\r
2170 \r
2171         s32 lidx;\r
2172         for (lidx=GL_LIGHT0; lidx < GL_LIGHT0 + MaxLights; ++lidx)\r
2173         {\r
2174                 if(!glIsEnabled(lidx))\r
2175                 {\r
2176                         RequestedLights[lightIndex].HardwareLightIndex = lidx;\r
2177                         break;\r
2178                 }\r
2179         }\r
2180 \r
2181         if(lidx == GL_LIGHT0 + MaxLights) // There's no room for it just now\r
2182                 return;\r
2183 \r
2184         GLfloat data[4];\r
2185         const SLight & light = RequestedLights[lightIndex].LightData;\r
2186 \r
2187         switch (light.Type)\r
2188         {\r
2189         case video::ELT_SPOT:\r
2190                 data[0] = light.Direction.X;\r
2191                 data[1] = light.Direction.Y;\r
2192                 data[2] = light.Direction.Z;\r
2193                 data[3] = 0.0f;\r
2194                 glLightfv(lidx, GL_SPOT_DIRECTION, data);\r
2195 \r
2196                 // set position\r
2197                 data[0] = light.Position.X;\r
2198                 data[1] = light.Position.Y;\r
2199                 data[2] = light.Position.Z;\r
2200                 data[3] = 1.0f; // 1.0f for positional light\r
2201                 glLightfv(lidx, GL_POSITION, data);\r
2202 \r
2203                 glLightf(lidx, GL_SPOT_EXPONENT, light.Falloff);\r
2204                 glLightf(lidx, GL_SPOT_CUTOFF, light.OuterCone);\r
2205         break;\r
2206         case video::ELT_POINT:\r
2207                 // set position\r
2208                 data[0] = light.Position.X;\r
2209                 data[1] = light.Position.Y;\r
2210                 data[2] = light.Position.Z;\r
2211                 data[3] = 1.0f; // 1.0f for positional light\r
2212                 glLightfv(lidx, GL_POSITION, data);\r
2213 \r
2214                 glLightf(lidx, GL_SPOT_EXPONENT, 0.0f);\r
2215                 glLightf(lidx, GL_SPOT_CUTOFF, 180.0f);\r
2216         break;\r
2217         case video::ELT_DIRECTIONAL:\r
2218                 // set direction\r
2219                 data[0] = -light.Direction.X;\r
2220                 data[1] = -light.Direction.Y;\r
2221                 data[2] = -light.Direction.Z;\r
2222                 data[3] = 0.0f; // 0.0f for directional light\r
2223                 glLightfv(lidx, GL_POSITION, data);\r
2224 \r
2225                 glLightf(lidx, GL_SPOT_EXPONENT, 0.0f);\r
2226                 glLightf(lidx, GL_SPOT_CUTOFF, 180.0f);\r
2227         break;\r
2228         case video::ELT_COUNT:\r
2229                 return;\r
2230         }\r
2231 \r
2232         // set diffuse color\r
2233         data[0] = light.DiffuseColor.r;\r
2234         data[1] = light.DiffuseColor.g;\r
2235         data[2] = light.DiffuseColor.b;\r
2236         data[3] = light.DiffuseColor.a;\r
2237         glLightfv(lidx, GL_DIFFUSE, data);\r
2238 \r
2239         // set specular color\r
2240         data[0] = light.SpecularColor.r;\r
2241         data[1] = light.SpecularColor.g;\r
2242         data[2] = light.SpecularColor.b;\r
2243         data[3] = light.SpecularColor.a;\r
2244         glLightfv(lidx, GL_SPECULAR, data);\r
2245 \r
2246         // set ambient color\r
2247         data[0] = light.AmbientColor.r;\r
2248         data[1] = light.AmbientColor.g;\r
2249         data[2] = light.AmbientColor.b;\r
2250         data[3] = light.AmbientColor.a;\r
2251         glLightfv(lidx, GL_AMBIENT, data);\r
2252 \r
2253         // 1.0f / (constant + linear * d + quadratic*(d*d);\r
2254 \r
2255         // set attenuation\r
2256         glLightf(lidx, GL_CONSTANT_ATTENUATION, light.Attenuation.X);\r
2257         glLightf(lidx, GL_LINEAR_ATTENUATION, light.Attenuation.Y);\r
2258         glLightf(lidx, GL_QUADRATIC_ATTENUATION, light.Attenuation.Z);\r
2259 \r
2260         glEnable(lidx);\r
2261 }\r
2262 \r
2263 \r
2264 //! Turns a dynamic light on or off\r
2265 //! \param lightIndex: the index returned by addDynamicLight\r
2266 //! \param turnOn: true to turn the light on, false to turn it off\r
2267 void COGLES1Driver::turnLightOn(s32 lightIndex, bool turnOn)\r
2268 {\r
2269         if(lightIndex < 0 || lightIndex >= (s32)RequestedLights.size())\r
2270                 return;\r
2271 \r
2272         RequestedLight & requestedLight = RequestedLights[lightIndex];\r
2273 \r
2274         requestedLight.DesireToBeOn = turnOn;\r
2275 \r
2276         if(turnOn)\r
2277         {\r
2278                 if(-1 == requestedLight.HardwareLightIndex)\r
2279                         assignHardwareLight(lightIndex);\r
2280         }\r
2281         else\r
2282         {\r
2283                 if(-1 != requestedLight.HardwareLightIndex)\r
2284                 {\r
2285                         // It's currently assigned, so free up the hardware light\r
2286                         glDisable(requestedLight.HardwareLightIndex);\r
2287                         requestedLight.HardwareLightIndex = -1;\r
2288 \r
2289                         // Now let the first light that's waiting on a free hardware light grab it\r
2290                         for(u32 requested = 0; requested < RequestedLights.size(); ++requested)\r
2291                                 if(RequestedLights[requested].DesireToBeOn\r
2292                                         &&\r
2293                                         -1 == RequestedLights[requested].HardwareLightIndex)\r
2294                                 {\r
2295                                         assignHardwareLight(requested);\r
2296                                         break;\r
2297                                 }\r
2298                 }\r
2299         }\r
2300 }\r
2301 \r
2302 \r
2303 //! returns the maximal amount of dynamic lights the device can handle\r
2304 u32 COGLES1Driver::getMaximalDynamicLightAmount() const\r
2305 {\r
2306         return MaxLights;\r
2307 }\r
2308 \r
2309 \r
2310 //! Sets the dynamic ambient light color.\r
2311 void COGLES1Driver::setAmbientLight(const SColorf& color)\r
2312 {\r
2313         CNullDriver::setAmbientLight(color);\r
2314         GLfloat data[4] = {color.r, color.g, color.b, color.a};\r
2315         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, data);\r
2316 }\r
2317 \r
2318 \r
2319 // this code was sent in by Oliver Klems, thank you\r
2320 void COGLES1Driver::setViewPort(const core::rect<s32>& area)\r
2321 {\r
2322         core::rect<s32> vp = area;\r
2323         core::rect<s32> rendert(0, 0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height);\r
2324         vp.clipAgainst(rendert);\r
2325 \r
2326         if (vp.getHeight() > 0 && vp.getWidth() > 0)\r
2327                 CacheHandler->setViewport(vp.UpperLeftCorner.X, getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), vp.getWidth(), vp.getHeight());\r
2328 \r
2329         ViewPort = vp;\r
2330 }\r
2331 \r
2332 \r
2333 void COGLES1Driver::setViewPortRaw(u32 width, u32 height)\r
2334 {\r
2335         CacheHandler->setViewport(0, 0, width, height);\r
2336         ViewPort = core::recti(0, 0, width, height);\r
2337 }\r
2338 \r
2339 \r
2340 //! Draws a shadow volume into the stencil buffer.\r
2341 void COGLES1Driver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)\r
2342 {\r
2343         const u32 count=triangles.size();\r
2344         if (!StencilBuffer || !count)\r
2345                 return;\r
2346 \r
2347         u8 colorMask = LastMaterial.ColorMask;\r
2348         const GLboolean lightingEnabled = glIsEnabled(GL_LIGHTING);\r
2349         const GLboolean fogEnabled = glIsEnabled(GL_FOG);\r
2350         const GLboolean cullFaceEnabled = glIsEnabled(GL_CULL_FACE);\r
2351 \r
2352         GLint cullFaceMode = 0;\r
2353         glGetIntegerv(GL_CULL_FACE_MODE, &cullFaceMode);\r
2354         GLint depthFunc = 0;\r
2355         glGetIntegerv(GL_DEPTH_FUNC, &depthFunc);\r
2356         GLboolean depthMask = 0;\r
2357         glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask);\r
2358 \r
2359         glDisable(GL_LIGHTING);\r
2360         glDisable(GL_FOG);\r
2361         glDepthFunc(GL_LEQUAL);\r
2362         glDepthMask(GL_FALSE);\r
2363 \r
2364         if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY)))\r
2365         {\r
2366                 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);\r
2367                 glEnable(GL_STENCIL_TEST);\r
2368         }\r
2369 \r
2370         glEnableClientState(GL_VERTEX_ARRAY);\r
2371         glVertexPointer(3, GL_FLOAT, sizeof(core::vector3df), triangles.const_pointer());\r
2372 \r
2373         glStencilMask(~0);\r
2374         glStencilFunc(GL_ALWAYS, 0, ~0);\r
2375 \r
2376         GLenum decr = GL_DECR;\r
2377         GLenum incr = GL_INCR;\r
2378 \r
2379 #if defined(GL_OES_stencil_wrap)\r
2380         if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_stencil_wrap])\r
2381         {\r
2382                 decr = GL_DECR_WRAP_OES;\r
2383                 incr = GL_INCR_WRAP_OES;\r
2384         }\r
2385 #endif\r
2386 \r
2387         glEnable(GL_CULL_FACE);\r
2388 \r
2389         if (zfail)\r
2390         {\r
2391                 glCullFace(GL_FRONT);\r
2392                 glStencilOp(GL_KEEP, incr, GL_KEEP);\r
2393                 glDrawArrays(GL_TRIANGLES, 0, count);\r
2394 \r
2395                 glCullFace(GL_BACK);\r
2396                 glStencilOp(GL_KEEP, decr, GL_KEEP);\r
2397                 glDrawArrays(GL_TRIANGLES, 0, count);\r
2398         }\r
2399         else // zpass\r
2400         {\r
2401                 glCullFace(GL_BACK);\r
2402                 glStencilOp(GL_KEEP, GL_KEEP, incr);\r
2403                 glDrawArrays(GL_TRIANGLES, 0, count);\r
2404 \r
2405                 glCullFace(GL_FRONT);\r
2406                 glStencilOp(GL_KEEP, GL_KEEP, decr);\r
2407                 glDrawArrays(GL_TRIANGLES, 0, count);\r
2408         }\r
2409 \r
2410         glDisableClientState(GL_VERTEX_ARRAY);\r
2411 \r
2412         glColorMask((colorMask & ECP_RED)?GL_TRUE:GL_FALSE,\r
2413                         (colorMask & ECP_GREEN)?GL_TRUE:GL_FALSE,\r
2414                         (colorMask & ECP_BLUE)?GL_TRUE:GL_FALSE,\r
2415                         (colorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE);\r
2416 \r
2417         glDisable(GL_STENCIL_TEST);\r
2418 \r
2419         if (lightingEnabled)\r
2420                 glEnable(GL_LIGHTING);\r
2421 \r
2422         if (fogEnabled)\r
2423                 glEnable(GL_FOG);\r
2424 \r
2425         if (cullFaceEnabled)\r
2426                 glEnable(GL_CULL_FACE);\r
2427         else\r
2428                 glDisable(GL_CULL_FACE);\r
2429 \r
2430         glCullFace(cullFaceMode);\r
2431         glDepthFunc(depthFunc);\r
2432         glDepthMask(depthMask);\r
2433 }\r
2434 \r
2435 \r
2436 void COGLES1Driver::drawStencilShadow(bool clearStencilBuffer,\r
2437                 video::SColor leftUpEdge, video::SColor rightUpEdge,\r
2438                 video::SColor leftDownEdge, video::SColor rightDownEdge)\r
2439 {\r
2440         if (!StencilBuffer)\r
2441                 return;\r
2442 \r
2443         setTextureRenderStates(SMaterial(), false);\r
2444 \r
2445         u8 colorMask = LastMaterial.ColorMask;\r
2446         const GLboolean lightingEnabled = glIsEnabled(GL_LIGHTING);\r
2447         const GLboolean fogEnabled = glIsEnabled(GL_FOG);\r
2448         const GLboolean blendEnabled = glIsEnabled(GL_BLEND);\r
2449 \r
2450         GLboolean depthMask = 0;\r
2451         glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask);\r
2452         GLint shadeModel = 0;\r
2453         glGetIntegerv(GL_SHADE_MODEL, &shadeModel);\r
2454         GLint blendSrc = 0, blendDst = 0;\r
2455         glGetIntegerv(GL_BLEND_SRC, &blendSrc);\r
2456         glGetIntegerv(GL_BLEND_DST, &blendDst);\r
2457 \r
2458         glDisable(GL_LIGHTING);\r
2459         glDisable(GL_FOG);\r
2460         glDepthMask(GL_FALSE);\r
2461 \r
2462         glShadeModel(GL_FLAT);\r
2463         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);\r
2464 \r
2465         glEnable(GL_BLEND);\r
2466         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
2467 \r
2468         glEnable(GL_STENCIL_TEST);\r
2469         glStencilFunc(GL_NOTEQUAL, 0, ~0);\r
2470         glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);\r
2471 \r
2472         glMatrixMode(GL_MODELVIEW);\r
2473         glPushMatrix();\r
2474         glLoadIdentity();\r
2475         glMatrixMode(GL_PROJECTION);\r
2476         glPushMatrix();\r
2477         glLoadIdentity();\r
2478 \r
2479         u16 indices[] = {0, 1, 2, 3};\r
2480         S3DVertex vertices[4];\r
2481         vertices[0] = S3DVertex(-1.f, 1.f, 0.9f, 0, 0, 1, leftDownEdge, 0, 0);\r
2482         vertices[1] = S3DVertex(1.f, 1.f, 0.9f, 0, 0, 1, leftUpEdge, 0, 0);\r
2483         vertices[2] = S3DVertex(1.f, -1.f, 0.9f, 0, 0, 1, rightUpEdge, 0, 0);\r
2484         vertices[3] = S3DVertex(-1.f, -1.f, 0.9f, 0, 0, 1, rightDownEdge, 0, 0);\r
2485         drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false);\r
2486 \r
2487         if (clearStencilBuffer)\r
2488                 glClear(GL_STENCIL_BUFFER_BIT);\r
2489 \r
2490         glColorMask((colorMask & ECP_RED)?GL_TRUE:GL_FALSE,\r
2491                         (colorMask & ECP_GREEN)?GL_TRUE:GL_FALSE,\r
2492                         (colorMask & ECP_BLUE)?GL_TRUE:GL_FALSE,\r
2493                         (colorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE);\r
2494 \r
2495         glDisable(GL_STENCIL_TEST);\r
2496 \r
2497         glPopMatrix();\r
2498         glMatrixMode(GL_MODELVIEW);\r
2499         glPopMatrix();\r
2500 \r
2501         if (lightingEnabled)\r
2502                 glEnable(GL_LIGHTING);\r
2503 \r
2504         if (fogEnabled)\r
2505                 glEnable(GL_FOG);\r
2506 \r
2507         if (!blendEnabled)\r
2508                 glDisable(GL_BLEND);\r
2509 \r
2510         glDepthMask(depthMask);\r
2511         glShadeModel(shadeModel);\r
2512         glBlendFunc(blendSrc, blendDst);\r
2513 }\r
2514 \r
2515 \r
2516 //! Sets the fog mode.\r
2517 void COGLES1Driver::setFog(SColor c, E_FOG_TYPE fogType, f32 start,\r
2518                         f32 end, f32 density, bool pixelFog, bool rangeFog)\r
2519 {\r
2520         CNullDriver::setFog(c, fogType, start, end, density, pixelFog, rangeFog);\r
2521 \r
2522         glFogf(GL_FOG_MODE, GLfloat((fogType==EFT_FOG_LINEAR)? GL_LINEAR : (fogType==EFT_FOG_EXP)?GL_EXP:GL_EXP2));\r
2523 \r
2524 #ifdef GL_EXT_fog_coord\r
2525         if (FeatureAvailable[IRR_EXT_fog_coord])\r
2526                 glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH);\r
2527 #endif\r
2528 \r
2529         if (fogType==EFT_FOG_LINEAR)\r
2530         {\r
2531                 glFogf(GL_FOG_START, start);\r
2532                 glFogf(GL_FOG_END, end);\r
2533         }\r
2534         else\r
2535                 glFogf(GL_FOG_DENSITY, density);\r
2536 \r
2537         if (pixelFog)\r
2538                 glHint(GL_FOG_HINT, GL_NICEST);\r
2539         else\r
2540                 glHint(GL_FOG_HINT, GL_FASTEST);\r
2541 \r
2542         SColorf color(c);\r
2543         GLfloat data[4] = {color.r, color.g, color.b, color.a};\r
2544         glFogfv(GL_FOG_COLOR, data);\r
2545 }\r
2546 \r
2547 \r
2548 //! Draws a 3d line.\r
2549 void COGLES1Driver::draw3DLine(const core::vector3df& start,\r
2550                                 const core::vector3df& end, SColor color)\r
2551 {\r
2552         setRenderStates3DMode();\r
2553 \r
2554         u16 indices[] = {0,1};\r
2555         S3DVertex vertices[2];\r
2556         vertices[0] = S3DVertex(start.X,start.Y,start.Z, 0,0,1, color, 0,0);\r
2557         vertices[1] = S3DVertex(end.X,end.Y,end.Z, 0,0,1, color, 0,0);\r
2558         drawVertexPrimitiveList2d3d(vertices, 2, indices, 1, video::EVT_STANDARD, scene::EPT_LINES);\r
2559 }\r
2560 \r
2561 \r
2562 //! Only used by the internal engine. Used to notify the driver that\r
2563 //! the window was resized.\r
2564 void COGLES1Driver::OnResize(const core::dimension2d<u32>& size)\r
2565 {\r
2566         CNullDriver::OnResize(size);\r
2567         CacheHandler->setViewport(0, 0, size.Width, size.Height);\r
2568         Transformation3DChanged = true;\r
2569 }\r
2570 \r
2571 \r
2572 //! Returns type of video driver\r
2573 E_DRIVER_TYPE COGLES1Driver::getDriverType() const\r
2574 {\r
2575         return EDT_OGLES1;\r
2576 }\r
2577 \r
2578 \r
2579 //! returns color format\r
2580 ECOLOR_FORMAT COGLES1Driver::getColorFormat() const\r
2581 {\r
2582         return ColorFormat;\r
2583 }\r
2584 \r
2585 \r
2586 //! Get a vertex shader constant index.\r
2587 s32 COGLES1Driver::getVertexShaderConstantID(const c8* name)\r
2588 {\r
2589         return getPixelShaderConstantID(name);\r
2590 }\r
2591 \r
2592 //! Get a pixel shader constant index.\r
2593 s32 COGLES1Driver::getPixelShaderConstantID(const c8* name)\r
2594 {\r
2595         os::Printer::log("Error: Please use IMaterialRendererServices from IShaderConstantSetCallBack::OnSetConstants not VideoDriver->getPixelShaderConstantID().");\r
2596         return -1;\r
2597 }\r
2598 \r
2599 //! Sets a constant for the vertex shader based on an index.\r
2600 bool COGLES1Driver::setVertexShaderConstant(s32 index, const f32* floats, int count)\r
2601 {\r
2602         //pass this along, as in GLSL the same routine is used for both vertex and fragment shaders\r
2603         return setPixelShaderConstant(index, floats, count);\r
2604 }\r
2605 \r
2606 //! Int interface for the above.\r
2607 bool COGLES1Driver::setVertexShaderConstant(s32 index, const s32* ints, int count)\r
2608 {\r
2609         return setPixelShaderConstant(index, ints, count);\r
2610 }\r
2611 \r
2612 bool COGLES1Driver::setVertexShaderConstant(s32 index, const u32* ints, int count)\r
2613 {\r
2614         return setPixelShaderConstant(index, ints, count);\r
2615 }\r
2616 \r
2617 //! Sets a constant for the pixel shader based on an index.\r
2618 bool COGLES1Driver::setPixelShaderConstant(s32 index, const f32* floats, int count)\r
2619 {\r
2620         os::Printer::log("Error: Please use IMaterialRendererServices from IShaderConstantSetCallBack::OnSetConstants not VideoDriver->setPixelShaderConstant().");\r
2621         return false;\r
2622 }\r
2623 \r
2624 //! Int interface for the above.\r
2625 bool COGLES1Driver::setPixelShaderConstant(s32 index, const s32* ints, int count)\r
2626 {\r
2627         os::Printer::log("Error: Please use IMaterialRendererServices from IShaderConstantSetCallBack::OnSetConstants not VideoDriver->setPixelShaderConstant().");\r
2628         return false;\r
2629 }\r
2630 \r
2631 bool COGLES1Driver::setPixelShaderConstant(s32 index, const u32* ints, int count)\r
2632 {\r
2633         os::Printer::log("Error: Please use IMaterialRendererServices from IShaderConstantSetCallBack::OnSetConstants not VideoDriver->setPixelShaderConstant().");\r
2634         return false;\r
2635 }\r
2636 \r
2637 //! Sets a vertex shader constant.\r
2638 void COGLES1Driver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)\r
2639 {\r
2640 #ifdef GL_vertex_program\r
2641         for (s32 i=0; i<constantAmount; ++i)\r
2642                 extGlProgramLocalParameter4fv(GL_VERTEX_PROGRAM, startRegister+i, &data[i*4]);\r
2643 #endif\r
2644 }\r
2645 \r
2646 //! Sets a pixel shader constant.\r
2647 void COGLES1Driver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)\r
2648 {\r
2649 #ifdef GL_fragment_program\r
2650         for (s32 i=0; i<constantAmount; ++i)\r
2651                 extGlProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM, startRegister+i, &data[i*4]);\r
2652 #endif\r
2653 }\r
2654 \r
2655 \r
2656 //! Adds a new material renderer to the VideoDriver, using pixel and/or\r
2657 //! vertex shaders to render geometry.\r
2658 s32 COGLES1Driver::addShaderMaterial(const c8* vertexShaderProgram,\r
2659         const c8* pixelShaderProgram,\r
2660         IShaderConstantSetCallBack* callback,\r
2661         E_MATERIAL_TYPE baseMaterial, s32 userData)\r
2662 {\r
2663         os::Printer::log("No shader support.");\r
2664         return -1;\r
2665 }\r
2666 \r
2667 \r
2668 //! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.\r
2669 s32 COGLES1Driver::addHighLevelShaderMaterial(\r
2670         const c8* vertexShaderProgram,\r
2671         const c8* vertexShaderEntryPointName,\r
2672         E_VERTEX_SHADER_TYPE vsCompileTarget,\r
2673         const c8* pixelShaderProgram,\r
2674         const c8* pixelShaderEntryPointName,\r
2675         E_PIXEL_SHADER_TYPE psCompileTarget,\r
2676         const c8* geometryShaderProgram,\r
2677         const c8* geometryShaderEntryPointName,\r
2678         E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
2679         scene::E_PRIMITIVE_TYPE inType,\r
2680         scene::E_PRIMITIVE_TYPE outType,\r
2681         u32 verticesOut,\r
2682         IShaderConstantSetCallBack* callback,\r
2683         E_MATERIAL_TYPE baseMaterial,\r
2684         s32 userData)\r
2685 {\r
2686         os::Printer::log("No shader support.");\r
2687         return -1;\r
2688 }\r
2689 \r
2690 //! Returns a pointer to the IVideoDriver interface. (Implementation for\r
2691 //! IMaterialRendererServices)\r
2692 IVideoDriver* COGLES1Driver::getVideoDriver()\r
2693 {\r
2694         return this;\r
2695 }\r
2696 \r
2697 \r
2698 //! Returns pointer to the IGPUProgrammingServices interface.\r
2699 IGPUProgrammingServices* COGLES1Driver::getGPUProgrammingServices()\r
2700 {\r
2701         return this;\r
2702 }\r
2703 \r
2704 \r
2705 ITexture* COGLES1Driver::addRenderTargetTexture(const core::dimension2d<u32>& size,\r
2706         const io::path& name, const ECOLOR_FORMAT format)\r
2707 {\r
2708         //disable mip-mapping\r
2709         bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);\r
2710         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);\r
2711 \r
2712         bool supportForFBO = (Feature.ColorAttachment > 0);\r
2713 \r
2714         core::dimension2du destSize(size);\r
2715 \r
2716         if (!supportForFBO)\r
2717         {\r
2718                 destSize = core::dimension2d<u32>(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height));\r
2719                 destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false);\r
2720         }\r
2721 \r
2722         COGLES1Texture* renderTargetTexture = new COGLES1Texture(name, destSize, ETT_2D, format, this);\r
2723         addTexture(renderTargetTexture);\r
2724         renderTargetTexture->drop();\r
2725 \r
2726         //restore mip-mapping\r
2727         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);\r
2728 \r
2729         return renderTargetTexture;\r
2730 }\r
2731 \r
2732 ITexture* COGLES1Driver::addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path& name, const ECOLOR_FORMAT format)\r
2733 {\r
2734         //disable mip-mapping\r
2735         bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);\r
2736         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);\r
2737 \r
2738         bool supportForFBO = (Feature.ColorAttachment > 0);\r
2739 \r
2740         const core::dimension2d<u32> size(sideLen, sideLen);\r
2741         core::dimension2du destSize(size);\r
2742 \r
2743         if (!supportForFBO)\r
2744         {\r
2745                 destSize = core::dimension2d<u32>(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height));\r
2746                 destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false);\r
2747         }\r
2748 \r
2749         COGLES1Texture* renderTargetTexture = new COGLES1Texture(name, destSize, ETT_CUBEMAP, format, this);\r
2750         addTexture(renderTargetTexture);\r
2751         renderTargetTexture->drop();\r
2752 \r
2753         //restore mip-mapping\r
2754         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);\r
2755 \r
2756         return renderTargetTexture;\r
2757 }\r
2758 \r
2759 //! Returns the maximum amount of primitives\r
2760 u32 COGLES1Driver::getMaximalPrimitiveCount() const\r
2761 {\r
2762         return 65535;\r
2763 }\r
2764 \r
2765 bool COGLES1Driver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)\r
2766 {\r
2767         if (target && target->getDriverType() != EDT_OGLES1)\r
2768         {\r
2769                 os::Printer::log("Fatal Error: Tried to set a render target not owned by OpenGL driver.", ELL_ERROR);\r
2770                 return false;\r
2771         }\r
2772 \r
2773         bool supportForFBO = (Feature.ColorAttachment > 0);\r
2774 \r
2775         core::dimension2d<u32> destRenderTargetSize(0, 0);\r
2776 \r
2777         if (target)\r
2778         {\r
2779                 COGLES1RenderTarget* renderTarget = static_cast<COGLES1RenderTarget*>(target);\r
2780 \r
2781                 if (supportForFBO)\r
2782                 {\r
2783                         CacheHandler->setFBO(renderTarget->getBufferID());\r
2784                         renderTarget->update();\r
2785                 }\r
2786 \r
2787                 destRenderTargetSize = renderTarget->getSize();\r
2788 \r
2789                 setViewPortRaw(destRenderTargetSize.Width, destRenderTargetSize.Height);\r
2790         }\r
2791         else\r
2792         {\r
2793                 if (supportForFBO)\r
2794                         CacheHandler->setFBO(0);\r
2795                 else\r
2796                 {\r
2797                         COGLES1RenderTarget* prevRenderTarget = static_cast<COGLES1RenderTarget*>(CurrentRenderTarget);\r
2798                         COGLES1Texture* renderTargetTexture = static_cast<COGLES1Texture*>(prevRenderTarget->getTexture());\r
2799 \r
2800                         if (renderTargetTexture)\r
2801                         {\r
2802                                 const COGLES1Texture* prevTexture = CacheHandler->getTextureCache().get(0);\r
2803 \r
2804                                 CacheHandler->getTextureCache().set(0, renderTargetTexture);\r
2805 \r
2806                                 const core::dimension2d<u32> size = renderTargetTexture->getSize();\r
2807                                 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size.Width, size.Height);\r
2808 \r
2809                                 CacheHandler->getTextureCache().set(0, prevTexture);\r
2810                         }\r
2811                 }\r
2812 \r
2813                 destRenderTargetSize = core::dimension2d<u32>(0, 0);\r
2814 \r
2815                 setViewPortRaw(ScreenSize.Width, ScreenSize.Height);\r
2816         }\r
2817 \r
2818         if (CurrentRenderTargetSize != destRenderTargetSize)\r
2819         {\r
2820                 CurrentRenderTargetSize = destRenderTargetSize;\r
2821 \r
2822                 Transformation3DChanged = true;\r
2823         }\r
2824 \r
2825         CurrentRenderTarget = target;\r
2826 \r
2827         if (!supportForFBO)\r
2828         {\r
2829                 clearFlag |= ECBF_COLOR;\r
2830                 clearFlag |= ECBF_DEPTH;\r
2831         }\r
2832 \r
2833         clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);\r
2834 \r
2835         return true;\r
2836 }\r
2837 \r
2838 void COGLES1Driver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)\r
2839 {\r
2840         GLbitfield mask = 0;\r
2841 \r
2842         if (flag & ECBF_COLOR)\r
2843         {\r
2844                 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);\r
2845 \r
2846                 const f32 inv = 1.0f / 255.0f;\r
2847                 glClearColor(color.getRed() * inv, color.getGreen() * inv,\r
2848                         color.getBlue() * inv, color.getAlpha() * inv);\r
2849 \r
2850                 mask |= GL_COLOR_BUFFER_BIT;\r
2851         }\r
2852 \r
2853         if (flag & ECBF_DEPTH)\r
2854         {\r
2855                 glDepthMask(GL_TRUE);\r
2856                 glClearDepthf(depth);\r
2857                 mask |= GL_DEPTH_BUFFER_BIT;\r
2858         }\r
2859 \r
2860         if (flag & ECBF_STENCIL)\r
2861         {\r
2862                 glClearStencil(stencil);\r
2863                 mask |= GL_STENCIL_BUFFER_BIT;\r
2864         }\r
2865 \r
2866         if (mask)\r
2867                 glClear(mask);\r
2868 }\r
2869 \r
2870 \r
2871 //! Returns an image created from the last rendered frame.\r
2872 // We want to read the front buffer to get the latest render finished.\r
2873 // This is not possible under ogl-es, though, so one has to call this method\r
2874 // outside of the render loop only.\r
2875 IImage* COGLES1Driver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)\r
2876 {\r
2877         if (target==video::ERT_MULTI_RENDER_TEXTURES || target==video::ERT_RENDER_TEXTURE || target==video::ERT_STEREO_BOTH_BUFFERS)\r
2878                 return 0;\r
2879         GLint internalformat=GL_RGBA;\r
2880         GLint type=GL_UNSIGNED_BYTE;\r
2881         if (false\r
2882                 && (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_IMG_read_format]\r
2883                         || FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_read_format]\r
2884                         || FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_EXT_read_format_bgra]))\r
2885         {\r
2886 #ifdef GL_IMPLEMENTATION_COLOR_READ_TYPE_OES\r
2887                 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &internalformat);\r
2888                 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &type);\r
2889 #endif\r
2890                 // there are formats we don't support ATM\r
2891                 if (GL_UNSIGNED_SHORT_4_4_4_4==type)\r
2892                         type=GL_UNSIGNED_SHORT_5_5_5_1;\r
2893 #ifdef GL_EXT_read_format_bgra\r
2894                 else if (GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT==type)\r
2895                         type=GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT;\r
2896 #endif\r
2897         }\r
2898 \r
2899         IImage* newImage = 0;\r
2900         if ((GL_RGBA==internalformat)\r
2901 #ifdef GL_EXT_read_format_bgra\r
2902                         || (GL_BGRA_EXT==internalformat)\r
2903 #endif\r
2904                         )\r
2905         {\r
2906                 if (GL_UNSIGNED_BYTE==type)\r
2907                         newImage = new CImage(ECF_A8R8G8B8, ScreenSize);\r
2908                 else\r
2909                         newImage = new CImage(ECF_A1R5G5B5, ScreenSize);\r
2910         }\r
2911         else\r
2912         {\r
2913                 if (GL_UNSIGNED_BYTE==type)\r
2914                         newImage = new CImage(ECF_R8G8B8, ScreenSize);\r
2915                 else\r
2916                         newImage = new CImage(ECF_R5G6B5, ScreenSize);\r
2917         }\r
2918 \r
2919         u8* pixels = static_cast<u8*>(newImage->getData());\r
2920         if (!pixels)\r
2921         {\r
2922                 newImage->drop();\r
2923                 return 0;\r
2924         }\r
2925 \r
2926         glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, internalformat, type, pixels);\r
2927 \r
2928         // opengl images are horizontally flipped, so we have to fix that here.\r
2929         const s32 pitch=newImage->getPitch();\r
2930         u8* p2 = pixels + (ScreenSize.Height - 1) * pitch;\r
2931         u8* tmpBuffer = new u8[pitch];\r
2932         for (u32 i=0; i < ScreenSize.Height; i += 2)\r
2933         {\r
2934                 memcpy(tmpBuffer, pixels, pitch);\r
2935                 memcpy(pixels, p2, pitch);\r
2936                 memcpy(p2, tmpBuffer, pitch);\r
2937                 pixels += pitch;\r
2938                 p2 -= pitch;\r
2939         }\r
2940         delete [] tmpBuffer;\r
2941 \r
2942         if (testGLError(__LINE__))\r
2943         {\r
2944                 newImage->drop();\r
2945                 return 0;\r
2946         }\r
2947 \r
2948         return newImage;\r
2949 }\r
2950 \r
2951 void COGLES1Driver::removeTexture(ITexture* texture)\r
2952 {\r
2953         CacheHandler->getTextureCache().remove(texture);\r
2954         CNullDriver::removeTexture(texture);\r
2955 }\r
2956 \r
2957 \r
2958 //! Set/unset a clipping plane.\r
2959 bool COGLES1Driver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)\r
2960 {\r
2961         if (index >= MaxUserClipPlanes)\r
2962                 return false;\r
2963 \r
2964         UserClipPlane[index]=plane;\r
2965         enableClipPlane(index, enable);\r
2966         return true;\r
2967 }\r
2968 \r
2969 \r
2970 void COGLES1Driver::uploadClipPlane(u32 index)\r
2971 {\r
2972         // opengl needs an array of doubles for the plane equation\r
2973         float clip_plane[4];\r
2974         clip_plane[0] = UserClipPlane[index].Normal.X;\r
2975         clip_plane[1] = UserClipPlane[index].Normal.Y;\r
2976         clip_plane[2] = UserClipPlane[index].Normal.Z;\r
2977         clip_plane[3] = UserClipPlane[index].D;\r
2978         glClipPlanef(GL_CLIP_PLANE0 + index, clip_plane);\r
2979 }\r
2980 \r
2981 \r
2982 //! Enable/disable a clipping plane.\r
2983 void COGLES1Driver::enableClipPlane(u32 index, bool enable)\r
2984 {\r
2985         if (index >= MaxUserClipPlanes)\r
2986                 return;\r
2987         if (enable)\r
2988         {\r
2989                 if (!UserClipPlaneEnabled[index])\r
2990                 {\r
2991                         uploadClipPlane(index);\r
2992                         glEnable(GL_CLIP_PLANE0 + index);\r
2993                 }\r
2994         }\r
2995         else\r
2996                 glDisable(GL_CLIP_PLANE0 + index);\r
2997 \r
2998         UserClipPlaneEnabled[index]=enable;\r
2999 }\r
3000 \r
3001 \r
3002 core::dimension2du COGLES1Driver::getMaxTextureSize() const\r
3003 {\r
3004         return core::dimension2du(MaxTextureSize, MaxTextureSize);\r
3005 }\r
3006 \r
3007 \r
3008 GLenum COGLES1Driver::getGLBlend(E_BLEND_FACTOR factor) const\r
3009 {\r
3010         static GLenum const blendTable[] =\r
3011         {\r
3012                 GL_ZERO,\r
3013                 GL_ONE,\r
3014                 GL_DST_COLOR,\r
3015                 GL_ONE_MINUS_DST_COLOR,\r
3016                 GL_SRC_COLOR,\r
3017                 GL_ONE_MINUS_SRC_COLOR,\r
3018                 GL_SRC_ALPHA,\r
3019                 GL_ONE_MINUS_SRC_ALPHA,\r
3020                 GL_DST_ALPHA,\r
3021                 GL_ONE_MINUS_DST_ALPHA,\r
3022                 GL_SRC_ALPHA_SATURATE\r
3023         };\r
3024 \r
3025         return blendTable[factor];\r
3026 }\r
3027 \r
3028 GLenum COGLES1Driver::getZBufferBits() const\r
3029 {\r
3030         GLenum bits = 0;\r
3031 \r
3032         switch (Params.ZBufferBits)\r
3033         {\r
3034         case 24:\r
3035 #if defined(GL_OES_depth24)\r
3036                 if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth24))\r
3037                         bits = GL_DEPTH_COMPONENT24_OES;\r
3038                 else\r
3039 #endif\r
3040                         bits = GL_DEPTH_COMPONENT16;\r
3041                 break;\r
3042         case 32:\r
3043 #if defined(GL_OES_depth32)\r
3044                 if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth32))\r
3045                         bits = GL_DEPTH_COMPONENT32_OES;\r
3046                 else\r
3047 #endif\r
3048                         bits = GL_DEPTH_COMPONENT16;\r
3049                 break;\r
3050         default:\r
3051                 bits = GL_DEPTH_COMPONENT16;\r
3052                 break;\r
3053         }\r
3054 \r
3055         return bits;\r
3056 }\r
3057 \r
3058 bool COGLES1Driver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat,\r
3059         GLenum& pixelType, void(**converter)(const void*, s32, void*)) const\r
3060 {\r
3061         bool supported = false;\r
3062         internalFormat = GL_RGBA;\r
3063         pixelFormat = GL_RGBA;\r
3064         pixelType = GL_UNSIGNED_BYTE;\r
3065         *converter = 0;\r
3066 \r
3067         switch (format)\r
3068         {\r
3069         case ECF_A1R5G5B5:\r
3070                 supported = true;\r
3071                 internalFormat = GL_RGBA;\r
3072                 pixelFormat = GL_RGBA;\r
3073                 pixelType = GL_UNSIGNED_SHORT_5_5_5_1;\r
3074                 *converter = CColorConverter::convert_A1R5G5B5toR5G5B5A1;\r
3075                 break;\r
3076         case ECF_R5G6B5:\r
3077                 supported = true;\r
3078                 internalFormat = GL_RGB;\r
3079                 pixelFormat = GL_RGB;\r
3080                 pixelType = GL_UNSIGNED_SHORT_5_6_5;\r
3081                 break;\r
3082         case ECF_R8G8B8:\r
3083                 supported = true;\r
3084                 internalFormat = GL_RGB;\r
3085                 pixelFormat = GL_RGB;\r
3086                 pixelType = GL_UNSIGNED_BYTE;\r
3087                 break;\r
3088         case ECF_A8R8G8B8:\r
3089                 supported = true;\r
3090                 if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_IMG_texture_format_BGRA8888) ||\r
3091                         queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_format_BGRA8888) ||\r
3092                         queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_APPLE_texture_format_BGRA8888))\r
3093                 {\r
3094                         internalFormat = GL_BGRA;\r
3095                         pixelFormat = GL_BGRA;\r
3096                 }\r
3097                 else\r
3098                 {\r
3099                         internalFormat = GL_RGBA;\r
3100                         pixelFormat = GL_RGBA;\r
3101                         *converter = CColorConverter::convert_A8R8G8B8toA8B8G8R8;\r
3102                 }\r
3103                 pixelType = GL_UNSIGNED_BYTE;\r
3104                 break;\r
3105 #ifdef GL_EXT_texture_compression_s3tc\r
3106         case ECF_DXT1:\r
3107                 supported = true;\r
3108                 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;\r
3109                 pixelFormat = GL_RGBA;\r
3110                 pixelType = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;\r
3111                 break;\r
3112 #endif\r
3113 #ifdef GL_EXT_texture_compression_s3tc\r
3114         case ECF_DXT2:\r
3115         case ECF_DXT3:\r
3116                 supported = true;\r
3117                 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;\r
3118                 pixelFormat = GL_RGBA;\r
3119                 pixelType = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;\r
3120                 break;\r
3121 #endif\r
3122 #ifdef GL_EXT_texture_compression_s3tc\r
3123         case ECF_DXT4:\r
3124         case ECF_DXT5:\r
3125                 supported = true;\r
3126                 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;\r
3127                 pixelFormat = GL_RGBA;\r
3128                 pixelType = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;\r
3129                 break;\r
3130 #endif\r
3131 #ifdef GL_IMG_texture_compression_pvrtc\r
3132         case ECF_PVRTC_RGB2:\r
3133                 supported = true;\r
3134                 internalFormat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;\r
3135                 pixelFormat = GL_RGB;\r
3136                 pixelType = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;\r
3137                 break;\r
3138 #endif\r
3139 #ifdef GL_IMG_texture_compression_pvrtc\r
3140         case ECF_PVRTC_ARGB2:\r
3141                 supported = true;\r
3142                 internalFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;\r
3143                 pixelFormat = GL_RGBA;\r
3144                 pixelType = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;\r
3145                 break;\r
3146 #endif\r
3147 #ifdef GL_IMG_texture_compression_pvrtc\r
3148         case ECF_PVRTC_RGB4:\r
3149                 supported = true;\r
3150                 internalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;\r
3151                 pixelFormat = GL_RGB;\r
3152                 pixelType = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;\r
3153                 break;\r
3154 #endif\r
3155 #ifdef GL_IMG_texture_compression_pvrtc\r
3156         case ECF_PVRTC_ARGB4:\r
3157                 supported = true;\r
3158                 internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;\r
3159                 pixelFormat = GL_RGBA;\r
3160                 pixelType = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;\r
3161                 break;\r
3162 #endif\r
3163 #ifdef GL_IMG_texture_compression_pvrtc2\r
3164         case ECF_PVRTC2_ARGB2:\r
3165                 supported = true;\r
3166                 internalFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG;\r
3167                 pixelFormat = GL_RGBA;\r
3168                 pixelType = GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG;\r
3169                 break;\r
3170 #endif\r
3171 #ifdef GL_IMG_texture_compression_pvrtc2\r
3172         case ECF_PVRTC2_ARGB4:\r
3173                 supported = true;\r
3174                 internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG;\r
3175                 pixelFormat = GL_RGBA;\r
3176                 pixelType = GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG;\r
3177                 break;\r
3178 #endif\r
3179 #ifdef GL_OES_compressed_ETC1_RGB8_texture\r
3180         case ECF_ETC1:\r
3181                 supported = true;\r
3182                 internalFormat = GL_ETC1_RGB8_OES;\r
3183                 pixelFormat = GL_RGB;\r
3184                 pixelType = GL_ETC1_RGB8_OES;\r
3185                 break;\r
3186 #endif\r
3187 #ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available\r
3188         case ECF_ETC2_RGB:\r
3189                 supported = true;\r
3190                 internalFormat = GL_COMPRESSED_RGB8_ETC2;\r
3191                 pixelFormat = GL_RGB;\r
3192                 pixelType = GL_COMPRESSED_RGB8_ETC2;\r
3193                 break;\r
3194 #endif\r
3195 #ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available\r
3196         case ECF_ETC2_ARGB:\r
3197                 supported = true;\r
3198                 internalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC;\r
3199                 pixelFormat = GL_RGBA;\r
3200                 pixelType = GL_COMPRESSED_RGBA8_ETC2_EAC;\r
3201                 break;\r
3202 #endif\r
3203         case ECF_D16:\r
3204                 supported = true;\r
3205                 internalFormat = GL_DEPTH_COMPONENT16;\r
3206                 pixelFormat = GL_DEPTH_COMPONENT;\r
3207                 pixelType = GL_UNSIGNED_SHORT;\r
3208                 break;\r
3209         case ECF_D32:\r
3210 #if defined(GL_OES_depth32)\r
3211                 if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth32))\r
3212                 {\r
3213                         supported = true;\r
3214                         internalFormat = GL_DEPTH_COMPONENT32_OES;\r
3215                         pixelFormat = GL_DEPTH_COMPONENT;\r
3216                         pixelType = GL_UNSIGNED_INT;\r
3217                 }\r
3218 #endif\r
3219                 break;\r
3220         case ECF_D24S8:\r
3221 #ifdef GL_OES_packed_depth_stencil\r
3222                 if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_packed_depth_stencil))\r
3223                 {\r
3224                         supported = true;\r
3225                         internalFormat = GL_DEPTH24_STENCIL8_OES;\r
3226                         pixelFormat = GL_DEPTH_STENCIL_OES;\r
3227                         pixelType = GL_UNSIGNED_INT_24_8_OES;\r
3228                 }\r
3229 #endif\r
3230                 break;\r
3231         case ECF_R8:\r
3232                 break;\r
3233         case ECF_R8G8:\r
3234                 break;\r
3235         case ECF_R16:\r
3236                 break;\r
3237         case ECF_R16G16:\r
3238                 break;\r
3239         case ECF_R16F:\r
3240                 break;\r
3241         case ECF_G16R16F:\r
3242                 break;\r
3243         case ECF_A16B16G16R16F:\r
3244                 break;\r
3245         case ECF_R32F:\r
3246                 break;\r
3247         case ECF_G32R32F:\r
3248                 break;\r
3249         case ECF_A32B32G32R32F:\r
3250                 break;\r
3251         default:\r
3252                 break;\r
3253         }\r
3254 \r
3255 #ifdef _IRR_IOS_PLATFORM_\r
3256         if (internalFormat == GL_BGRA)\r
3257                 internalFormat = GL_RGBA;\r
3258 #endif\r
3259 \r
3260         return supported;\r
3261 }\r
3262 \r
3263 bool COGLES1Driver::queryTextureFormat(ECOLOR_FORMAT format) const\r
3264 {\r
3265         GLint dummyInternalFormat;\r
3266         GLenum dummyPixelFormat;\r
3267         GLenum dummyPixelType;\r
3268         void (*dummyConverter)(const void*, s32, void*);\r
3269         return getColorFormatParameters(format, dummyInternalFormat, dummyPixelFormat, dummyPixelType, &dummyConverter);\r
3270 }\r
3271 \r
3272 bool COGLES1Driver::needsTransparentRenderPass(const irr::video::SMaterial& material) const\r
3273 {\r
3274         return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation();\r
3275 }\r
3276 \r
3277 COGLES1CacheHandler* COGLES1Driver::getCacheHandler() const\r
3278 {\r
3279         return CacheHandler;\r
3280 }\r
3281 \r
3282 } // end namespace\r
3283 } // end namespace\r
3284 \r
3285 #endif // _IRR_COMPILE_WITH_OGLES1_\r
3286 \r
3287 namespace irr\r
3288 {\r
3289 namespace video\r
3290 {\r
3291 \r
3292 #ifndef _IRR_COMPILE_WITH_OGLES1_\r
3293 class IVideoDriver;\r
3294 class IContextManager;\r
3295 #endif\r
3296 \r
3297 IVideoDriver* createOGLES1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)\r
3298 {\r
3299 #ifdef _IRR_COMPILE_WITH_OGLES1_\r
3300         return new COGLES1Driver(params, io, contextManager);\r
3301 #else\r
3302         return 0;\r
3303 #endif //  _IRR_COMPILE_WITH_OGLES1_\r
3304 }\r
3305 \r
3306 } // end namespace\r
3307 } // end namespace\r