Add implementation of chromakey for layer to LayerManagerPlugin
authorNobuhiko Tanibata <ntanibata@jp.adit-jv.com>
Sun, 5 Aug 2012 23:21:28 +0000 (08:21 +0900)
committerMichael Schuldt <michael.schuldt@bmw.de>
Wed, 12 Sep 2012 09:34:34 +0000 (11:34 +0200)
GLESGraphicSystem:
-If chromakey for layer is enabled, creates temporary buffer and render surfaces to it.
-and then the buffer is texturized and composite.

LayerManagerPlugins/Renderers/Graphic/include/GraphicSystems/GLESGraphicSystem.h
LayerManagerPlugins/Renderers/Graphic/src/GraphicSystems/GLESGraphicSystem.cpp

index 342ced5..e21eb78 100644 (file)
@@ -70,6 +70,13 @@ public:
        virtual void applyLayerMatrix(IlmMatrix& matrix);
 
 protected:
+    virtual bool setupTextureForChromaKey();
+    virtual void createPbufferSurface();
+    virtual void createTempTexture();
+    virtual void renderTempTexture();
+    virtual void destroyTempTexture();
+
+protected:
     int m_windowWidth;
     int m_windowHeight;
     EGLNativeDisplayType m_nativeDisplay;
@@ -78,6 +85,7 @@ protected:
     EGLConfig m_eglConfig;
     EGLContext m_eglContext;
     EGLSurface m_eglSurface;
+    EGLSurface m_eglPbufferSurface;
     EGLDisplay m_eglDisplay;
     uint m_vbo;
     EGLint m_displayWidth;
@@ -90,6 +98,7 @@ protected:
 #ifdef DRAW_LAYER_DEBUG
     Shader* m_layerShader;
 #endif
+    uint m_texId;
 private:
     void saveScreenShot();
 };
