bool StGLStereoFrameBuffer::init(StGLContext&  theCtx,
                                 const GLsizei theTextureSizeX,
                                 const GLsizei theTextureSizeY,
                                 const bool    theNeedDepthBuffer) {
    // release current objects
    release(theCtx);

    if(theCtx.arbFbo == NULL) {
        return false;
    }

    // create the textures
    if(!StGLStereoTexture::initTrash(theCtx, theTextureSizeX, theTextureSizeY)) {
        release(theCtx);
        return false;
    }

    const GLuint aFboBakDraw = theCtx.stglFramebufferDraw();
    const GLuint aFboBakRead = theCtx.stglFramebufferRead();
    theCtx.stglBindFramebuffer(StGLFrameBuffer::NO_FRAMEBUFFER);

    const GLint aDepthFormat = theCtx.isGlGreaterEqual(3, 0) ? GL_DEPTH24_STENCIL8 : GL_DEPTH_COMPONENT16;
    if(theNeedDepthBuffer) {
        theCtx.arbFbo->glGenRenderbuffers(2, myGLDepthRBIds);

        theCtx.arbFbo->glBindRenderbuffer(GL_RENDERBUFFER, myGLDepthRBIds[StGLStereoTexture::LEFT_TEXTURE]);
        theCtx.arbFbo->glRenderbufferStorage(GL_RENDERBUFFER, aDepthFormat, theTextureSizeX, theTextureSizeY);
    }

    // build FBOs
    theCtx.arbFbo->glGenFramebuffers(2, myGLFBufferIds);
    theCtx.stglBindFramebuffer(myGLFBufferIds[StGLStereoTexture::LEFT_TEXTURE]);

    // bind left texture to left FBO as color buffer
    theCtx.arbFbo->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
                                          StGLStereoTexture::myTextures[StGLStereoTexture::LEFT_TEXTURE].getTextureId(), 0);
    if(theNeedDepthBuffer) {
        // bind left render buffer to left FBO as depth buffer
        theCtx.arbFbo->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
                                                 myGLDepthRBIds[StGLStereoTexture::LEFT_TEXTURE]);
    }
    bool isOk = theCtx.arbFbo->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
    theCtx.arbFbo->glBindRenderbuffer(GL_RENDERBUFFER, StGLFrameBuffer::NO_RENDERBUFFER);
    if(!isOk) {
        release(theCtx);
        theCtx.stglBindFramebufferDraw(aFboBakDraw);
        theCtx.stglBindFramebufferRead(aFboBakRead);
        return false;
    }
    theCtx.stglBindFramebuffer(StGLFrameBuffer::NO_FRAMEBUFFER);

    if(theNeedDepthBuffer) {
        // create right RenderBuffer (will be used as depth buffer)
        theCtx.arbFbo->glBindRenderbuffer(GL_RENDERBUFFER, myGLDepthRBIds[StGLStereoTexture::RIGHT_TEXTURE]);
        theCtx.arbFbo->glRenderbufferStorage(GL_RENDERBUFFER, aDepthFormat, theTextureSizeX, theTextureSizeY);
    }

    theCtx.stglBindFramebuffer(myGLFBufferIds[StGLStereoTexture::RIGHT_TEXTURE]);

    // bind right texture to rights FBO as color buffer
    theCtx.arbFbo->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
                                          StGLStereoTexture::myTextures[StGLStereoTexture::RIGHT_TEXTURE].getTextureId(), 0);

    if(theNeedDepthBuffer) {
        // bind right render buffer to right FBO as depth buffer
        theCtx.arbFbo->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
                                                 myGLDepthRBIds[StGLStereoTexture::RIGHT_TEXTURE]);
    }
    isOk = theCtx.arbFbo->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
    theCtx.arbFbo->glBindRenderbuffer(GL_RENDERBUFFER, StGLFrameBuffer::NO_RENDERBUFFER);
    theCtx.stglBindFramebufferDraw(aFboBakDraw);
    theCtx.stglBindFramebufferRead(aFboBakRead);
    if(!isOk) {
        release(theCtx);
        return false;
    }

    ST_DEBUG_LOG("OpenGL, created StFrameBuffer(WxH= " + getSizeX() + 'x' + getSizeY() + ')');

    // create vertices buffers to draw simple textured quad
    StArray<StGLVec4> aQuad(4);
    aQuad[0] = StGLVec4( 1.0f, -1.0f, 0.0f, 1.0f); // top-right
    aQuad[1] = StGLVec4( 1.0f,  1.0f, 0.0f, 1.0f); // bottom-right
    aQuad[2] = StGLVec4(-1.0f, -1.0f, 0.0f, 1.0f); // top-left
    aQuad[3] = StGLVec4(-1.0f,  1.0f, 0.0f, 1.0f); // bottom-left
    myVerticesBuf.init(theCtx, aQuad);

    StArray<StGLVec2> aQuadTC(4);
    aQuadTC[0] = StGLVec2(1.0f, 0.0f);
    aQuadTC[1] = StGLVec2(1.0f, 1.0f);
    aQuadTC[2] = StGLVec2(0.0f, 0.0f);
    aQuadTC[3] = StGLVec2(0.0f, 1.0f);
    myTexCoordBuf.init(theCtx, aQuadTC);

    myViewPortX = theTextureSizeX;
    myViewPortY = theTextureSizeY;
    return true;
}