CRender * OGLDeviceBuilder::CreateRender(void)
{
    if( m_pRender == NULL )
    {
        if( CGraphicsContext::g_pGraphicsContext == NULL && CGraphicsContext::g_pGraphicsContext->Ready() )
        {
            DebugMessage(M64MSG_ERROR, "Can not create ColorCombiner before creating and initializing GraphicsContext");
            m_pRender = NULL;
            SAFE_CHECK(m_pRender);
        }

        COGLGraphicsContext &context = *((COGLGraphicsContext*)CGraphicsContext::g_pGraphicsContext);

        if( context.m_bSupportMultiTexture )
        {
            // OGL extension render
            m_pRender = new COGLExtRender();
        }
        else
        {
            // Basic OGL Render
            m_pRender = new OGLRender();
        }
        SAFE_CHECK(m_pRender);
        CRender::g_pRender = m_pRender;
    }

    return m_pRender;
}
CDeviceBuilder* CDeviceBuilder::CreateBuilder(SupportedDeviceType type)
{
    if( m_pInstance == NULL )
    {
        switch( type )
        {
        case    OGL_DEVICE:
        case    OGL_1_1_DEVICE:
        case    OGL_1_2_DEVICE:
        case    OGL_1_3_DEVICE:
        case    OGL_1_4_DEVICE:
        case    OGL_1_4_V2_DEVICE:
        case    OGL_TNT2_DEVICE:
        case    NVIDIA_OGL_DEVICE:
        case OGL_FRAGMENT_PROGRAM:
            m_pInstance = new OGLDeviceBuilder();
            break;
        default:
            DebugMessage(M64MSG_ERROR, "CreateBuilder: unknown OGL device type");
            exit(1);
        }

        SAFE_CHECK(m_pInstance);
    }

    return m_pInstance;
}
CBlender * OGLDeviceBuilder::CreateAlphaBlender(CRender *pRender)
{
    if( m_pAlphaBlender == NULL )
    {
        m_pAlphaBlender = new COGLBlender(pRender);
        SAFE_CHECK(m_pAlphaBlender);
    }

    return m_pAlphaBlender;
}
CRender * OGLDeviceBuilder::CreateRender(void)
{
    if( m_pRender == NULL )
    {
        if( CGraphicsContext::IsNull() || !CGraphicsContext::Get()->IsReady() )
        {
            DebugMessage(M64MSG_ERROR, "Can not create ColorCombiner before creating and initializing GraphicsContext");
            m_pRender = NULL;
            SAFE_CHECK(m_pRender);
        }

        m_pRender = new OGLRender();

        SAFE_CHECK(m_pRender);
        CRender::g_pRender = m_pRender;
    }

    return m_pRender;
}
CGraphicsContext * OGLDeviceBuilder::CreateGraphicsContext(void)
{
    if( m_pGraphicsContext == NULL )
    {
        m_pGraphicsContext = new COGLGraphicsContext();
        SAFE_CHECK(m_pGraphicsContext);
        CGraphicsContext::g_pGraphicsContext = m_pGraphicsContext;
    }

    g_pFrameBufferManager = new FrameBufferManager;
    return m_pGraphicsContext;
}
CGraphicsContext * OGLDeviceBuilder::CreateGraphicsContext(void)
{
    if( CGraphicsContext::IsNull() )
    {
        CGraphicsContext::m_pGraphicsContext = new COGLGraphicsContext();
        SAFE_CHECK(CGraphicsContext::m_pGraphicsContext);
    }

    g_pFrameBufferManager = new FrameBufferManager;

    return CGraphicsContext::m_pGraphicsContext;
}
CColorCombiner * OGLDeviceBuilder::CreateColorCombiner(CRender *pRender)
{
    bool bColorCombinerFound = false;

    if( m_pColorCombiner == NULL )
    {
        if(    CGraphicsContext::Get() == NULL
            && CGraphicsContext::Get()->IsReady() )
        {
            DebugMessage(M64MSG_ERROR, "Can not create ColorCombiner before creating and initializing GraphicsContext");
        }
        else
        {
            m_deviceType = (SupportedDeviceType)options.OpenglRenderSetting;

            if( m_deviceType == OGL_DEVICE )    // Best fit
            {
                m_pColorCombiner = new COGLColorCombiner(pRender);
                bColorCombinerFound = true;
                DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: 2.1");
            }
            else
            {
                switch(m_deviceType)
                {
                case OGL_FRAGMENT_PROGRAM:
                    m_pColorCombiner = new COGLColorCombiner(pRender);
                    bColorCombinerFound = true;
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: 2.1");
                    break;
                 default:
                    break;
                }
            }
        }

        if (!bColorCombinerFound)
        {
            DebugMessage(M64MSG_ERROR, "OpenGL Combiner: Can't find a valid OpenGL Combiner");
            exit(1);
        }

        SAFE_CHECK(m_pColorCombiner);
    }

    return m_pColorCombiner;
}
CTextureManager::CTextureManager() :
    m_pHead(NULL),
    m_pCacheTxtrList(NULL),
    m_numOfCachedTxtrList(809)
{
    m_numOfCachedTxtrList = GetNextPrime(800);

    m_currentTextureMemUsage    = 0;
    m_pYoungestTexture          = NULL;
    m_pOldestTexture            = NULL;

    m_pCacheTxtrList = new TxtrCacheEntry *[m_numOfCachedTxtrList];
    SAFE_CHECK(m_pCacheTxtrList);

    for (uint32 i = 0; i < m_numOfCachedTxtrList; i++)
        m_pCacheTxtrList[i] = NULL;

    memset(&m_blackTextureEntry, 0, sizeof(TxtrCacheEntry));
}
CColorCombiner * OGLDeviceBuilder::CreateColorCombiner(CRender *pRender)
{
    if( m_pColorCombiner == NULL )
    {
        if( CGraphicsContext::g_pGraphicsContext == NULL && CGraphicsContext::g_pGraphicsContext->Ready() )
        {
            DebugMessage(M64MSG_ERROR, "Can not create ColorCombiner before creating and initializing GraphicsContext");
        }
        else
        {
            m_deviceType = (SupportedDeviceType)options.OpenglRenderSetting;

#if SDL_VIDEO_OPENGL

            if (m_deviceType == NVIDIA_OGL_DEVICE && !bNvidiaExtensionsSupported)
            {
                DebugMessage(M64MSG_WARNING, "Your video card does not support Nvidia OpenGL extensions.  Falling back to auto device.");
                m_deviceType = OGL_DEVICE;
            }
            if( m_deviceType == OGL_DEVICE )    // Best fit
            {
                GLint maxUnit = 2;
                COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext);
                glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,&maxUnit);
                OPENGL_CHECK_ERRORS;
#ifndef HAVE_GLES
                if( pcontext->IsExtensionSupported("GL_ARB_fragment_program") )
                {
                    m_pColorCombiner = new COGL_FragmentProgramCombiner(pRender);
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Fragment Program");
                }
                else if( pcontext->IsExtensionSupported("GL_NV_texture_env_combine4") || 
                    pcontext->IsExtensionSupported("GL_NV_register_combiners") )
                {
                    m_pColorCombiner = new COGLColorCombinerNvidia(pRender);
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: NVidia");
                }
                else if( pcontext->IsExtensionSupported("GL_NV_texture_env_combine4") )
                {
                    m_pColorCombiner = new COGLColorCombinerTNT2(pRender);
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: TNT2");
                }
                else if( pcontext->IsExtensionSupported("GL_EXT_texture_env_combine") ||
                         pcontext->IsExtensionSupported("GL_ARB_texture_env_combine") )
                {
                    if( pcontext->IsExtensionSupported("GL_ARB_texture_env_crossbar") )
#endif
                    {
#ifndef HAVE_GLES
                        if( maxUnit > 2 )
                        {
                            m_pColorCombiner = new COGLColorCombiner4v2(pRender);
                            DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.4 version 2");
                        }
                        else
#endif
                        {
                            m_pColorCombiner = new COGLColorCombiner4(pRender);
                            DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.4");
                        }
                     }
#ifndef HAVE_GLES
                   else
                    {
                        if( maxUnit > 2 )
                        {
                            m_pColorCombiner = new COGLColorCombiner4v2(pRender);
                            DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.4 version 2 (w/o env crossbar)");
                        }
                        else
                        {
                            m_pColorCombiner = new COGLColorCombiner2(pRender);
                            DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.2/1.3");
                        }
                    }
                }
                else
                {
                    m_pColorCombiner = new COGLColorCombiner(pRender);
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Basic OGL");
                }
#endif
            }
            else
            {
                switch(m_deviceType)
                {
                case OGL_1_1_DEVICE:
                    m_pColorCombiner = new COGLColorCombiner(pRender);
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Basic OGL");
                    break;
                case OGL_1_2_DEVICE:
                case OGL_1_3_DEVICE:
                    m_pColorCombiner = new COGLColorCombiner2(pRender);
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.2/1.3");
                    break;
                case OGL_1_4_DEVICE:
                    m_pColorCombiner = new COGLColorCombiner4(pRender);
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.4");
                    break;
                case OGL_1_4_V2_DEVICE:
                    m_pColorCombiner = new COGLColorCombiner4v2(pRender);
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: OGL 1.4 Version 2");
                    break;
#ifndef HAVE_GLES
                case OGL_TNT2_DEVICE:
                    m_pColorCombiner = new COGLColorCombinerTNT2(pRender);
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: TNT2");
                    break;
                case NVIDIA_OGL_DEVICE:
                    m_pColorCombiner = new COGLColorCombinerNvidia(pRender);
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Nvidia");
                    break;
                case OGL_FRAGMENT_PROGRAM:
                    m_pColorCombiner = new COGL_FragmentProgramCombiner(pRender);
                    DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Fragment Program");
                    break;
#endif
                 default:
                    break;
                }
            }

#elif SDL_VIDEO_OPENGL_ES2
            m_pColorCombiner = new COGL_FragmentProgramCombiner(pRender);
            DebugMessage(M64MSG_VERBOSE, "OpenGL Combiner: Fragment Program");
#endif
        }

        SAFE_CHECK(m_pColorCombiner);
    }

    return m_pColorCombiner;
}