File: cpw_glextensions.c

/***************************************************************************/
/*                                                                         */
/*  cpw_glextensions.c                                                     */
/*                                                                         */
/*    The Cpw library interface to the localhost's GL extensions.          */
/*                                                                         */
/*  Copyright 2001-2002 by                                                 */
/*  Jim Mathies,                                                           */
/*                                                                         */
/*  This file is part of the Cpw project, and may only be used,            */
/*  modified, and distributed under the terms of the Cpw project           */
/*  license.  By continuing to use, modify, or distribute this file        */
/*  you indicate that you have read the license and understand and         */
/*  accept it fully.                                                       */
/*                                                                         */
/*  File Platform: cross                                                   */
/*                                                                         */
/***************************************************************************/

#include "cpw_glextensions.h"
#include "cpw_windowlist.h"
#include "cpw_error.h"
#include CPW_OPENGL_H

/*************************************************************************/
/*                                                                       */
/*   init and exit.                                                      */
/*                                                                       */
/*************************************************************************/

#define MAXEXTENSIONS 200

/* http://www.opengl.org/developers/code/features/OGLextensions/OGLextensions.html */
/* http://oss.sgi.com/projects/ogl-sample/registry/ */

bool cpw_glextensions_init( pCpw cpw )
{
    CpwExtensionList * list = cpwmalloc( sizeof( CpwExtensionList ) );

    if ( list == 0 ) {
        cpw_error_set( cpw, cpw_error_outofmemory );
        return false;
    }
    memset( list, 0, sizeof( CpwExtensionList ) );
    
    cpw->extensions = (pVoid)list;

    return true;
}

void cpw_glextensions_exit( pCpw cpw )
{
    CpwExtensionList * list = (CpwExtensionList*)cpw->extensions;
    pStr * p;

    /* free the list extension string list if it was ever created */

    if ( list->init != false ) {
        list->index = 0;
        while ( list->size > list->index ) {
            p = (pStr*)( list->list + ( sizeof( pStr ) * list->index ) );
            freeStr( p );
            list->index++;
        }
    }

    /* free the base list struct memory */

    cpwfree( list );
}

/* init a list of extension strings. called the first time
   the user asks for an extension. used below. */

bool cpw_glextensions_initlist( pCpw cpw ) 
{
    static const GLubyte * extlist = null;
    pStr token     = 0;
    uint_32 pos    = 0;
    pStr string    = 0;
    uint_32 count  = 1;
    uint_32 expand = 0;
    CpwExtensionList * list = (CpwExtensionList*)cpw->extensions;
    pStr * pp;

    if ( list->init == true ) return true;

    /* you must init gl before you can query for extensions. check to
       make sure a window has been initialized indicating gl is 'running'. */        

    if ( cpw_windowlist_length( cpw ) == 0 ) {
        cpw_error_set( cpw, cpw_error_novalidcontext );
        return false;
    }

    if ( list == 0 ) {
        cpw_error_set( cpw, cpw_error_invalidparameter );
        return false;
    }

    list->list = 0;
    list->size = 0;
    list->index = 0;
    list->init = true;

    extlist = glGetString( GL_EXTENSIONS );

    /* real careful, sometimes drivers don't give us a good string */

    if ( extlist == null )
        return false;

    setString( &string, (char*)extlist );

    if ( strLen( string ) == 0 ) {
        freeStr( &string );
        return false;
    }

    /* save a list of pointers to copies of each extension string identifier */
    /* ( regardless of pointer size, this should work ) */
    
    while ( ( token = strToken( &string, " " ) ) != 0 ) {

        /* strToken returns a new pStr (see cpw_str.h) */

        expand = sizeof( pStr ) * count; /* 4*1=4 bytes on 32 bit cpu's */

        /* it is assumed that the local realloc can take a null pointer */

        list->list = cpwrealloc( list->list, expand );

        /* store pointer at plist + ( extension count - size of a pointer ) */

        pp = (pStr*) ( list->list + ( expand - sizeof( pStr ) ) );
        *pp = token;
        count++;

        /* safety */

        if ( count > MAXEXTENSIONS ) break;
    }

    if ( count == 0 ) { 
        cpwfree( list->list ); 
        freeStr( &string );
        return false; 
    }

    list->size = count-1;
    freeStr( &string );

    return true;
}

/*************************************************************************/
/*                                                                       */
/*   extensions api                                                      */
/*                                                                       */
/*************************************************************************/

/* pop one extension at a time back to the user out of our list of extensions */

pChar cpwIterateExtensions( pCpw cpw ) 
{
    CpwExtensionList * list = (CpwExtensionList*)cpw->extensions;
    pStr * p;

    /* if our internal list of extension isn't created, create it. */

    if ( list->init == false )
        if ( !cpw_glextensions_initlist( cpw ) ) 
            return 0;

    /* all done */

    if ( list->size == list->index ) return 0;

    /* next */

    p = (pStr*)( list->list + ( sizeof( pStr ) * list->index ) );

    /* inc our internal extension pointer */

    list->index++;

    return str((*p));
}

/* reset the list */

bool  cpwIterateExtensionsReset( pCpw cpw )
{
    CpwExtensionList * list = (CpwExtensionList*)cpw->extensions;
    list->index = 0;
    return true;
}

/* direct check for a certain extension string identifier. */

bool cpwExtensionSupport( pCpw cpw, pChar string ) 
{
    static const GLubyte * extlist = null;
    
    /* you must init gl before you can query for extensions. check to
       make sure a window has been initialized indicating gl is 'running'. */        

    if ( cpw_windowlist_length( cpw ) == 0 ) {
        cpw_error_set( cpw, cpw_error_novalidcontext );
        return false;
    }

    if ( string == 0 ) {
        cpw_error_set( cpw, cpw_error_invalidparameter );
        return false;
    }

    extlist = glGetString( GL_EXTENSIONS );

    if ( extlist == null )
        return false;

    if ( slFind( (char*)extlist, string ) >= 0 ) return true;
    return false;
}