void CKLBOGLWrapper::draw(
    GLenum				mode,
    CShaderInstance*	instance,
    CBuffer**			ppBuffer,
    u32					bufferCount,
    CIndexBuffer*		pIndexBuffer,
    CTextureUsage**		array_pTexture,
    s32*				uniformID,
    s32					indexCount) {

    // Force buffer to commit changes if they are VBO and were not updated.

    u32 n=0;
    while (n < bufferCount) {
        CBuffer* pBuffer = ppBuffer[n];
        n++;

        if (pBuffer->VBOModified) {
            pBuffer->commitVBO();
        }
    }

    if (pIndexBuffer->VBOModified) {
        pIndexBuffer->commitVBO();
    }

    if (m_lastShaderInstance != instance) {
        // Same Shader with different param is also a possibility.
        if (!m_lastShaderInstance || (m_lastShaderInstance->m_pShaderSet != instance->m_pShaderSet)) {
            // Use Shader only when program really changes.
            dglUseProgram(instance->m_pShaderSet->programObj);
        }

        // Transform matrix
//		u32 _projectionUniform = dglGetUniformLocation(instance->m_pShaderSet->programObj, "Projection");
//		dglUniformMatrix4fv(_projectionUniform, 1, 0, displayMatrix2D);
        m_lastShaderInstance = instance;
    }
    u32 _projectionUniform = dglGetUniformLocation(instance->m_pShaderSet->programObj, "Projection");
    dglUniformMatrix4fv(_projectionUniform, 1, 0, displayMatrix2D);

    //
    // Process all input for shaders.
    //
    CShader* pVertexS	= instance->m_pShaderSet->vertexShader;
    s32 maxVertexInput	= pVertexS->countStreamInfo;
    s32 count			= 0;
    while (count < maxVertexInput) {
        CShaderInstance::SInternalParam* pParam = &instance->paramArrayVertexVertexShader[count];
        if (pParam->isConstantifiedOrUniform)
        {
            dglDisableVertexAttribArray(count);

            // Constantified
            switch (pParam->dType & 0x0F) {
            case VEC1F:
                dglVertexAttrib1fv(count, (GLfloat*)pParam->values);
                break;
            case VEC2:
                dglVertexAttrib2fv(count, (GLfloat*)pParam->values);
                break;
            case VEC3:
                dglVertexAttrib3fv(count, (GLfloat*)pParam->values);
                break;
            case VEC4BYTE:
            case VEC4:
                dglVertexAttrib4fv(count, (GLfloat*)pParam->values);
                break;
            default:
                klb_assertAlways("Invalid Type for vertex attribute");
            }
        } else {
            //
            // Search in buffer the source mapping the shader input.
            //
            s32 vertID = instance->paramArrayVertexVertexShader[count].vertexInfoID;

            u32 n=0;
            while (n < bufferCount) {
                CBuffer* pBuffer = ppBuffer[n];
                n++;

                SVertexEntry* pEntries = pBuffer->structure;
                SVertexEntry* pEntriesEnd = &pEntries[pBuffer->dynCount + pBuffer->vboCount];
                while ((pEntries->vertexInfoID != vertID) && (pEntries < pEntriesEnd)) {
                    pEntries++;
                }

                if (pEntries < pEntriesEnd) {
                    GLint size = GLint(pParam->dType & 0xF);
                    GLenum type	= GL_FLOAT;
                    GLboolean normalized = GL_FALSE;
                    if (size == VEC4BYTE) {
                        size = 4;
                        type = GL_UNSIGNED_BYTE;
                        normalized = GL_TRUE;
                    }

                    if (pEntries->isVBO) {
                        _glBindBuffer(pBuffer->vboID);
                        dglEnableVertexAttribArray(count);
                        dglVertexAttribPointer(				count,
                                                            size,
                                                            type,
                                                            normalized,
                                                            (pBuffer->strideVBO * sizeof(float)),
                                                            (const void*)((pEntries->offset + pBuffer->offsetDrawVBO) * sizeof(float)));
                    } else {
                        _glBindBuffer(0);
                        dglEnableVertexAttribArray(count);
                        dglVertexAttribPointer(				count,
                                                            size,
                                                            type,
                                                            normalized,
                                                            (pBuffer->strideDyn * sizeof(float)),
                                                            &(((float*)pBuffer->ptrBuffer)[pEntries->offset + pBuffer->offsetDrawDyn]));
                    }
                    // Break and go to next array.
                    break;
                }
            }
        }
        count++;
    }

    //
    // Process uniform parameters.
    //
    count = 0;
    s32 countTexture = 0;
    s32* pLocation = instance->m_pShaderSet->locationArray;	// Vertex + Pixel shader.

    for (s32 n=0; n < 2; n++) {
        CShaderInstance::SInternalParam* pParam;
        CShaderInstance::SInternalParam* maxVertexUniform;

        //
        // Vertex & Pixel Shader. (MUST BE SAME ORDER AS CreateShaderSet !!!)
        //
        if (n == 0) {
            pParam = instance->paramArrayUniformVertexShader;
            maxVertexUniform = &pParam[pVertexS->countUniform];
        } else {
            pParam = instance->paramArrayUniformPixelShader;
            maxVertexUniform = &pParam[instance->m_pShaderSet->pixelShader->countUniform];
        }

        while (pParam < maxVertexUniform) {
            s32 location = *pLocation++;
            switch (pParam->dType & 0x0F) {
            case VEC1I:
                dglUniform1iv(location, 1, (GLint*)(pParam->values));
                break;
            case VEC1F:
                dglUniform1fv(location, 1, (GLfloat*)(pParam->values));
                break;
            case VEC2:
                dglUniform2fv(location, 1, (GLfloat*)(pParam->values));
                break;
            case VEC3:
                dglUniform3fv(location, 1, (GLfloat*)(pParam->values));
                break;
            case VEC4:
                dglUniform4fv(location, 1, (GLfloat*)(pParam->values));
                break;
            case MMAT2:
                dglUniformMatrix2fv(location, 1, GL_FALSE, (GLfloat*)(pParam->values));
                break;
            case MMAT3:
                dglUniformMatrix3fv(location, 1, GL_FALSE, (GLfloat*)(pParam->values));
                break;
            case MMAT4:
                dglUniformMatrix4fv(location, 1, GL_FALSE, (GLfloat*)(pParam->values));
                break;
            case TEX2D:
                if (pParam->pTexture == NULL) {
                    //
                    // Process texture
                    //
                    CTextureUsage**	pTex	= array_pTexture;
                    if (pTex != null) {
                        s32*			pUniID	= uniformID;
                        while ((*pTex != null) && (pParam->vertexInfoID != *pUniID)) {
                            pTex++;
                            pUniID++;
                        }

                        if (*pTex != null) {
                            // Assign texture to texture unit and apply parameters.
                            CTextureUsage* pUsage = *pTex;
                            pUsage->activate(countTexture);

                            // Link active texture unit to uniform
                            dglUniform1i(location, countTexture);
                            countTexture++;
                        } else {
                            // klb_assertAlways("Texture attribute is not mapped to a valid texture");
                        }
                    } else {
                        klb_assertAlways("No texture information when shader use texture");
                    }
                } /*else {
					// Assign texture to texture unit and apply parameters.
					CTextureUsage* pUsage = pParam->pTexture;
					pUsage->activate(countTexture);
					// Link active texture unit to uniform
					dglUniform1i(location, countTexture);
					countTexture++;
				}*/

                break;
            }
            pParam++;
        }
    }

    //
    // Handle Index Buffer & Draw call.
    //
    if (pIndexBuffer->isVBO) {
        if (lastElementArrayBuffer != pIndexBuffer->vboID) {
            lastElementArrayBuffer = pIndexBuffer->vboID;
            dglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pIndexBuffer->vboID);
        }
        dglDrawElements(mode, indexCount, GL_UNSIGNED_SHORT, 0);
    } else {
        if (lastElementArrayBuffer != 0) {
            lastElementArrayBuffer = 0;
            dglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        }
        dglDrawElements(mode, indexCount, GL_UNSIGNED_SHORT, &pIndexBuffer->ptrBuffer[pIndexBuffer->offsetDraw]);
    }
}