index cdee4ec..5afdbdc 100644 (file)
@@ -56,6 +56,7 @@ GLESGraphicsystem::GLESGraphicsystem(int windowWidth, int windowHeight, PfnShade
 , m_eglConfig(0)
 , m_eglContext(0)
 , m_eglSurface(0)
+, m_eglPbufferSurface(0)
 , m_eglDisplay(0)
 , m_vbo(0)
 , m_displayWidth(0)
@@ -68,6 +69,7 @@ GLESGraphicsystem::GLESGraphicsystem(int windowWidth, int windowHeight, PfnShade
 #ifdef DRAW_LAYER_DEBUG
 , m_layerShader(0)
 #endif
+, m_texId(0)
 {
     LOG_DEBUG("GLESGraphicsystem", "creating GLESGraphicsystem");
 }
@@ -107,12 +109,10 @@ bool GLESGraphicsystem::init(EGLNativeDisplayType display, EGLNativeWindowType N
     eglBindAPI(EGL_OPENGL_ES_API);
 
     EGLint pi32ConfigAttribs[] = {
-            EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE,
-            EGL_OPENGL_ES2_BIT,
-            EGL_RED_SIZE,
-            8,
-            EGL_ALPHA_SIZE,
-            8,
+            EGL_SURFACE_TYPE,    EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+            EGL_RED_SIZE,        8,
+            EGL_ALPHA_SIZE,      8,
             EGL_NONE
     };
 
@@ -255,14 +255,28 @@ void GLESGraphicsystem::renderSWLayer(Layer *layer, bool clear)
 
     if ( layer->visibility && layer->opacity > 0.0 )
     {
-        SurfaceList surfaces = layer->getAllSurfaces();
-        for(SurfaceListConstIterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
+        bool bChromaKeyEnabled = m_currentLayer->getChromaKeyEnabled();
+        if (bChromaKeyEnabled && !setupTextureForChromaKey())
+        {
+            LOG_WARNING("GLESGraphicsystem", "Failed to create Pbuffer. Layer chroma key to be disabled.");
+            bChromaKeyEnabled = false;
+        }
+
+        SurfaceList surfaces = m_currentLayer->getAllSurfaces();
+        for(std::list<Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
         {
             if ((*currentS)->hasNativeContent() && (*currentS)->visibility && (*currentS)->opacity>0.0f)
             {
                 renderSurface(*currentS);
             }
         }
+
+        if (bChromaKeyEnabled)
+        {
+            activateGraphicContext();
+            renderTempTexture();
+            destroyTempTexture();
+        }
     }
 
     endLayer();
@@ -560,3 +574,140 @@ void GLESGraphicsystem::saveScreenShotOfFramebuffer(std::string fileToSave)
     free(rgbbuffer);
 }
 
+bool GLESGraphicsystem::setupTextureForChromaKey()
+{
+    createPbufferSurface();
+    if (m_eglPbufferSurface == EGL_NO_SURFACE)
+    {
+        return false;
+    }
+
+    // Switch the current context to pbuffer surface
+    eglMakeCurrent(m_eglDisplay, m_eglPbufferSurface, m_eglPbufferSurface, m_eglContext);
+    createTempTexture();
+    return true;
+}
+
+void GLESGraphicsystem::createPbufferSurface()
+{
+    if (m_eglPbufferSurface != EGL_NO_SURFACE)
+    {
+        LOG_DEBUG("GLESGraphicsystem", "m_eglPbufferSurface is alread created");
+        return;
+    }
+
+    const FloatRectangle layerDestRegion = m_currentLayer->getDestinationRegion();
+    EGLint width  = static_cast<EGLint>(layerDestRegion.width);
+    EGLint height = static_cast<EGLint>(layerDestRegion.height);
+
+    EGLint pb_attrs[] = {
+        EGL_WIDTH,  width,
+        EGL_HEIGHT, height,
+        EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
+        EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
+        EGL_NONE
+    };
+
+    m_eglPbufferSurface = eglCreatePbufferSurface(m_eglDisplay, m_eglConfig, pb_attrs);
+    if (m_eglPbufferSurface == EGL_NO_SURFACE)
+    {
+        LOG_ERROR("GLESGraphicsystem", "Failed to create EGL pbuffer: " << eglGetError());
+        return;
+    }
+}
+
+void GLESGraphicsystem::createTempTexture()
+{
+    glGenTextures(1, &m_texId);
+    glBindTexture(GL_TEXTURE_2D, m_texId);
+
+    if (!eglBindTexImage(m_eglDisplay, m_eglPbufferSurface, EGL_BACK_BUFFER))
+    {
+        LOG_ERROR("GLESGraphicsystem", "Failed to bind texture for chroma key layer");
+        glDeleteTextures(1, &m_texId);
+        return;
+    }
+
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+
+void GLESGraphicsystem::destroyTempTexture()
+{
+    if (m_texId > 0)
+    {
+        glDeleteTextures(1, &m_texId);
+    }
+
+    if (m_eglPbufferSurface != EGL_NO_SURFACE)
+    {
+        eglReleaseTexImage(m_eglDisplay, m_eglPbufferSurface, EGL_BACK_BUFFER);
+        eglDestroySurface(m_eglDisplay, m_eglPbufferSurface);
+    }
+
+    m_texId = 0;
+    m_eglPbufferSurface = EGL_NO_SURFACE;
+}
+
+void GLESGraphicsystem::renderTempTexture()
+{
+    const FloatRectangle layerSourceRegion      = m_currentLayer->getSourceRegion();
+    const FloatRectangle layerDestinationRegion = m_currentLayer->getDestinationRegion();
+    float textureCoordinates[4];
+
+    ViewportTransform::transformRectangleToTextureCoordinates(
+        layerSourceRegion,
+        m_currentLayer->OriginalSourceWidth,
+        m_currentLayer->OriginalSourceHeight,
+        textureCoordinates);
+
+    ShaderProgram::CommonUniforms uniforms;
+    IlmMatrix layerMatrix;
+    IlmMatrixIdentity(layerMatrix);
+
+    uniforms.x = layerDestinationRegion.x / m_displayWidth;
+    uniforms.y = 1.0f - (layerDestinationRegion.y + layerDestinationRegion.height) / m_displayHeight;
+    uniforms.width   = layerDestinationRegion.width  / m_displayWidth;
+    uniforms.height  = layerDestinationRegion.height / m_displayHeight;
+    uniforms.opacity = m_currentLayer->getOpacity();
+    uniforms.texRange[0]  = textureCoordinates[2] - textureCoordinates[0];
+    uniforms.texRange[1]  = textureCoordinates[3] - textureCoordinates[1];
+    uniforms.texOffset[0] = textureCoordinates[0];
+    uniforms.texOffset[1] = textureCoordinates[1];
+    uniforms.texUnit = 0;
+    uniforms.matrix = layerMatrix.f;
+    uniforms.chromaKeyEnabled = m_currentLayer->getChromaKeyEnabled();
+    if (uniforms.chromaKeyEnabled == true) {
+        unsigned char red   = 0;
+        unsigned char green = 0;
+        unsigned char blue  = 0;
+        m_currentLayer->getChromaKey(red, green, blue);
+        uniforms.chromaKey[0] = (float)red   / 255.0f;
+        uniforms.chromaKey[1] = (float)green / 255.0f;
+        uniforms.chromaKey[2] = (float)blue  / 255.0f;
+    }
+
+    glEnable (GL_BLEND);
+
+    Shader* shader = m_currentLayer->getShader();
+    if (!shader) {
+        shader = m_defaultShader;
+    }
+    shader = pickOptimizedShader(shader, uniforms);
+    shader->use();
+    shader->loadCommonUniforms(uniforms);
+    shader->loadUniforms();
+
+    glBindTexture(GL_TEXTURE_2D, m_texId);
+
+    int orientation = m_currentLayer->getOrientation() % 4;
+    GLint index     = orientation * 12;
+    glDrawArrays(GL_TRIANGLES, index, 6);
+
+    GLenum glErrorCode = glGetError();
+    if ( GL_NO_ERROR != glErrorCode ) {
+        LOG_ERROR("GLESGraphicsystem", "GL Error occured in renderTempTexture:" << glErrorCode );
+    }
+}