1 // Copyright (C) 2015 Patryk Nadrowski
\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
5 #ifndef __C_OGLCORE_CACHE_HANDLER_H_INCLUDED__
\r
6 #define __C_OGLCORE_CACHE_HANDLER_H_INCLUDED__
\r
8 #include "IrrCompileConfig.h"
\r
10 #if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)
\r
12 #include "SMaterial.h"
\r
13 #include "ITexture.h"
\r
20 enum ESetTextureActive
\r
22 EST_ACTIVE_ALWAYS, // texture unit always active after set call
\r
23 EST_ACTIVE_ON_CHANGE // texture unit only active after call when texture changed in cache
\r
27 template <class TOpenGLDriver, class TOpenGLTexture>
\r
28 class COpenGLCoreCacheHandler
\r
33 STextureCache(COpenGLCoreCacheHandler& cacheHandler, E_DRIVER_TYPE driverType, u32 textureCount) :
\r
34 CacheHandler(cacheHandler), DriverType(driverType), TextureCount(textureCount)
\r
36 for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i)
\r
47 const TOpenGLTexture* operator[](int index) const
\r
49 if (static_cast<u32>(index) < MATERIAL_MAX_TEXTURES)
\r
50 return Texture[static_cast<u32>(index)];
\r
55 const TOpenGLTexture* get(u32 index) const
\r
57 if (index < MATERIAL_MAX_TEXTURES)
\r
58 return Texture[index];
\r
63 bool set(u32 index, const ITexture* texture, ESetTextureActive esa=EST_ACTIVE_ALWAYS)
\r
65 bool status = false;
\r
67 E_DRIVER_TYPE type = DriverType;
\r
69 if (index < MATERIAL_MAX_TEXTURES && index < TextureCount)
\r
71 if ( esa == EST_ACTIVE_ALWAYS )
\r
72 CacheHandler.setActiveTexture(GL_TEXTURE0 + index);
\r
74 const TOpenGLTexture* prevTexture = Texture[index];
\r
76 if (texture != prevTexture)
\r
78 if ( esa == EST_ACTIVE_ON_CHANGE )
\r
79 CacheHandler.setActiveTexture(GL_TEXTURE0 + index);
\r
83 type = texture->getDriverType();
\r
85 if (type == DriverType)
\r
89 const TOpenGLTexture* curTexture = static_cast<const TOpenGLTexture*>(texture);
\r
90 const GLenum curTextureType = curTexture->getOpenGLTextureType();
\r
91 const GLenum prevTextureType = (prevTexture) ? prevTexture->getOpenGLTextureType() : curTextureType;
\r
93 if (curTextureType != prevTextureType)
\r
95 glBindTexture(prevTextureType, 0);
\r
97 #if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) )
\r
98 glDisable(prevTextureType);
\r
99 glEnable(curTextureType);
\r
102 #if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) )
\r
103 else if (!prevTexture)
\r
104 glEnable(curTextureType);
\r
107 glBindTexture(curTextureType, static_cast<const TOpenGLTexture*>(texture)->getOpenGLTextureName());
\r
113 os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR);
\r
114 os::Printer::log("Texture type", irr::core::stringc((int)type), ELL_ERROR);
\r
115 os::Printer::log("Driver (or cache handler) type", irr::core::stringc((int)DriverType), ELL_ERROR);
\r
119 if (!texture && prevTexture)
\r
121 const GLenum prevTextureType = prevTexture->getOpenGLTextureType();
\r
123 glBindTexture(prevTextureType, 0);
\r
125 #if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) )
\r
126 glDisable(prevTextureType);
\r
130 Texture[index] = static_cast<const TOpenGLTexture*>(texture);
\r
133 prevTexture->drop();
\r
139 return (status && type == DriverType);
\r
142 void remove(ITexture* texture)
\r
147 for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i)
\r
149 if (Texture[i] == texture)
\r
160 for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i)
\r
164 const TOpenGLTexture* prevTexture = Texture[i];
\r
168 prevTexture->drop();
\r
174 COpenGLCoreCacheHandler& CacheHandler;
\r
176 E_DRIVER_TYPE DriverType;
\r
178 const TOpenGLTexture* Texture[MATERIAL_MAX_TEXTURES];
\r
183 COpenGLCoreCacheHandler(TOpenGLDriver* driver) :
\r
185 #if defined(_MSC_VER)
\r
186 #pragma warning(push)
\r
187 #pragma warning(disable: 4355) // Warning: "'this' : used in base member initializer list. ". It's OK, we don't use the reference in STextureCache constructor.
\r
189 TextureCache(STextureCache(*this, driver->getDriverType(), driver->getFeature().MaxTextureUnits)),
\r
190 #if defined(_MSC_VER)
\r
191 #pragma warning(pop)
\r
193 FrameBufferCount(0), BlendEquation(0), BlendSourceRGB(0),
\r
194 BlendDestinationRGB(0), BlendSourceAlpha(0), BlendDestinationAlpha(0), Blend(0), BlendEquationInvalid(false), BlendFuncInvalid(false), BlendInvalid(false),
\r
195 ColorMask(0), ColorMaskInvalid(false), CullFaceMode(GL_BACK), CullFace(false), DepthFunc(GL_LESS), DepthMask(true), DepthTest(false), FrameBufferID(0),
\r
196 ProgramID(0), ActiveTexture(GL_TEXTURE0), ViewportX(0), ViewportY(0)
\r
198 const COpenGLCoreFeature& feature = Driver->getFeature();
\r
200 FrameBufferCount = core::max_(static_cast<GLuint>(1), static_cast<GLuint>(feature.MultipleRenderTarget));
\r
202 BlendEquation = new GLenum[FrameBufferCount];
\r
203 BlendSourceRGB = new GLenum[FrameBufferCount];
\r
204 BlendDestinationRGB = new GLenum[FrameBufferCount];
\r
205 BlendSourceAlpha = new GLenum[FrameBufferCount];
\r
206 BlendDestinationAlpha = new GLenum[FrameBufferCount];
\r
207 Blend = new bool[FrameBufferCount];
\r
208 ColorMask = new u8[FrameBufferCount];
\r
210 // Initial OpenGL values from specification.
\r
212 if (feature.BlendOperation)
\r
214 Driver->irrGlBlendEquation(GL_FUNC_ADD);
\r
217 for (u32 i = 0; i < FrameBufferCount; ++i)
\r
219 BlendEquation[i] = GL_FUNC_ADD;
\r
221 BlendSourceRGB[i] = GL_ONE;
\r
222 BlendDestinationRGB[i] = GL_ZERO;
\r
223 BlendSourceAlpha[i] = GL_ONE;
\r
224 BlendDestinationAlpha[i] = GL_ZERO;
\r
227 ColorMask[i] = ECP_ALL;
\r
230 glBlendFunc(GL_ONE, GL_ZERO);
\r
231 glDisable(GL_BLEND);
\r
233 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
\r
235 glCullFace(CullFaceMode);
\r
236 glDisable(GL_CULL_FACE);
\r
238 glDepthFunc(DepthFunc);
\r
239 glDepthMask(GL_TRUE);
\r
240 glDisable(GL_DEPTH_TEST);
\r
242 Driver->irrGlActiveTexture(ActiveTexture);
\r
244 #if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) )
\r
245 glDisable(GL_TEXTURE_2D);
\r
248 const core::dimension2d<u32> ScreenSize = Driver->getScreenSize();
\r
249 ViewportWidth = ScreenSize.Width;
\r
250 ViewportHeight = ScreenSize.Height;
\r
251 glViewport(ViewportX, ViewportY, ViewportWidth, ViewportHeight);
\r
254 virtual ~COpenGLCoreCacheHandler()
\r
256 delete[] BlendEquation;
\r
257 delete[] BlendSourceRGB;
\r
258 delete[] BlendDestinationRGB;
\r
259 delete[] BlendSourceAlpha;
\r
260 delete[] BlendDestinationAlpha;
\r
263 delete[] ColorMask;
\r
266 E_DRIVER_TYPE getDriverType() const
\r
268 return Driver->getDriverType();
\r
271 STextureCache& getTextureCache()
\r
273 return TextureCache;
\r
278 void setBlendEquation(GLenum mode)
\r
280 if (BlendEquation[0] != mode || BlendEquationInvalid)
\r
282 Driver->irrGlBlendEquation(mode);
\r
284 for (GLuint i = 0; i < FrameBufferCount; ++i)
\r
285 BlendEquation[i] = mode;
\r
287 BlendEquationInvalid = false;
\r
291 void setBlendEquationIndexed(GLuint index, GLenum mode)
\r
293 if (index < FrameBufferCount && BlendEquation[index] != mode)
\r
295 Driver->irrGlBlendEquationIndexed(index, mode);
\r
297 BlendEquation[index] = mode;
\r
298 BlendEquationInvalid = true;
\r
302 void setBlendFunc(GLenum source, GLenum destination)
\r
304 if (BlendSourceRGB[0] != source || BlendDestinationRGB[0] != destination ||
\r
305 BlendSourceAlpha[0] != source || BlendDestinationAlpha[0] != destination ||
\r
308 glBlendFunc(source, destination);
\r
310 for (GLuint i = 0; i < FrameBufferCount; ++i)
\r
312 BlendSourceRGB[i] = source;
\r
313 BlendDestinationRGB[i] = destination;
\r
314 BlendSourceAlpha[i] = source;
\r
315 BlendDestinationAlpha[i] = destination;
\r
318 BlendFuncInvalid = false;
\r
322 void setBlendFuncSeparate(GLenum sourceRGB, GLenum destinationRGB, GLenum sourceAlpha, GLenum destinationAlpha)
\r
324 if (sourceRGB != sourceAlpha || destinationRGB != destinationAlpha)
\r
326 if (BlendSourceRGB[0] != sourceRGB || BlendDestinationRGB[0] != destinationRGB ||
\r
327 BlendSourceAlpha[0] != sourceAlpha || BlendDestinationAlpha[0] != destinationAlpha ||
\r
330 Driver->irrGlBlendFuncSeparate(sourceRGB, destinationRGB, sourceAlpha, destinationAlpha);
\r
332 for (GLuint i = 0; i < FrameBufferCount; ++i)
\r
334 BlendSourceRGB[i] = sourceRGB;
\r
335 BlendDestinationRGB[i] = destinationRGB;
\r
336 BlendSourceAlpha[i] = sourceAlpha;
\r
337 BlendDestinationAlpha[i] = destinationAlpha;
\r
340 BlendFuncInvalid = false;
\r
345 setBlendFunc(sourceRGB, destinationRGB);
\r
349 void setBlendFuncIndexed(GLuint index, GLenum source, GLenum destination)
\r
351 if (index < FrameBufferCount && (BlendSourceRGB[index] != source || BlendDestinationRGB[index] != destination ||
\r
352 BlendSourceAlpha[index] != source || BlendDestinationAlpha[index] != destination))
\r
354 Driver->irrGlBlendFuncIndexed(index, source, destination);
\r
356 BlendSourceRGB[index] = source;
\r
357 BlendDestinationRGB[index] = destination;
\r
358 BlendSourceAlpha[index] = source;
\r
359 BlendDestinationAlpha[index] = destination;
\r
360 BlendFuncInvalid = true;
\r
364 void setBlendFuncSeparateIndexed(GLuint index, GLenum sourceRGB, GLenum destinationRGB, GLenum sourceAlpha, GLenum destinationAlpha)
\r
366 if (sourceRGB != sourceAlpha || destinationRGB != destinationAlpha)
\r
368 if (index < FrameBufferCount && (BlendSourceRGB[index] != sourceRGB || BlendDestinationRGB[index] != destinationRGB ||
\r
369 BlendSourceAlpha[index] != sourceAlpha || BlendDestinationAlpha[index] != destinationAlpha))
\r
371 Driver->irrGlBlendFuncSeparateIndexed(index, sourceRGB, destinationRGB, sourceAlpha, destinationAlpha);
\r
373 BlendSourceRGB[index] = sourceRGB;
\r
374 BlendDestinationRGB[index] = destinationRGB;
\r
375 BlendSourceAlpha[index] = sourceAlpha;
\r
376 BlendDestinationAlpha[index] = destinationAlpha;
\r
377 BlendFuncInvalid = true;
\r
382 setBlendFuncIndexed(index, sourceRGB, destinationRGB);
\r
386 void setBlend(bool enable)
\r
388 if (Blend[0] != enable || BlendInvalid)
\r
391 glEnable(GL_BLEND);
\r
393 glDisable(GL_BLEND);
\r
395 for (GLuint i = 0; i < FrameBufferCount; ++i)
\r
398 BlendInvalid = false;
\r
402 void setBlendIndexed(GLuint index, bool enable)
\r
404 if (index < FrameBufferCount && Blend[index] != enable)
\r
407 Driver->irrGlEnableIndexed(GL_BLEND, index);
\r
409 Driver->irrGlDisableIndexed(GL_BLEND, index);
\r
411 Blend[index] = enable;
\r
412 BlendInvalid = true;
\r
418 void getColorMask(u8& mask)
\r
420 mask = ColorMask[0];
\r
423 void setColorMask(u8 mask)
\r
425 if (ColorMask[0] != mask || ColorMaskInvalid)
\r
427 glColorMask((mask & ECP_RED) ? GL_TRUE : GL_FALSE, (mask & ECP_GREEN) ? GL_TRUE : GL_FALSE, (mask & ECP_BLUE) ? GL_TRUE : GL_FALSE, (mask & ECP_ALPHA) ? GL_TRUE : GL_FALSE);
\r
429 for (GLuint i = 0; i < FrameBufferCount; ++i)
\r
430 ColorMask[i] = mask;
\r
432 ColorMaskInvalid = false;
\r
436 void setColorMaskIndexed(GLuint index, u8 mask)
\r
438 if (index < FrameBufferCount && ColorMask[index] != mask)
\r
440 Driver->irrGlColorMaskIndexed(index, (mask & ECP_RED) ? GL_TRUE : GL_FALSE, (mask & ECP_GREEN) ? GL_TRUE : GL_FALSE, (mask & ECP_BLUE) ? GL_TRUE : GL_FALSE, (mask & ECP_ALPHA) ? GL_TRUE : GL_FALSE);
\r
442 ColorMask[index] = mask;
\r
443 ColorMaskInvalid = true;
\r
447 // Cull face calls.
\r
449 void setCullFaceFunc(GLenum mode)
\r
451 if (CullFaceMode != mode)
\r
454 CullFaceMode = mode;
\r
458 void setCullFace(bool enable)
\r
460 if (CullFace != enable)
\r
463 glEnable(GL_CULL_FACE);
\r
465 glDisable(GL_CULL_FACE);
\r
473 void setDepthFunc(GLenum mode)
\r
475 if (DepthFunc != mode)
\r
482 void getDepthMask(bool& depth)
\r
487 void setDepthMask(bool enable)
\r
489 if (DepthMask != enable)
\r
492 glDepthMask(GL_TRUE);
\r
494 glDepthMask(GL_FALSE);
\r
496 DepthMask = enable;
\r
500 void getDepthTest(bool& enable)
\r
502 enable = DepthTest;
\r
505 void setDepthTest(bool enable)
\r
507 if (DepthTest != enable)
\r
510 glEnable(GL_DEPTH_TEST);
\r
512 glDisable(GL_DEPTH_TEST);
\r
514 DepthTest = enable;
\r
520 void getFBO(GLuint& frameBufferID) const
\r
522 frameBufferID = FrameBufferID;
\r
525 void setFBO(GLuint frameBufferID)
\r
527 if (FrameBufferID != frameBufferID)
\r
529 Driver->irrGlBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
\r
530 FrameBufferID = frameBufferID;
\r
536 void getProgram(GLuint& programID) const
\r
538 programID = ProgramID;
\r
541 void setProgram(GLuint programID)
\r
543 if (ProgramID != programID)
\r
545 Driver->irrGlUseProgram(programID);
\r
546 ProgramID = programID;
\r
552 void getActiveTexture(GLenum& texture) const
\r
554 texture = ActiveTexture;
\r
557 void setActiveTexture(GLenum texture)
\r
559 if (ActiveTexture != texture)
\r
561 Driver->irrGlActiveTexture(texture);
\r
562 ActiveTexture = texture;
\r
568 void getViewport(GLint& viewportX, GLint& viewportY, GLsizei& viewportWidth, GLsizei& viewportHeight) const
\r
570 viewportX = ViewportX;
\r
571 viewportY = ViewportY;
\r
572 viewportWidth = ViewportWidth;
\r
573 viewportHeight = ViewportHeight;
\r
576 void setViewport(GLint viewportX, GLint viewportY, GLsizei viewportWidth, GLsizei viewportHeight)
\r
578 if (ViewportX != viewportX || ViewportY != viewportY || ViewportWidth != viewportWidth || ViewportHeight != viewportHeight)
\r
580 glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
\r
581 ViewportX = viewportX;
\r
582 ViewportY = viewportY;
\r
583 ViewportWidth = viewportWidth;
\r
584 ViewportHeight = viewportHeight;
\r
588 //! Compare material to current cache and update it when there are differences
\r
589 // Some material renderers do change the cache beyond the original material settings
\r
590 // This corrects the material to represent the current cache state again.
\r
591 void correctCacheMaterial(irr::video::SMaterial& material)
\r
593 // Fix textures which got removed
\r
594 for ( u32 i=0; i < MATERIAL_MAX_TEXTURES; ++i )
\r
596 if ( material.TextureLayer[i].Texture && !TextureCache[i] )
\r
598 material.TextureLayer[i].Texture = 0;
\r
604 TOpenGLDriver* Driver;
\r
606 STextureCache TextureCache;
\r
608 GLuint FrameBufferCount;
\r
610 GLenum* BlendEquation;
\r
611 GLenum* BlendSourceRGB;
\r
612 GLenum* BlendDestinationRGB;
\r
613 GLenum* BlendSourceAlpha;
\r
614 GLenum* BlendDestinationAlpha;
\r
616 bool BlendEquationInvalid;
\r
617 bool BlendFuncInvalid;
\r
622 bool ColorMaskInvalid;
\r
624 GLenum CullFaceMode;
\r
631 GLuint FrameBufferID;
\r
635 GLenum ActiveTexture;
\r
639 GLsizei ViewportWidth;
\r
640 GLsizei ViewportHeight;
\r