]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - libs/picomodel/picomodel.c
eol style
[xonotic/netradiant.git] / libs / picomodel / picomodel.c
index ed4f8b21acb654876f60eb1f702910dd7e718c89..d7790c37f91318ec4c2e365d26cc7a0a958b02c2 100644 (file)
-/* -----------------------------------------------------------------------------\r
-\r
-PicoModel Library\r
-\r
-Copyright (c) 2002, Randy Reddig & seaw0lf\r
-All rights reserved.\r
-\r
-Redistribution and use in source and binary forms, with or without modification,\r
-are permitted provided that the following conditions are met:\r
-\r
-Redistributions of source code must retain the above copyright notice, this list\r
-of conditions and the following disclaimer.\r
-\r
-Redistributions in binary form must reproduce the above copyright notice, this\r
-list of conditions and the following disclaimer in the documentation and/or\r
-other materials provided with the distribution.\r
-\r
-Neither the names of the copyright holders nor the names of its contributors may\r
-be used to endorse or promote products derived from this software without\r
-specific prior written permission.\r
-\r
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-\r
------------------------------------------------------------------------------ */\r
-\r
-\r
-\r
-/* marker */\r
-#define PICOMODEL_C\r
-\r
-\r
-\r
-/* dependencies */\r
-#include "picointernal.h"\r
-\r
-\r
-\r
-/*\r
-PicoInit()\r
-initializes the picomodel library\r
-*/\r
-\r
-int PicoInit( void )\r
-{\r
-       /* successfully initialized -sea */\r
-       return 1;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoShutdown()\r
-shuts the pico model library down\r
-*/\r
-\r
-void PicoShutdown( void )\r
-{\r
-       /* do something interesting here in the future */\r
-       return;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoError()\r
-returns last picomodel error code (see PME_* defines)\r
-*/\r
-\r
-int PicoError( void )\r
-{\r
-       /* todo: do something here */\r
-       return 0;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoSetMallocFunc()\r
-sets the ptr to the malloc function\r
-*/\r
-\r
-void PicoSetMallocFunc( void *(*func)( size_t ) )\r
-{\r
-       if( func != NULL )\r
-               _pico_ptr_malloc = func;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoSetFreeFunc()\r
-sets the ptr to the free function\r
-*/\r
-\r
-void PicoSetFreeFunc( void (*func)( void* ) )\r
-{\r
-       if( func != NULL )\r
-               _pico_ptr_free = func;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoSetLoadFileFunc()\r
-sets the ptr to the file load function\r
-*/\r
-\r
-void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) )\r
-{\r
-       if( func != NULL )\r
-               _pico_ptr_load_file = func;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoSetFreeFileFunc()\r
-sets the ptr to the free function\r
-*/\r
-\r
-void PicoSetFreeFileFunc( void (*func)( void* ) )\r
-{\r
-       if( func != NULL )\r
-               _pico_ptr_free_file = func;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoSetPrintFunc()\r
-sets the ptr to the print function\r
-*/\r
-\r
-void PicoSetPrintFunc( void (*func)( int, const char* ) )\r
-{\r
-       if( func != NULL )\r
-               _pico_ptr_print = func;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoLoadModel()\r
-the meat and potatoes function\r
-*/\r
-\r
-picoModel_t    *PicoLoadModel( char *fileName, int frameNum )\r
-{\r
-       const picoModule_t      **modules, *pm;\r
-       picoModel_t                     *model;\r
-       picoByte_t                      *buffer;\r
-       int                                     bufSize;\r
-       char                            *modelFileName, *remapFileName;\r
-\r
-       \r
-       /* init */\r
-       model = NULL;\r
-       \r
-       /* make sure we've got a file name */\r
-       if( fileName == NULL )\r
-       {\r
-               _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" );\r
-               return NULL;\r
-       }\r
-       \r
-       /* load file data (buffer is allocated by host app) */\r
-       _pico_load_file( fileName, &buffer, &bufSize );\r
-       if( bufSize < 0 )\r
-       {\r
-               _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName );\r
-               return NULL;\r
-       }\r
-\r
-       /* get ptr to list of supported modules */\r
-       modules = PicoModuleList( NULL );\r
-       \r
-       /* run it through the various loader functions and try */\r
-       /* to find a loader that fits the given file data */\r
-       for( ; *modules != NULL; modules++ )\r
-       {\r
-               /* get module */\r
-               pm = *modules;\r
-               \r
-               /* sanity check */\r
-               if( pm == NULL)\r
-                       break;\r
-\r
-               /* module must be able to load */\r
-               if( pm->canload == NULL || pm->load == NULL )\r
-                       continue;\r
-               \r
-               /* see whether this module can load the model file or not */\r
-               if( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK )\r
-               {\r
-                       /* use loader provided by module to read the model data */\r
-                       model = pm->load( fileName, frameNum, buffer, bufSize );\r
-                       if( model == NULL )\r
-                       {\r
-                               _pico_free_file( buffer );\r
-                               return NULL;\r
-                       }\r
-                       \r
-                       /* assign pointer to file format module */\r
-                       model->module = pm;\r
-                       \r
-                       /* get model file name */\r
-                       modelFileName = PicoGetModelFileName( model );\r
-                       \r
-                       /* apply model remappings from <model>.remap */\r
-                       if( strlen( modelFileName ) )\r
-                       {\r
-                               /* alloc copy of model file name */\r
-                               remapFileName = _pico_alloc( strlen( modelFileName ) + 20 );\r
-                               if( remapFileName != NULL )\r
-                               {\r
-                                       /* copy model file name and change extension */\r
-                                       strcpy( remapFileName, modelFileName );\r
-                                       _pico_setfext( remapFileName, "remap" );\r
-\r
-                                       /* try to remap model; we don't handle the result */\r
-                                       PicoRemapModel( model, remapFileName );\r
-\r
-                                       /* free the remap file name string */\r
-                                       _pico_free( remapFileName );\r
-                               }\r
-                       }\r
-                       \r
-                       /* model was loaded, so break out of loop */\r
-                       break;\r
-               }\r
-       }\r
-       \r
-       /* free memory used by file buffer */\r
-       if( buffer)\r
-               _pico_free_file( buffer );\r
-\r
-       /* return */\r
-       return model;\r
-}\r
-\r
-\r
-\r
-/* ----------------------------------------------------------------------------\r
-models\r
----------------------------------------------------------------------------- */\r
-\r
-/*\r
-PicoNewModel()\r
-creates a new pico model\r
-*/\r
-\r
-picoModel_t *PicoNewModel( void )\r
-{\r
-       picoModel_t     *model;\r
-       \r
-       /* allocate */\r
-       model = _pico_alloc( sizeof(picoModel_t) );\r
-       if( model == NULL )\r
-               return NULL;\r
-\r
-       /* clear */\r
-       memset( model,0,sizeof(picoModel_t) );\r
-       \r
-       /* model set up */\r
-       _pico_zero_bounds( model->mins,model->maxs );\r
-\r
-       /* set initial frame count to 1 -sea */\r
-       model->numFrames = 1;\r
-\r
-       /* return ptr to new model */\r
-       return model;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoFreeModel()\r
-frees a model and all associated data\r
-*/\r
-\r
-void PicoFreeModel( picoModel_t *model )\r
-{\r
-       int                             i;\r
-       \r
-\r
-       /* sanity check */\r
-       if( model == NULL )\r
-               return;\r
-       \r
-       /* free bits */\r
-       if( model->name )\r
-               _pico_free( model->name );\r
-       \r
-       /* free shaders */\r
-       for( i = 0; i < model->numShaders; i++ )\r
-               PicoFreeShader( model->shader[ i ] );\r
-       free( model->shader );\r
-       \r
-       /* free surfaces */\r
-       for( i = 0; i < model->numSurfaces; i++ )\r
-               PicoFreeSurface( model->surface[ i ] );\r
-       free( model->surface );\r
-       \r
-       /* free the model */\r
-       _pico_free( model );\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoAdjustModel()\r
-adjusts a models's memory allocations to handle the requested sizes.\r
-will always grow, never shrink\r
-*/\r
-\r
-int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces )\r
-{\r
-       /* dummy check */\r
-       if( model == NULL )\r
-               return 0;\r
-       \r
-       /* bare minimums */\r
-       /* sea: null surface/shader fix (1s=>0s) */\r
-       if( numShaders < 0 )\r
-               numShaders = 0;\r
-       if( numSurfaces < 0 )\r
-               numSurfaces = 0;\r
-\r
-       /* additional shaders? */\r
-       while( numShaders > model->maxShaders )\r
-       {\r
-               model->maxShaders += PICO_GROW_SHADERS;\r
-               if( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) )\r
-                       return 0;\r
-       }\r
-       \r
-       /* set shader count to higher */\r
-       if( numShaders > model->numShaders )\r
-               model->numShaders = numShaders;\r
-       \r
-       /* additional surfaces? */\r
-       while( numSurfaces > model->maxSurfaces )\r
-       {\r
-               model->maxSurfaces += PICO_GROW_SURFACES;\r
-               if( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) )\r
-                       return 0;\r
-       }\r
-       \r
-       /* set shader count to higher */\r
-       if( numSurfaces > model->numSurfaces )\r
-               model->numSurfaces = numSurfaces;\r
-       \r
-       /* return ok */\r
-       return 1;\r
-}\r
-\r
-\r
-\r
-/* ----------------------------------------------------------------------------\r
-shaders\r
----------------------------------------------------------------------------- */\r
-\r
-/*\r
-PicoNewShader()\r
-creates a new pico shader and returns its index. -sea\r
-*/\r
-\r
-picoShader_t *PicoNewShader( picoModel_t *model )\r
-{\r
-       picoShader_t    *shader;\r
-       \r
-\r
-       /* allocate and clear */\r
-       shader = _pico_alloc( sizeof(picoShader_t) );\r
-       if( shader == NULL )\r
-               return NULL;\r
-       memset( shader, 0, sizeof(picoShader_t) );\r
-       \r
-       /* attach it to the model */\r
-       if( model != NULL )\r
-       {\r
-               /* adjust model */\r
-               if( !PicoAdjustModel( model, model->numShaders + 1, 0 ) )\r
-               {\r
-                       _pico_free( shader );\r
-                       return NULL;\r
-               }\r
-               /* attach */\r
-               model->shader[ model->numShaders - 1 ] = shader;\r
-               shader->model = model;\r
-       }\r
-       /* setup default shader colors */\r
-       _pico_set_color( shader->ambientColor,0,0,0,0 );\r
-       _pico_set_color( shader->diffuseColor,255,255,255,1 );\r
-       _pico_set_color( shader->specularColor,0,0,0,0 );\r
-\r
-       /* no need to do this, but i do it anyway */\r
-       shader->transparency = 0;\r
-       shader->shininess = 0;\r
-\r
-       /* return the newly created shader */\r
-       return shader;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoFreeShader()\r
-frees a shader and all associated data -sea\r
-*/\r
-\r
-void PicoFreeShader( picoShader_t *shader )\r
-{\r
-       /* dummy check */\r
-       if( shader == NULL )\r
-               return;\r
-       \r
-       /* free bits */\r
-       if( shader->name )\r
-               _pico_free( shader->name );\r
-       if( shader->mapName )\r
-               _pico_free( shader->mapName );\r
-       \r
-       /* free the shader */\r
-       _pico_free( shader );\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoFindShader()\r
-finds a named shader in a model\r
-*/\r
-\r
-picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive )\r
-{\r
-       int             i;\r
-       \r
-       \r
-       /* sanity checks */\r
-       if( model == NULL || name == NULL )     /* sea: null name fix */\r
-               return NULL;\r
-       \r
-       /* walk list */\r
-       for( i = 0; i < model->numShaders; i++ )\r
-       {\r
-               /* skip null shaders or shaders with null names */\r
-               if( model->shader[ i ] == NULL ||\r
-                       model->shader[ i ]->name == NULL )\r
-                       continue;\r
-\r
-               /* compare the shader name with name we're looking for */\r
-               if( caseSensitive )\r
-               {\r
-                       if( !strcmp( name, model->shader[ i ]->name ) )\r
-                               return model->shader[ i ];\r
-               }\r
-               else if( !_pico_stricmp( name, model->shader[ i ]->name ) )\r
-                               return model->shader[ i ];\r
-       }\r
-       \r
-       /* named shader not found */\r
-       return NULL;\r
-}\r
-\r
-\r
-\r
-/* ----------------------------------------------------------------------------\r
-surfaces\r
----------------------------------------------------------------------------- */\r
-\r
-/*\r
-PicoNewSurface()\r
-creates a new pico surface\r
-*/\r
-\r
-picoSurface_t *PicoNewSurface( picoModel_t *model )\r
-{\r
-       picoSurface_t   *surface;\r
-       char surfaceName[64];\r
-       \r
-       /* allocate and clear */\r
-       surface = _pico_alloc( sizeof( *surface ) );\r
-       if( surface == NULL )\r
-               return NULL;\r
-       memset( surface, 0, sizeof( *surface ) );\r
-       \r
-       /* attach it to the model */\r
-       if( model != NULL )\r
-       {\r
-               /* adjust model */\r
-               if( !PicoAdjustModel( model, 0, model->numSurfaces + 1 ) )\r
-               {\r
-                       _pico_free( surface );\r
-                       return NULL;\r
-               }\r
-               \r
-               /* attach */\r
-               model->surface[ model->numSurfaces - 1 ] = surface;\r
-               surface->model = model;\r
-               \r
-               /* set default name */\r
-               sprintf( surfaceName, "Unnamed_%d", model->numSurfaces );\r
-               PicoSetSurfaceName( surface, surfaceName );\r
-       }\r
-       \r
-       /* return */\r
-       return surface;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoFreeSurface()\r
-frees a surface and all associated data\r
-*/\r
-void PicoFreeSurface( picoSurface_t *surface )\r
-{\r
-       int             i;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( surface == NULL )\r
-               return;\r
-       \r
-       /* free bits */\r
-       _pico_free( surface->xyz );\r
-       _pico_free( surface->normal );\r
-       _pico_free( surface->index );\r
-       _pico_free( surface->faceNormal );\r
-       \r
-       /* free arrays */\r
-       for( i = 0; i < surface->numSTArrays; i++ )\r
-               _pico_free( surface->st[ i ] );\r
-       free( surface->st );\r
-       for( i = 0; i < surface->numColorArrays; i++ )\r
-               _pico_free( surface->color[ i ] );\r
-       free( surface->color );\r
-       \r
-       /* free the surface */\r
-       _pico_free( surface );\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoAdjustSurface()\r
-adjusts a surface's memory allocations to handle the requested sizes.\r
-will always grow, never shrink\r
-*/\r
-\r
-int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals )\r
-{\r
-       int             i;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( surface == NULL )\r
-               return 0;\r
-       \r
-       /* bare minimums */\r
-       if( numVertexes < 1 )\r
-               numVertexes = 1;\r
-       if( numSTArrays < 1 )\r
-               numSTArrays = 1;\r
-       if( numColorArrays < 1 )\r
-               numColorArrays = 1;\r
-       if( numIndexes < 1 )\r
-               numIndexes = 1;\r
-       \r
-       /* additional vertexes? */\r
-       while( numVertexes > surface->maxVertexes ) /* fix */\r
-       {\r
-               surface->maxVertexes += PICO_GROW_VERTEXES;\r
-               if( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) )\r
-                       return 0;\r
-               if( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) )\r
-                       return 0;\r
-               for( i = 0; i < surface->numSTArrays; i++ )\r
-                       if( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) )\r
-                       return 0;\r
-               for( i = 0; i < surface->numColorArrays; i++ )\r
-                       if( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) )\r
-                       return 0;\r
-       }\r
-       \r
-       /* set vertex count to higher */\r
-       if( numVertexes > surface->numVertexes )\r
-               surface->numVertexes = numVertexes;\r
-       \r
-       /* additional st arrays? */\r
-       while( numSTArrays > surface->maxSTArrays ) /* fix */\r
-       {\r
-               surface->maxSTArrays += PICO_GROW_ARRAYS;\r
-               if( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) )\r
-                       return 0;\r
-               while( surface->numSTArrays < numSTArrays )\r
-               {\r
-                       surface->st[ surface->numSTArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );\r
-                       memset( surface->st[ surface->numSTArrays ], 0, surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );\r
-                       surface->numSTArrays++;\r
-               }\r
-       }\r
-       \r
-       /* additional color arrays? */\r
-       while( numColorArrays > surface->maxColorArrays ) /* fix */\r
-       {\r
-               surface->maxColorArrays += PICO_GROW_ARRAYS;\r
-               if( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) )\r
-                       return 0;\r
-               while( surface->numColorArrays < numColorArrays )\r
-               {\r
-                       surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );\r
-                       memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );\r
-                       surface->numColorArrays++;\r
-               }\r
-       }\r
-       \r
-       /* additional indexes? */\r
-       while( numIndexes > surface->maxIndexes ) /* fix */\r
-       {\r
-               surface->maxIndexes += PICO_GROW_INDEXES;\r
-               if( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) )\r
-                       return 0;\r
-       }\r
-       \r
-       /* set index count to higher */\r
-       if( numIndexes > surface->numIndexes )\r
-               surface->numIndexes = numIndexes;\r
-\r
-       /* additional face normals? */\r
-       while( numFaceNormals > surface->maxFaceNormals ) /* fix */\r
-       {\r
-               surface->maxFaceNormals += PICO_GROW_FACES;\r
-               if( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) )\r
-                       return 0;\r
-       }\r
-\r
-       /* set face normal count to higher */\r
-       if( numFaceNormals > surface->numFaceNormals )\r
-               surface->numFaceNormals = numFaceNormals;\r
-\r
-       /* return ok */\r
-       return 1;\r
-}\r
-\r
-\r
-/* PicoFindSurface:\r
- *   Finds first matching named surface in a model.\r
- */\r
-picoSurface_t *PicoFindSurface(\r
-       picoModel_t *model, char *name, int caseSensitive )\r
-{\r
-       int             i;\r
-\r
-       /* sanity check */\r
-       if( model == NULL || name == NULL )\r
-               return NULL;\r
-       \r
-       /* walk list */\r
-       for( i = 0; i < model->numSurfaces; i++ )\r
-       {\r
-               /* skip null surfaces or surfaces with null names */\r
-               if( model->surface[ i ] == NULL ||\r
-                       model->surface[ i ]->name == NULL )\r
-                       continue;\r
-\r
-               /* compare the surface name with name we're looking for */\r
-               if (caseSensitive) {\r
-                       if( !strcmp(name,model->surface[ i ]->name) )\r
-                               return model->surface[ i ];\r
-               } else {\r
-                       if( !_pico_stricmp(name,model->surface[ i ]->name) )\r
-                               return model->surface[ i ];\r
-               }\r
-       }\r
-       /* named surface not found */\r
-       return NULL;\r
-}\r
-\r
-\r
-\r
-/*----------------------------------------------------------------------------\r
-  PicoSet*() Setter Functions\r
-----------------------------------------------------------------------------*/\r
-\r
-void PicoSetModelName( picoModel_t *model, char *name )\r
-{\r
-       if( model == NULL || name == NULL )\r
-               return;\r
-       if( model->name != NULL )\r
-               _pico_free( model->name );\r
-\r
-       model->name = _pico_clone_alloc( name,-1 );\r
-}\r
-\r
-\r
-\r
-void PicoSetModelFileName( picoModel_t *model, char *fileName )\r
-{\r
-       if( model == NULL || fileName == NULL )\r
-               return;\r
-       if( model->fileName != NULL )\r
-               _pico_free( model->fileName );\r
-\r
-       model->fileName = _pico_clone_alloc( fileName,-1 );\r
-}\r
-\r
-\r
-\r
-void PicoSetModelFrameNum( picoModel_t *model, int frameNum )\r
-{\r
-       if( model == NULL )\r
-               return;\r
-       model->frameNum = frameNum;\r
-}\r
-\r
-\r
-\r
-void PicoSetModelNumFrames( picoModel_t *model, int numFrames )\r
-{\r
-       if( model == NULL )\r
-               return;\r
-       model->numFrames = numFrames;\r
-}\r
-\r
-\r
-\r
-void PicoSetModelData( picoModel_t *model, void *data )\r
-{\r
-       if( model == NULL )\r
-               return;\r
-       model->data = data;\r
-}\r
-\r
-\r
-\r
-void PicoSetShaderName( picoShader_t *shader, char *name )\r
-{\r
-       if( shader == NULL || name == NULL )\r
-               return;\r
-       if( shader->name != NULL )\r
-               _pico_free( shader->name );\r
-\r
-       shader->name = _pico_clone_alloc( name,-1 );\r
-}\r
-\r
-\r
-\r
-void PicoSetShaderMapName( picoShader_t *shader, char *mapName )\r
-{\r
-       if( shader == NULL || mapName == NULL )\r
-               return;\r
-       if( shader->mapName != NULL )\r
-               _pico_free( shader->mapName );\r
-\r
-       shader->mapName = _pico_clone_alloc( mapName,-1 );\r
-}\r
-\r
-\r
-\r
-void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color )\r
-{\r
-       if( shader == NULL || color == NULL )\r
-               return;\r
-       shader->ambientColor[ 0 ] = color[ 0 ];\r
-       shader->ambientColor[ 1 ] = color[ 1 ];\r
-       shader->ambientColor[ 2 ] = color[ 2 ];\r
-       shader->ambientColor[ 3 ] = color[ 3 ];\r
-}\r
-\r
-\r
-\r
-void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color )\r
-{\r
-       if( shader == NULL || color == NULL )\r
-               return;\r
-       shader->diffuseColor[ 0 ] = color[ 0 ];\r
-       shader->diffuseColor[ 1 ] = color[ 1 ];\r
-       shader->diffuseColor[ 2 ] = color[ 2 ];\r
-       shader->diffuseColor[ 3 ] = color[ 3 ];\r
-}\r
-\r
-\r
-\r
-void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color )\r
-{\r
-       if( shader == NULL || color == NULL )\r
-               return;\r
-       shader->specularColor[ 0 ] = color[ 0 ];\r
-       shader->specularColor[ 1 ] = color[ 1 ];\r
-       shader->specularColor[ 2 ] = color[ 2 ];\r
-       shader->specularColor[ 3 ] = color[ 3 ];\r
-}\r
-\r
-\r
-\r
-void PicoSetShaderTransparency( picoShader_t *shader, float value )\r
-{\r
-       if( shader == NULL )\r
-               return;\r
-       shader->transparency = value;\r
-\r
-       /* cap to 0..1 range */\r
-       if (shader->transparency < 0.0)\r
-               shader->transparency = 0.0;\r
-       if (shader->transparency > 1.0)\r
-               shader->transparency = 1.0;\r
-}\r
-\r
-\r
-\r
-void PicoSetShaderShininess( picoShader_t *shader, float value )\r
-{\r
-       if( shader == NULL )\r
-               return;\r
-       shader->shininess = value;\r
-\r
-       /* cap to 0..127 range */\r
-       if (shader->shininess < 0.0)\r
-               shader->shininess = 0.0;\r
-       if (shader->shininess > 127.0)\r
-               shader->shininess = 127.0;\r
-}\r
-\r
-\r
-\r
-void PicoSetSurfaceData( picoSurface_t *surface, void *data )\r
-{\r
-       if( surface == NULL )\r
-               return;\r
-       surface->data = data;\r
-}\r
-\r
-\r
-\r
-void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type )\r
-{\r
-       if( surface == NULL )\r
-               return;\r
-       surface->type = type;\r
-}\r
-\r
-\r
-\r
-void PicoSetSurfaceName( picoSurface_t *surface, char *name )\r
-{\r
-       if( surface == NULL || name == NULL )\r
-               return;\r
-       if( surface->name != NULL )\r
-               _pico_free( surface->name );\r
-\r
-       surface->name = _pico_clone_alloc( name,-1 );\r
-}\r
-\r
-\r
-\r
-void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader )\r
-{\r
-       if( surface == NULL )\r
-               return;\r
-       surface->shader = shader;\r
-}\r
-\r
-\r
-\r
-void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz )\r
-{\r
-       if( surface == NULL || num < 0 || xyz == NULL )\r
-               return;\r
-       if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) )\r
-               return;\r
-       _pico_copy_vec( xyz, surface->xyz[ num ] );\r
-       if( surface->model != NULL )\r
-               _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs );\r
-}\r
-\r
-\r
-\r
-void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal )\r
-{\r
-       if( surface == NULL || num < 0 || normal == NULL )\r
-               return;\r
-       if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) )\r
-               return;\r
-       _pico_copy_vec( normal, surface->normal[ num ] );\r
-}\r
-\r
-\r
-\r
-void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st )\r
-{\r
-       if( surface == NULL || num < 0 || st == NULL )\r
-               return;\r
-       if( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) )\r
-               return;\r
-       surface->st[ array ][ num ][ 0 ] = st[ 0 ];\r
-       surface->st[ array ][ num ][ 1 ] = st[ 1 ];\r
-}\r
-\r
-\r
-\r
-void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color )\r
-{\r
-       if( surface == NULL || num < 0 || color == NULL )\r
-               return;\r
-       if( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) )\r
-               return;\r
-       surface->color[ array ][ num ][ 0 ] = color[ 0 ];\r
-       surface->color[ array ][ num ][ 1 ] = color[ 1 ];\r
-       surface->color[ array ][ num ][ 2 ] = color[ 2 ];\r
-       surface->color[ array ][ num ][ 3 ] = color[ 3 ];\r
-}\r
-\r
-\r
-\r
-void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index )\r
-{\r
-       if( surface == NULL || num < 0 )\r
-               return;\r
-       if( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) )\r
-               return;\r
-       surface->index[ num ] = index;\r
-}\r
-\r
-\r
-\r
-void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count )\r
-{\r
-       if( num < 0 || index == NULL || count < 1 )\r
-               return;\r
-       if( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) )\r
-               return;\r
-       memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) );\r
-}\r
-\r
-\r
-\r
-void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal )\r
-{\r
-       if( surface == NULL || num < 0 || normal == NULL )\r
-               return;\r
-       if( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) )\r
-               return;\r
-       _pico_copy_vec( normal, surface->faceNormal[ num ] );\r
-}\r
-\r
-\r
-void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special )\r
-{\r
-       if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL )\r
-               return;\r
-       surface->special[ num ] = special;\r
-}\r
-\r
-\r
-\r
-/*----------------------------------------------------------------------------\r
-  PicoGet*() Getter Functions\r
-----------------------------------------------------------------------------*/\r
-\r
-char *PicoGetModelName( picoModel_t *model )\r
-{\r
-       if( model == NULL )\r
-               return NULL;\r
-       if( model->name == NULL)\r
-               return (char*) "";\r
-       return model->name;\r
-}\r
-\r
-\r
-\r
-char *PicoGetModelFileName( picoModel_t *model )\r
-{\r
-       if( model == NULL )\r
-               return NULL;\r
-       if( model->fileName == NULL)\r
-               return (char*) "";\r
-       return model->fileName;\r
-}\r
-\r
-\r
-\r
-int PicoGetModelFrameNum( picoModel_t *model )\r
-{\r
-       if( model == NULL )\r
-               return 0;\r
-       return model->frameNum;\r
-}\r
-\r
-\r
-\r
-int PicoGetModelNumFrames( picoModel_t *model )\r
-{\r
-       if( model == NULL )\r
-               return 0;\r
-       return model->numFrames;\r
-}\r
-\r
-\r
-\r
-void *PicoGetModelData( picoModel_t *model )\r
-{\r
-       if( model == NULL )\r
-               return NULL;\r
-       return model->data;\r
-}\r
-\r
-\r
-\r
-int PicoGetModelNumShaders( picoModel_t *model )\r
-{\r
-       if( model == NULL )\r
-               return 0;\r
-       return model->numShaders;\r
-}\r
-\r
-\r
-\r
-picoShader_t *PicoGetModelShader( picoModel_t *model, int num )\r
-{\r
-       /* a few sanity checks */\r
-       if( model == NULL )\r
-               return NULL;\r
-       if( model->shader == NULL)\r
-               return NULL;\r
-       if( num < 0 || num >= model->numShaders )\r
-               return NULL;\r
-       \r
-       /* return the shader */\r
-       return model->shader[ num ];\r
-}\r
-\r
-\r
-\r
-int PicoGetModelNumSurfaces( picoModel_t *model )\r
-{\r
-       if( model == NULL )\r
-               return 0;\r
-       return model->numSurfaces;\r
-}\r
-\r
-\r
-\r
-picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num )\r
-{\r
-       /* a few sanity checks */\r
-       if( model == NULL )\r
-               return NULL;\r
-       if( model->surface == NULL)\r
-               return NULL;\r
-       if( num < 0 || num >= model->numSurfaces )\r
-               return NULL;\r
-       \r
-       /* return the surface */\r
-       return model->surface[ num ];\r
-}\r
-\r
-\r
-\r
-int PicoGetModelTotalVertexes( picoModel_t *model )\r
-{\r
-       int             i, count;\r
-       \r
-       \r
-       if( model == NULL )\r
-               return 0;\r
-       if( model->surface == NULL )\r
-               return 0;\r
-       \r
-       count = 0;\r
-       for( i = 0; i < model->numSurfaces; i++ )\r
-                count += PicoGetSurfaceNumVertexes( model->surface[ i ] );\r
-       \r
-       return count;\r
-}\r
-\r
-\r
-\r
-int PicoGetModelTotalIndexes( picoModel_t *model )\r
-{\r
-       int             i, count;\r
-       \r
-       \r
-       if( model == NULL )\r
-               return 0;\r
-       if( model->surface == NULL )\r
-               return 0;\r
-       \r
-       count = 0;\r
-       for( i = 0; i < model->numSurfaces; i++ )\r
-                count += PicoGetSurfaceNumIndexes( model->surface[ i ] );\r
-       \r
-       return count;\r
-}\r
-\r
-\r
-\r
-char *PicoGetShaderName( picoShader_t *shader )\r
-{\r
-       if( shader == NULL )\r
-               return NULL;\r
-       if( shader->name == NULL)\r
-               return (char*) "";\r
-       return shader->name;\r
-}\r
-\r
-\r
-\r
-char *PicoGetShaderMapName( picoShader_t *shader )\r
-{\r
-       if( shader == NULL )\r
-               return NULL;\r
-       if( shader->mapName == NULL)\r
-               return (char*) "";\r
-       return shader->mapName;\r
-}\r
-\r
-\r
-\r
-picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader )\r
-{\r
-       if( shader == NULL )\r
-               return NULL;\r
-       return shader->ambientColor;\r
-}\r
-\r
-\r
-\r
-picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader )\r
-{\r
-       if( shader == NULL )\r
-               return NULL;\r
-       return shader->diffuseColor;\r
-}\r
-\r
-\r
-\r
-picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader )\r
-{\r
-       if( shader == NULL )\r
-               return NULL;\r
-       return shader->specularColor;\r
-}\r
-\r
-\r
-\r
-float PicoGetShaderTransparency( picoShader_t *shader )\r
-{\r
-       if( shader == NULL )\r
-               return 0.0f;\r
-       return shader->transparency;\r
-}\r
-\r
-\r
-\r
-float PicoGetShaderShininess( picoShader_t *shader )\r
-{\r
-       if( shader == NULL )\r
-               return 0.0f;\r
-       return shader->shininess;\r
-}\r
-\r
-\r
-\r
-void *PicoGetSurfaceData( picoSurface_t *surface )\r
-{\r
-       if( surface == NULL )\r
-               return NULL;\r
-       return surface->data;\r
-}\r
-\r
-\r
-\r
-picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface )\r
-{\r
-       if( surface == NULL )\r
-               return PICO_BAD;\r
-       return surface->type;\r
-}\r
-\r
-\r
-\r
-char *PicoGetSurfaceName( picoSurface_t *surface )\r
-{\r
-       if( surface == NULL )\r
-               return NULL;\r
-       if( surface->name == NULL )\r
-               return (char*) "";\r
-       return surface->name;\r
-}\r
-\r
-\r
-\r
-picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface )\r
-{\r
-       if( surface == NULL )\r
-               return NULL;\r
-       return surface->shader;\r
-}\r
-\r
-\r
-\r
-int PicoGetSurfaceNumVertexes( picoSurface_t *surface )\r
-{\r
-       if( surface == NULL )\r
-               return 0;\r
-       return surface->numVertexes;\r
-}\r
-\r
-\r
-\r
-picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num )\r
-{\r
-       if( surface == NULL || num < 0 || num > surface->numVertexes )\r
-               return NULL;\r
-       return surface->xyz[ num ];\r
-}\r
-\r
-\r
-\r
-picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num )\r
-{\r
-       if( surface == NULL || num < 0 || num > surface->numVertexes )\r
-               return NULL;\r
-       return surface->normal[ num ];\r
-}\r
-\r
-\r
-\r
-picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num  )\r
-{\r
-       if( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes )\r
-               return NULL;\r
-       return surface->st[ array ][ num ];\r
-}\r
-\r
-\r
-\r
-picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num )\r
-{\r
-       if( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes )\r
-               return NULL;\r
-       return surface->color[ array ][ num ];\r
-}\r
-\r
-\r
-\r
-int PicoGetSurfaceNumIndexes( picoSurface_t *surface )\r
-{\r
-       if( surface == NULL )\r
-               return 0;\r
-       return surface->numIndexes;\r
-}\r
-\r
-\r
-\r
-picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num )\r
-{\r
-       if( surface == NULL || num < 0 || num > surface->numIndexes )\r
-               return 0;\r
-       return surface->index[ num ];\r
-}\r
-\r
-\r
-\r
-picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num )\r
-{\r
-       if( surface == NULL || num < 0 || num > surface->numIndexes )\r
-               return NULL;\r
-       return &surface->index[ num ];\r
-}\r
-\r
-\r
-picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num )\r
-{\r
-       if( surface == NULL || num < 0 || num > surface->numFaceNormals )\r
-               return NULL;\r
-       return surface->faceNormal[ num ];\r
-}\r
-\r
-\r
-int PicoGetSurfaceSpecial( picoSurface_t *surface, int num )\r
-{\r
-       if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL )\r
-               return 0;\r
-       return surface->special[ num ];\r
-}\r
-\r
-\r
-\r
-/* ----------------------------------------------------------------------------\r
-hashtable related functions\r
----------------------------------------------------------------------------- */\r
-\r
-/* hashtable code for faster vertex lookups */\r
-//#define HASHTABLE_SIZE 32768 // 2048                 /* power of 2, use & */\r
-#define HASHTABLE_SIZE 7919 // 32749 // 2039   /* prime, use % */\r
-\r
-int PicoGetHashTableSize( void )\r
-{\r
-       return HASHTABLE_SIZE;\r
-}\r
-\r
-#define HASH_USE_EPSILON\r
-\r
-#ifdef HASH_USE_EPSILON\r
-#define HASH_XYZ_EPSILON                                       0.01f\r
-#define HASH_XYZ_EPSILONSPACE_MULTIPLIER       1.f / HASH_XYZ_EPSILON\r
-#define HASH_ST_EPSILON                                                0.0001f\r
-#define HASH_NORMAL_EPSILON                                    0.02f\r
-#endif\r
-\r
-unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz )\r
-{\r
-       unsigned int hash = 0;\r
-\r
-#ifndef HASH_USE_EPSILON\r
-       hash += ~(*((unsigned int*) &xyz[ 0 ]) << 15);\r
-       hash ^= (*((unsigned int*) &xyz[ 0 ]) >> 10);\r
-       hash += (*((unsigned int*) &xyz[ 1 ]) << 3);\r
-       hash ^= (*((unsigned int*) &xyz[ 1 ]) >> 6);\r
-       hash += ~(*((unsigned int*) &xyz[ 2 ]) << 11);\r
-       hash ^= (*((unsigned int*) &xyz[ 2 ]) >> 16);\r
-#else\r
-       picoVec3_t xyz_epsilonspace;\r
-\r
-       _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace );\r
-       xyz_epsilonspace[ 0 ] = (float)floor(xyz_epsilonspace[ 0 ]);\r
-       xyz_epsilonspace[ 1 ] = (float)floor(xyz_epsilonspace[ 1 ]);\r
-       xyz_epsilonspace[ 2 ] = (float)floor(xyz_epsilonspace[ 2 ]);\r
-\r
-       hash += ~(*((unsigned int*) &xyz_epsilonspace[ 0 ]) << 15);\r
-       hash ^= (*((unsigned int*) &xyz_epsilonspace[ 0 ]) >> 10);\r
-       hash += (*((unsigned int*) &xyz_epsilonspace[ 1 ]) << 3);\r
-       hash ^= (*((unsigned int*) &xyz_epsilonspace[ 1 ]) >> 6);\r
-       hash += ~(*((unsigned int*) &xyz_epsilonspace[ 2 ]) << 11);\r
-       hash ^= (*((unsigned int*) &xyz_epsilonspace[ 2 ]) >> 16);\r
-#endif\r
-\r
-       //hash = hash & (HASHTABLE_SIZE-1);\r
-       hash = hash % (HASHTABLE_SIZE);\r
-       return hash;\r
-}\r
-\r
-picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void )\r
-{\r
-       picoVertexCombinationHash_t     **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) );\r
-\r
-       memset( hashTable, 0, HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) );\r
-\r
-       return hashTable;\r
-}\r
-\r
-void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable )\r
-{\r
-       int                                                     i;\r
-       picoVertexCombinationHash_t     *vertexCombinationHash;\r
-       picoVertexCombinationHash_t *nextVertexCombinationHash;\r
-\r
-       /* dummy check */\r
-       if (hashTable == NULL)\r
-               return;\r
-\r
-       for( i = 0; i < HASHTABLE_SIZE; i++ )\r
-       {\r
-               if (hashTable[ i ])\r
-               {\r
-                       nextVertexCombinationHash = NULL;\r
-\r
-                       for( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash )\r
-                       {\r
-                               nextVertexCombinationHash = vertexCombinationHash->next;\r
-                               if (vertexCombinationHash->data != NULL)\r
-                               {\r
-                                       _pico_free( vertexCombinationHash->data );\r
-                               }\r
-                               _pico_free( vertexCombinationHash );\r
-                       }\r
-               }\r
-       }\r
-\r
-       _pico_free( hashTable );\r
-}\r
-\r
-picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color )\r
-{\r
-       unsigned int                            hash;\r
-       picoVertexCombinationHash_t     *vertexCombinationHash;\r
-\r
-       /* dumy check */\r
-       if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL )\r
-               return NULL;\r
-\r
-       hash = PicoVertexCoordGenerateHash( xyz );\r
-\r
-       for( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next )\r
-       {\r
-#ifndef HASH_USE_EPSILON\r
-               /* check xyz */\r
-               if( (vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ]) )\r
-                       continue;\r
-\r
-               /* check normal */\r
-               if( (vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ]) )\r
-                       continue;\r
-               \r
-               /* check st */\r
-               if( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] )\r
-                       continue;\r
-#else\r
-               /* check xyz */\r
-               if( ( fabs(xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ]) ) > HASH_XYZ_EPSILON ||\r
-                       ( fabs(xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ]) ) > HASH_XYZ_EPSILON ||\r
-                       ( fabs(xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ]) ) > HASH_XYZ_EPSILON )\r
-                       continue;\r
-\r
-               /* check normal */\r
-               if( ( fabs(normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ]) ) > HASH_NORMAL_EPSILON ||\r
-                       ( fabs(normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ]) ) > HASH_NORMAL_EPSILON ||\r
-                       ( fabs(normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ]) ) > HASH_NORMAL_EPSILON )\r
-                       continue;\r
-               \r
-               /* check st */\r
-               if( ( fabs(st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ]) ) > HASH_ST_EPSILON ||\r
-                       ( fabs(st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ]) ) > HASH_ST_EPSILON )\r
-                       continue;\r
-#endif\r
-\r
-               /* check color */\r
-               if( *((int*) vertexCombinationHash->vcd.color) != *((int*) color) )\r
-                       continue;\r
-\r
-               /* gotcha */\r
-               return vertexCombinationHash;\r
-       }\r
-\r
-       return NULL;\r
-}\r
-\r
-picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index )\r
-{\r
-       unsigned int                            hash;\r
-       picoVertexCombinationHash_t     *vertexCombinationHash;\r
-\r
-       /* dumy check */\r
-       if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL )\r
-               return NULL;\r
-\r
-       vertexCombinationHash = _pico_alloc( sizeof(picoVertexCombinationHash_t) );\r
-\r
-       if (!vertexCombinationHash)\r
-               return NULL;\r
-\r
-       hash = PicoVertexCoordGenerateHash( xyz );\r
-\r
-       _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz );\r
-       _pico_copy_vec( normal, vertexCombinationHash->vcd.normal );\r
-       _pico_copy_vec2( st, vertexCombinationHash->vcd.st );\r
-       _pico_copy_color( color, vertexCombinationHash->vcd.color );\r
-       vertexCombinationHash->index = index;\r
-       vertexCombinationHash->data = NULL;\r
-       vertexCombinationHash->next = hashTable[ hash ];\r
-       hashTable[ hash ] = vertexCombinationHash;\r
-\r
-       return vertexCombinationHash;\r
-}\r
-\r
-/* ----------------------------------------------------------------------------\r
-specialized routines\r
----------------------------------------------------------------------------- */\r
-\r
-/*\r
-PicoFindSurfaceVertex()\r
-finds a vertex matching the set parameters\r
-fixme: needs non-naive algorithm\r
-*/\r
-\r
-int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color )\r
-{\r
-       int             i, j;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( surface == NULL || surface->numVertexes <= 0 )\r
-               return -1;\r
-       \r
-       /* walk vertex list */\r
-       for( i = 0; i < surface->numVertexes; i++ )\r
-       {\r
-               /* check xyz */\r
-               if( xyz != NULL && (surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ]) )\r
-                       continue;\r
-               \r
-               /* check normal */\r
-               if( normal != NULL && (surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ]) )\r
-                       continue;\r
-               \r
-               /* check st */\r
-               if( numSTs > 0 && st != NULL )\r
-               {\r
-                       for( j = 0; j < numSTs; j++ )\r
-                       {\r
-                               if( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] )\r
-                                       break;\r
-                       }\r
-                       if( j != numSTs )\r
-                               continue;\r
-               }\r
-               \r
-               /* check color */\r
-               if( numColors > 0 && color != NULL )\r
-               {\r
-                       for( j = 0; j < numSTs; j++ )\r
-                       {\r
-                               if( *((int*) surface->color[ j ]) != *((int*) color[ j ]) )\r
-                                       break;\r
-                       }\r
-                       if( j != numColors )\r
-                               continue;\r
-               }\r
-               \r
-               /* vertex matches */\r
-               return i;\r
-       }\r
-       \r
-       /* nada */\r
-       return -1;\r
-}\r
-\r
-\r
-\r
-/*\r
-PicoFixSurfaceNormals()\r
-fixes broken normals (certain formats bork normals)\r
-*/\r
-\r
-#define MAX_NORMAL_VOTES               128\r
-#define EQUAL_NORMAL_EPSILON   0.01\r
-#define BAD_NORMAL_EPSILON             0.5\r
-\r
-void PicoFixSurfaceNormals( picoSurface_t *surface )\r
-{\r
-       int                             i, j, k, a, b, c, numVotes, faceIndex;\r
-       picoVec3_t              votes[ MAX_NORMAL_VOTES ];\r
-       picoVec3_t              *normals, diff;\r
-       picoVec4_t              plane;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( surface == NULL || surface->numVertexes == 0 )\r
-               return;\r
-       \r
-       /* fixme: handle other surface types */\r
-       if( surface->type != PICO_TRIANGLES )\r
-               return;\r
-       \r
-       /* allocate normal storage */\r
-       normals = _pico_alloc( surface->numVertexes * sizeof( *normals ) );\r
-       if( normals == NULL )\r
-       {\r
-               _pico_printf( PICO_ERROR, "PicoFixSurfaceNormals: Unable to allocate memory for temporary normal storage" );\r
-               return;\r
-       }\r
-       \r
-       /* zero it out */\r
-       memset( normals, 0, surface->numVertexes * sizeof( *normals ) );\r
-       \r
-       /* walk vertex list */\r
-       for( i = 0; i < surface->numVertexes; i++ )\r
-       {\r
-               /* zero out votes */\r
-               numVotes = 0;\r
-               \r
-               /* find all the triangles that reference this vertex */\r
-               for( j = 0, faceIndex = 0; j < surface->numIndexes; j += 3, faceIndex++ )\r
-               {\r
-                       /* get triangle */\r
-                       a = surface->index[ j ];\r
-                       b = surface->index[ j + 1 ];\r
-                       c = surface->index[ j + 2 ];\r
-                       \r
-                       /* ignore degenerate triangles */\r
-                       if( a == b || b == c || c == a )\r
-                               continue;\r
-                       \r
-                       /* ignore indexes out of range */\r
-                       if( a < 0 || a >= surface->numVertexes ||\r
-                               b < 0 || b >= surface->numVertexes ||\r
-                               c < 0 || c >= surface->numVertexes )\r
-                               continue;\r
-                       \r
-                       /* test triangle */\r
-                       if( a == i || b == i || c == i )\r
-                       {\r
-                               /* if this surface has face normals */\r
-                               if( surface->numFaceNormals && faceIndex < surface->numFaceNormals )\r
-                               {\r
-                                       _pico_copy_vec( surface->faceNormal[ faceIndex ], plane );\r
-                                       if( plane[ 0 ] == 0.f && plane[ 1 ] == 0.f && plane[ 2 ] == 0.f )\r
-                                       {\r
-                                               /* if null normal, make plane from the 3 points */\r
-                                               if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 )\r
-                                               {\r
-                                                       continue;\r
-                                               }\r
-                                       }\r
-                               }\r
-                               /* make a plane from the 3 points */\r
-                               else if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 )\r
-                               {\r
-                                       continue;\r
-                               }\r
-\r
-                               /* see if this normal has already been voted */\r
-                               for( k = 0; k < numVotes; k++ )\r
-                               {\r
-                                       _pico_subtract_vec( plane, votes[ k ], diff );\r
-                                       if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&\r
-                                               fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&\r
-                                               fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON )\r
-                                               break;\r
-                               }\r
-                               \r
-                               /* add a new vote? */\r
-                               if( k == numVotes && numVotes < MAX_NORMAL_VOTES )\r
-                               {\r
-                                       _pico_copy_vec( plane, votes[ numVotes ] );\r
-                                       numVotes++;\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               /* tally votes */\r
-               if( numVotes > 0 )\r
-               {\r
-                       /* create average normal */\r
-                       _pico_zero_vec( normals[ i ] );\r
-                       for( k = 0; k < numVotes; k++ )\r
-                               _pico_add_vec( normals[ i ], votes[ k ], normals[ i ] );\r
-                       \r
-                       /* normalize it */\r
-                       if( _pico_normalize_vec( normals[ i ] ) )\r
-                       {\r
-                               /* test against actual normal */\r
-                               if( fabs( _pico_dot_vec( normals[ i ], surface->normal[ i ] ) - 1 ) > BAD_NORMAL_EPSILON )\r
-                               {\r
-                                       //%     printf( "Normal %8d: (%f %f %f) -> (%f %f %f)\n", i,\r
-                                       //%             surface->normal[ i ][ 0 ], surface->normal[ i ][ 1 ], surface->normal[ i ][ 2 ],\r
-                                       //%             normals[ i ][ 0 ], normals[ i ][ 1 ], normals[ i ][ 2 ] );\r
-                                       _pico_copy_vec( normals[ i ], surface->normal[ i ] );\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       \r
-       /* free normal storage */\r
-       _pico_free( normals );\r
-}\r
-\r
-\r
-\r
-\r
-/*\r
-PicoRemapModel() - sea\r
-remaps model material/etc. information using the remappings\r
-contained in the given 'remapFile' (full path to the ascii file to open)\r
-returns 1 on success or 0 on error\r
-*/\r
-\r
-#define _prm_error_return \\r
-{ \\r
-       _pico_free_parser( p ); \\r
-       _pico_free_file( remapBuffer ); \\r
-       return 0; \\r
-}\r
-\r
-int PicoRemapModel( picoModel_t *model, char *remapFile )\r
-{\r
-       picoParser_t    *p;\r
-       picoByte_t              *remapBuffer;\r
-       int                             remapBufSize;\r
-       \r
-       \r
-       /* sanity checks */\r
-       if( model == NULL || remapFile == NULL )\r
-               return 0;\r
-       \r
-       /* load remap file contents */\r
-       _pico_load_file( remapFile,&remapBuffer,&remapBufSize );\r
-       \r
-       /* check result */\r
-       if( remapBufSize == 0 )\r
-               return 1;       /* file is empty: no error */\r
-       if( remapBufSize < 0 )\r
-               return 0;       /* load failed: error */\r
-       \r
-       /* create a new pico parser */\r
-       p = _pico_new_parser( remapBuffer, remapBufSize );\r
-       if (p == NULL)\r
-       {\r
-               /* ram is really cheap nowadays... */\r
-               _prm_error_return;\r
-       }\r
-       \r
-       /* doo teh parse */\r
-       while( 1 )\r
-       {\r
-               /* get next token in remap file */\r
-               if (!_pico_parse( p,1 ))\r
-                       break;\r
-\r
-               /* skip over c++ style comment lines */\r
-               if (!_pico_stricmp(p->token,"//"))\r
-               {\r
-                       _pico_parse_skip_rest( p );\r
-                       continue;\r
-               }\r
-               \r
-               /* block for quick material shader name remapping */\r
-               /* materials { "m" (=>|->|=) "s" } */\r
-               if( !_pico_stricmp(p->token, "materials" ) )\r
-               {\r
-                       int level = 1;\r
-\r
-                       /* check bracket */\r
-                       if (!_pico_parse_check( p,1,"{" ))\r
-                               _prm_error_return;\r
-\r
-                       /* process assignments */\r
-                       while( 1 )\r
-                       {\r
-                               picoShader_t    *shader;\r
-                               char                    *materialName;\r
-                               \r
-                               \r
-                               /* get material name */\r
-                               if (_pico_parse( p,1 ) == NULL) break;\r
-                               if (!strlen(p->token)) continue;\r
-                               materialName = _pico_clone_alloc( p->token,-1 );\r
-                               if (materialName == NULL)\r
-                                       _prm_error_return;\r
-\r
-                               /* handle levels */\r
-                               if (p->token[0] == '{') level++;\r
-                               if (p->token[0] == '}') level--;\r
-                               if (!level) break;\r
-\r
-                               /* get next token (assignment token or shader name) */\r
-                               if (!_pico_parse( p,0 ))\r
-                               {\r
-                                       _pico_free( materialName );\r
-                                       _prm_error_return;\r
-                               }\r
-                               /* skip assignment token (if present) */\r
-                               if (!strcmp(p->token,"=>") ||\r
-                                       !strcmp(p->token,"->") ||\r
-                                       !strcmp(p->token,"="))\r
-                               {\r
-                                       /* simply grab the next token */\r
-                                       if (!_pico_parse( p,0 ))\r
-                                       {\r
-                                               _pico_free( materialName );\r
-                                               _prm_error_return;\r
-                                       }\r
-                               }\r
-                               /* try to find material by name */\r
-                               shader = PicoFindShader( model,materialName,0 );\r
-\r
-                               /* we've found a material matching the name */\r
-                               if (shader != NULL)\r
-                               {\r
-                                       PicoSetShaderName( shader,p->token );\r
-                               }\r
-                               /* free memory used by material name */\r
-                               _pico_free( materialName );\r
-\r
-                               /* skip rest */\r
-                               _pico_parse_skip_rest( p );\r
-                       }\r
-               }\r
-               /* block for detailed single material remappings */\r
-               /* materials[ "m" ] { key data... } */\r
-               else if (!_pico_stricmp(p->token,"materials["))\r
-               {\r
-                       picoShader_t *shader;\r
-                       char *tempMaterialName;\r
-                       int level = 1;\r
-\r
-                       /* get material name */\r
-                       if (!_pico_parse( p,0 ))\r
-                               _prm_error_return;\r
-\r
-                       /* temporary copy of material name */\r
-                       tempMaterialName = _pico_clone_alloc( p->token,-1 );\r
-                       if (tempMaterialName == NULL)\r
-                               _prm_error_return;\r
-\r
-                       /* check square closing bracket */\r
-                       if (!_pico_parse_check( p,0,"]" ))\r
-                               _prm_error_return;                      \r
-\r
-                       /* try to find material by name */\r
-                       shader = PicoFindShader( model,tempMaterialName,0 );\r
-\r
-                       /* free memory used by temporary material name */\r
-                       _pico_free( tempMaterialName );\r
-\r
-                       /* we haven't found a material matching the name */\r
-                       /* so we simply skip the braced section now and */\r
-                       /* continue parsing with the next main token */\r
-                       if (shader == NULL)\r
-                       {\r
-                               _pico_parse_skip_braced( p );\r
-                               continue;\r
-                       }\r
-                       /* check opening bracket */\r
-                       if (!_pico_parse_check( p,1,"{" ))\r
-                               _prm_error_return;\r
-\r
-                       /* process material info keys */\r
-                       while( 1 )\r
-                       {\r
-                               /* get key name */\r
-                               if (_pico_parse( p,1 ) == NULL) break;\r
-                               if (!strlen(p->token)) continue;\r
-\r
-                               /* handle levels */\r
-                               if (p->token[0] == '{') level++;\r
-                               if (p->token[0] == '}') level--;\r
-                               if (!level) break;\r
-\r
-                               /* remap shader name */\r
-                               if (!_pico_stricmp(p->token,"shader"))\r
-                               {\r
-                                       if (!_pico_parse( p,0 )) _prm_error_return;\r
-                                       PicoSetShaderName( shader,p->token );\r
-                               }\r
-                               /* remap shader map name */\r
-                               else if (!_pico_stricmp(p->token,"mapname"))\r
-                               {\r
-                                       if (!_pico_parse( p,0 )) _prm_error_return;\r
-                                       PicoSetShaderMapName( shader,p->token );\r
-                               }\r
-                               /* remap shader's ambient color */\r
-                               else if (!_pico_stricmp(p->token,"ambient"))\r
-                               {\r
-                                       picoColor_t color;\r
-                                       picoVec3_t  v;\r
-\r
-                                       /* get vector from parser */\r
-                                       if (!_pico_parse_vec( p,v )) _prm_error_return;\r
-\r
-                                       /* store as color */\r
-                                       color[ 0 ] = (picoByte_t)v[ 0 ];\r
-                                       color[ 1 ] = (picoByte_t)v[ 1 ];\r
-                                       color[ 2 ] = (picoByte_t)v[ 2 ];\r
-\r
-                                       /* set new ambient color */\r
-                                       PicoSetShaderAmbientColor( shader,color );\r
-                               }\r
-                               /* remap shader's diffuse color */\r
-                               else if (!_pico_stricmp(p->token,"diffuse"))\r
-                               {\r
-                                       picoColor_t color;\r
-                                       picoVec3_t  v;\r
-\r
-                                       /* get vector from parser */\r
-                                       if (!_pico_parse_vec( p,v )) _prm_error_return;\r
-\r
-                                       /* store as color */\r
-                                       color[ 0 ] = (picoByte_t)v[ 0 ];\r
-                                       color[ 1 ] = (picoByte_t)v[ 1 ];\r
-                                       color[ 2 ] = (picoByte_t)v[ 2 ];\r
-\r
-                                       /* set new ambient color */\r
-                                       PicoSetShaderDiffuseColor( shader,color );\r
-                               }\r
-                               /* remap shader's specular color */\r
-                               else if (!_pico_stricmp(p->token,"specular"))\r
-                               {\r
-                                       picoColor_t color;\r
-                                       picoVec3_t  v;\r
-\r
-                                       /* get vector from parser */\r
-                                       if (!_pico_parse_vec( p,v )) _prm_error_return;\r
-\r
-                                       /* store as color */\r
-                                       color[ 0 ] = (picoByte_t)v[ 0 ];\r
-                                       color[ 1 ] = (picoByte_t)v[ 1 ];\r
-                                       color[ 2 ] = (picoByte_t)v[ 2 ];\r
-\r
-                                       /* set new ambient color */\r
-                                       PicoSetShaderSpecularColor( shader,color );\r
-                               }\r
-                               /* skip rest */\r
-                               _pico_parse_skip_rest( p );\r
-                       }\r
-               }\r
-               /* end 'materials[' */\r
-       }\r
-       \r
-       /* free both parser and file buffer */\r
-       _pico_free_parser( p );\r
-       _pico_free_file( remapBuffer );\r
-\r
-       /* return with success */\r
-       return 1;\r
-}\r
-\r
-\r
-/*\r
-PicoAddTriangleToModel() - jhefty\r
-A nice way to add individual triangles to the model.\r
-Chooses an appropriate surface based on the shader, or adds a new surface if necessary\r
-*/\r
-\r
-void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, \r
-                                                       int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors,\r
-                                                       picoShader_t* shader )\r
-{\r
-       int i,j;\r
-       int vertDataIndex;\r
-       picoSurface_t* workSurface = NULL;\r
-\r
-       /* see if a surface already has the shader */\r
-       for ( i = 0 ; i < model->numSurfaces ; i++ )\r
-       {\r
-               workSurface = model->surface[i];\r
-               if ( workSurface->shader == shader )\r
-               {                       \r
-                       break;\r
-               }\r
-       }\r
-\r
-       /* no surface uses this shader yet, so create a new surface */\r
-       if ( !workSurface || i >=model->numSurfaces )\r
-       {\r
-               /* create a new surface in the model for the unique shader */\r
-               workSurface = PicoNewSurface(model);\r
-               if ( !workSurface )\r
-               {\r
-                       _pico_printf ( PICO_ERROR , "Could not allocate a new surface!\n" );\r
-                       return;\r
-               }\r
-\r
-               /* do surface setup */\r
-               PicoSetSurfaceType( workSurface, PICO_TRIANGLES );\r
-               PicoSetSurfaceName( workSurface, shader->name );\r
-               PicoSetSurfaceShader( workSurface, shader );\r
-       }\r
-\r
-       /* add the triangle data to the surface */\r
-       for ( i = 0 ; i < 3 ; i++ )     \r
-       {\r
-               /* get the next free spot in the index array */\r
-               int newVertIndex = PicoGetSurfaceNumIndexes ( workSurface );\r
-\r
-               /* get the index of the vertex that we're going to store at newVertIndex */\r
-               vertDataIndex = PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i]);\r
-\r
-               /* the vertex wasn't found, so create a new vertex in the pool from the data we have */\r
-               if ( vertDataIndex == -1 )\r
-               {                       \r
-                       /* find the next spot for a new vertex */\r
-                       vertDataIndex = PicoGetSurfaceNumVertexes ( workSurface );                      \r
-\r
-                       /* assign the data to it */\r
-                       PicoSetSurfaceXYZ ( workSurface ,vertDataIndex , *xyz[i] );\r
-                       PicoSetSurfaceNormal ( workSurface , vertDataIndex , *normals[i] );                     \r
-\r
-                       /* make sure to copy over all available ST's and colors for the vertex */\r
-                       for ( j = 0 ; j < numColors ; j++ )\r
-                       {\r
-                               PicoSetSurfaceColor( workSurface , j , vertDataIndex , colors[i][j] );\r
-                       }\r
-                       for ( j = 0 ; j < numSTs ; j++ )\r
-                       {\r
-                               PicoSetSurfaceST ( workSurface , j , vertDataIndex , st[i][j] );\r
-                       }\r
-               }\r
-\r
-               /* add this vertex to the triangle */           \r
-               PicoSetSurfaceIndex ( workSurface , newVertIndex , vertDataIndex );\r
-       }       \r
-}\r
+/* -----------------------------------------------------------------------------
+
+PicoModel Library
+
+Copyright (c) 2002, Randy Reddig & seaw0lf
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+Neither the names of the copyright holders nor the names of its contributors may
+be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#define PICOMODEL_C
+
+
+
+/* dependencies */
+#include "picointernal.h"
+
+
+
+/*
+PicoInit()
+initializes the picomodel library
+*/
+
+int PicoInit( void )
+{
+       /* successfully initialized -sea */
+       return 1;
+}
+
+
+
+/*
+PicoShutdown()
+shuts the pico model library down
+*/
+
+void PicoShutdown( void )
+{
+       /* do something interesting here in the future */
+       return;
+}
+
+
+
+/*
+PicoError()
+returns last picomodel error code (see PME_* defines)
+*/
+
+int PicoError( void )
+{
+       /* todo: do something here */
+       return 0;
+}
+
+
+
+/*
+PicoSetMallocFunc()
+sets the ptr to the malloc function
+*/
+
+void PicoSetMallocFunc( void *(*func)( size_t ) )
+{
+       if( func != NULL )
+               _pico_ptr_malloc = func;
+}
+
+
+
+/*
+PicoSetFreeFunc()
+sets the ptr to the free function
+*/
+
+void PicoSetFreeFunc( void (*func)( void* ) )
+{
+       if( func != NULL )
+               _pico_ptr_free = func;
+}
+
+
+
+/*
+PicoSetLoadFileFunc()
+sets the ptr to the file load function
+*/
+
+void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) )
+{
+       if( func != NULL )
+               _pico_ptr_load_file = func;
+}
+
+
+
+/*
+PicoSetFreeFileFunc()
+sets the ptr to the free function
+*/
+
+void PicoSetFreeFileFunc( void (*func)( void* ) )
+{
+       if( func != NULL )
+               _pico_ptr_free_file = func;
+}
+
+
+
+/*
+PicoSetPrintFunc()
+sets the ptr to the print function
+*/
+
+void PicoSetPrintFunc( void (*func)( int, const char* ) )
+{
+       if( func != NULL )
+               _pico_ptr_print = func;
+}
+
+
+
+/*
+PicoLoadModel()
+the meat and potatoes function
+*/
+
+picoModel_t    *PicoLoadModel( char *fileName, int frameNum )
+{
+       const picoModule_t      **modules, *pm;
+       picoModel_t                     *model;
+       picoByte_t                      *buffer;
+       int                                     bufSize;
+       char                            *modelFileName, *remapFileName;
+
+       
+       /* init */
+       model = NULL;
+       
+       /* make sure we've got a file name */
+       if( fileName == NULL )
+       {
+               _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" );
+               return NULL;
+       }
+       
+       /* load file data (buffer is allocated by host app) */
+       _pico_load_file( fileName, &buffer, &bufSize );
+       if( bufSize < 0 )
+       {
+               _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName );
+               return NULL;
+       }
+
+       /* get ptr to list of supported modules */
+       modules = PicoModuleList( NULL );
+       
+       /* run it through the various loader functions and try */
+       /* to find a loader that fits the given file data */
+       for( ; *modules != NULL; modules++ )
+       {
+               /* get module */
+               pm = *modules;
+               
+               /* sanity check */
+               if( pm == NULL)
+                       break;
+
+               /* module must be able to load */
+               if( pm->canload == NULL || pm->load == NULL )
+                       continue;
+               
+               /* see whether this module can load the model file or not */
+               if( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK )
+               {
+                       /* use loader provided by module to read the model data */
+                       model = pm->load( fileName, frameNum, buffer, bufSize );
+                       if( model == NULL )
+                       {
+                               _pico_free_file( buffer );
+                               return NULL;
+                       }
+                       
+                       /* assign pointer to file format module */
+                       model->module = pm;
+                       
+                       /* get model file name */
+                       modelFileName = PicoGetModelFileName( model );
+                       
+                       /* apply model remappings from <model>.remap */
+                       if( strlen( modelFileName ) )
+                       {
+                               /* alloc copy of model file name */
+                               remapFileName = _pico_alloc( strlen( modelFileName ) + 20 );
+                               if( remapFileName != NULL )
+                               {
+                                       /* copy model file name and change extension */
+                                       strcpy( remapFileName, modelFileName );
+                                       _pico_setfext( remapFileName, "remap" );
+
+                                       /* try to remap model; we don't handle the result */
+                                       PicoRemapModel( model, remapFileName );
+
+                                       /* free the remap file name string */
+                                       _pico_free( remapFileName );
+                               }
+                       }
+                       
+                       /* model was loaded, so break out of loop */
+                       break;
+               }
+       }
+       
+       /* free memory used by file buffer */
+       if( buffer)
+               _pico_free_file( buffer );
+
+       /* return */
+       return model;
+}
+
+
+
+/* ----------------------------------------------------------------------------
+models
+---------------------------------------------------------------------------- */
+
+/*
+PicoNewModel()
+creates a new pico model
+*/
+
+picoModel_t *PicoNewModel( void )
+{
+       picoModel_t     *model;
+       
+       /* allocate */
+       model = _pico_alloc( sizeof(picoModel_t) );
+       if( model == NULL )
+               return NULL;
+
+       /* clear */
+       memset( model,0,sizeof(picoModel_t) );
+       
+       /* model set up */
+       _pico_zero_bounds( model->mins,model->maxs );
+
+       /* set initial frame count to 1 -sea */
+       model->numFrames = 1;
+
+       /* return ptr to new model */
+       return model;
+}
+
+
+
+/*
+PicoFreeModel()
+frees a model and all associated data
+*/
+
+void PicoFreeModel( picoModel_t *model )
+{
+       int                             i;
+       
+
+       /* sanity check */
+       if( model == NULL )
+               return;
+       
+       /* free bits */
+       if( model->name )
+               _pico_free( model->name );
+       
+       /* free shaders */
+       for( i = 0; i < model->numShaders; i++ )
+               PicoFreeShader( model->shader[ i ] );
+       free( model->shader );
+       
+       /* free surfaces */
+       for( i = 0; i < model->numSurfaces; i++ )
+               PicoFreeSurface( model->surface[ i ] );
+       free( model->surface );
+       
+       /* free the model */
+       _pico_free( model );
+}
+
+
+
+/*
+PicoAdjustModel()
+adjusts a models's memory allocations to handle the requested sizes.
+will always grow, never shrink
+*/
+
+int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces )
+{
+       /* dummy check */
+       if( model == NULL )
+               return 0;
+       
+       /* bare minimums */
+       /* sea: null surface/shader fix (1s=>0s) */
+       if( numShaders < 0 )
+               numShaders = 0;
+       if( numSurfaces < 0 )
+               numSurfaces = 0;
+
+       /* additional shaders? */
+       while( numShaders > model->maxShaders )
+       {
+               model->maxShaders += PICO_GROW_SHADERS;
+               if( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) )
+                       return 0;
+       }
+       
+       /* set shader count to higher */
+       if( numShaders > model->numShaders )
+               model->numShaders = numShaders;
+       
+       /* additional surfaces? */
+       while( numSurfaces > model->maxSurfaces )
+       {
+               model->maxSurfaces += PICO_GROW_SURFACES;
+               if( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) )
+                       return 0;
+       }
+       
+       /* set shader count to higher */
+       if( numSurfaces > model->numSurfaces )
+               model->numSurfaces = numSurfaces;
+       
+       /* return ok */
+       return 1;
+}
+
+
+
+/* ----------------------------------------------------------------------------
+shaders
+---------------------------------------------------------------------------- */
+
+/*
+PicoNewShader()
+creates a new pico shader and returns its index. -sea
+*/
+
+picoShader_t *PicoNewShader( picoModel_t *model )
+{
+       picoShader_t    *shader;
+       
+
+       /* allocate and clear */
+       shader = _pico_alloc( sizeof(picoShader_t) );
+       if( shader == NULL )
+               return NULL;
+       memset( shader, 0, sizeof(picoShader_t) );
+       
+       /* attach it to the model */
+       if( model != NULL )
+       {
+               /* adjust model */
+               if( !PicoAdjustModel( model, model->numShaders + 1, 0 ) )
+               {
+                       _pico_free( shader );
+                       return NULL;
+               }
+               /* attach */
+               model->shader[ model->numShaders - 1 ] = shader;
+               shader->model = model;
+       }
+       /* setup default shader colors */
+       _pico_set_color( shader->ambientColor,0,0,0,0 );
+       _pico_set_color( shader->diffuseColor,255,255,255,1 );
+       _pico_set_color( shader->specularColor,0,0,0,0 );
+
+       /* no need to do this, but i do it anyway */
+       shader->transparency = 0;
+       shader->shininess = 0;
+
+       /* return the newly created shader */
+       return shader;
+}
+
+
+
+/*
+PicoFreeShader()
+frees a shader and all associated data -sea
+*/
+
+void PicoFreeShader( picoShader_t *shader )
+{
+       /* dummy check */
+       if( shader == NULL )
+               return;
+       
+       /* free bits */
+       if( shader->name )
+               _pico_free( shader->name );
+       if( shader->mapName )
+               _pico_free( shader->mapName );
+       
+       /* free the shader */
+       _pico_free( shader );
+}
+
+
+
+/*
+PicoFindShader()
+finds a named shader in a model
+*/
+
+picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive )
+{
+       int             i;
+       
+       
+       /* sanity checks */
+       if( model == NULL || name == NULL )     /* sea: null name fix */
+               return NULL;
+       
+       /* walk list */
+       for( i = 0; i < model->numShaders; i++ )
+       {
+               /* skip null shaders or shaders with null names */
+               if( model->shader[ i ] == NULL ||
+                       model->shader[ i ]->name == NULL )
+                       continue;
+
+               /* compare the shader name with name we're looking for */
+               if( caseSensitive )
+               {
+                       if( !strcmp( name, model->shader[ i ]->name ) )
+                               return model->shader[ i ];
+               }
+               else if( !_pico_stricmp( name, model->shader[ i ]->name ) )
+                               return model->shader[ i ];
+       }
+       
+       /* named shader not found */
+       return NULL;
+}
+
+
+
+/* ----------------------------------------------------------------------------
+surfaces
+---------------------------------------------------------------------------- */
+
+/*
+PicoNewSurface()
+creates a new pico surface
+*/
+
+picoSurface_t *PicoNewSurface( picoModel_t *model )
+{
+       picoSurface_t   *surface;
+       char surfaceName[64];
+       
+       /* allocate and clear */
+       surface = _pico_alloc( sizeof( *surface ) );
+       if( surface == NULL )
+               return NULL;
+       memset( surface, 0, sizeof( *surface ) );
+       
+       /* attach it to the model */
+       if( model != NULL )
+       {
+               /* adjust model */
+               if( !PicoAdjustModel( model, 0, model->numSurfaces + 1 ) )
+               {
+                       _pico_free( surface );
+                       return NULL;
+               }
+               
+               /* attach */
+               model->surface[ model->numSurfaces - 1 ] = surface;
+               surface->model = model;
+               
+               /* set default name */
+               sprintf( surfaceName, "Unnamed_%d", model->numSurfaces );
+               PicoSetSurfaceName( surface, surfaceName );
+       }
+       
+       /* return */
+       return surface;
+}
+
+
+
+/*
+PicoFreeSurface()
+frees a surface and all associated data
+*/
+void PicoFreeSurface( picoSurface_t *surface )
+{
+       int             i;
+       
+       
+       /* dummy check */
+       if( surface == NULL )
+               return;
+       
+       /* free bits */
+       _pico_free( surface->xyz );
+       _pico_free( surface->normal );
+       _pico_free( surface->index );
+       _pico_free( surface->faceNormal );
+       
+       /* free arrays */
+       for( i = 0; i < surface->numSTArrays; i++ )
+               _pico_free( surface->st[ i ] );
+       free( surface->st );
+       for( i = 0; i < surface->numColorArrays; i++ )
+               _pico_free( surface->color[ i ] );
+       free( surface->color );
+       
+       /* free the surface */
+       _pico_free( surface );
+}
+
+
+
+/*
+PicoAdjustSurface()
+adjusts a surface's memory allocations to handle the requested sizes.
+will always grow, never shrink
+*/
+
+int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals )
+{
+       int             i;
+       
+       
+       /* dummy check */
+       if( surface == NULL )
+               return 0;
+       
+       /* bare minimums */
+       if( numVertexes < 1 )
+               numVertexes = 1;
+       if( numSTArrays < 1 )
+               numSTArrays = 1;
+       if( numColorArrays < 1 )
+               numColorArrays = 1;
+       if( numIndexes < 1 )
+               numIndexes = 1;
+       
+       /* additional vertexes? */
+       while( numVertexes > surface->maxVertexes ) /* fix */
+       {
+               surface->maxVertexes += PICO_GROW_VERTEXES;
+               if( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) )
+                       return 0;
+               if( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) )
+                       return 0;
+               for( i = 0; i < surface->numSTArrays; i++ )
+                       if( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) )
+                       return 0;
+               for( i = 0; i < surface->numColorArrays; i++ )
+                       if( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) )
+                       return 0;
+       }
+       
+       /* set vertex count to higher */
+       if( numVertexes > surface->numVertexes )
+               surface->numVertexes = numVertexes;
+       
+       /* additional st arrays? */
+       while( numSTArrays > surface->maxSTArrays ) /* fix */
+       {
+               surface->maxSTArrays += PICO_GROW_ARRAYS;
+               if( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) )
+                       return 0;
+               while( surface->numSTArrays < numSTArrays )
+               {
+                       surface->st[ surface->numSTArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
+                       memset( surface->st[ surface->numSTArrays ], 0, surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
+                       surface->numSTArrays++;
+               }
+       }
+       
+       /* additional color arrays? */
+       while( numColorArrays > surface->maxColorArrays ) /* fix */
+       {
+               surface->maxColorArrays += PICO_GROW_ARRAYS;
+               if( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) )
+                       return 0;
+               while( surface->numColorArrays < numColorArrays )
+               {
+                       surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
+                       memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
+                       surface->numColorArrays++;
+               }
+       }
+       
+       /* additional indexes? */
+       while( numIndexes > surface->maxIndexes ) /* fix */
+       {
+               surface->maxIndexes += PICO_GROW_INDEXES;
+               if( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) )
+                       return 0;
+       }
+       
+       /* set index count to higher */
+       if( numIndexes > surface->numIndexes )
+               surface->numIndexes = numIndexes;
+
+       /* additional face normals? */
+       while( numFaceNormals > surface->maxFaceNormals ) /* fix */
+       {
+               surface->maxFaceNormals += PICO_GROW_FACES;
+               if( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) )
+                       return 0;
+       }
+
+       /* set face normal count to higher */
+       if( numFaceNormals > surface->numFaceNormals )
+               surface->numFaceNormals = numFaceNormals;
+
+       /* return ok */
+       return 1;
+}
+
+
+/* PicoFindSurface:
+ *   Finds first matching named surface in a model.
+ */
+picoSurface_t *PicoFindSurface(
+       picoModel_t *model, char *name, int caseSensitive )
+{
+       int             i;
+
+       /* sanity check */
+       if( model == NULL || name == NULL )
+               return NULL;
+       
+       /* walk list */
+       for( i = 0; i < model->numSurfaces; i++ )
+       {
+               /* skip null surfaces or surfaces with null names */
+               if( model->surface[ i ] == NULL ||
+                       model->surface[ i ]->name == NULL )
+                       continue;
+
+               /* compare the surface name with name we're looking for */
+               if (caseSensitive) {
+                       if( !strcmp(name,model->surface[ i ]->name) )
+                               return model->surface[ i ];
+               } else {
+                       if( !_pico_stricmp(name,model->surface[ i ]->name) )
+                               return model->surface[ i ];
+               }
+       }
+       /* named surface not found */
+       return NULL;
+}
+
+
+
+/*----------------------------------------------------------------------------
+  PicoSet*() Setter Functions
+----------------------------------------------------------------------------*/
+
+void PicoSetModelName( picoModel_t *model, char *name )
+{
+       if( model == NULL || name == NULL )
+               return;
+       if( model->name != NULL )
+               _pico_free( model->name );
+
+       model->name = _pico_clone_alloc( name,-1 );
+}
+
+
+
+void PicoSetModelFileName( picoModel_t *model, char *fileName )
+{
+       if( model == NULL || fileName == NULL )
+               return;
+       if( model->fileName != NULL )
+               _pico_free( model->fileName );
+
+       model->fileName = _pico_clone_alloc( fileName,-1 );
+}
+
+
+
+void PicoSetModelFrameNum( picoModel_t *model, int frameNum )
+{
+       if( model == NULL )
+               return;
+       model->frameNum = frameNum;
+}
+
+
+
+void PicoSetModelNumFrames( picoModel_t *model, int numFrames )
+{
+       if( model == NULL )
+               return;
+       model->numFrames = numFrames;
+}
+
+
+
+void PicoSetModelData( picoModel_t *model, void *data )
+{
+       if( model == NULL )
+               return;
+       model->data = data;
+}
+
+
+
+void PicoSetShaderName( picoShader_t *shader, char *name )
+{
+       if( shader == NULL || name == NULL )
+               return;
+       if( shader->name != NULL )
+               _pico_free( shader->name );
+
+       shader->name = _pico_clone_alloc( name,-1 );
+}
+
+
+
+void PicoSetShaderMapName( picoShader_t *shader, char *mapName )
+{
+       if( shader == NULL || mapName == NULL )
+               return;
+       if( shader->mapName != NULL )
+               _pico_free( shader->mapName );
+
+       shader->mapName = _pico_clone_alloc( mapName,-1 );
+}
+
+
+
+void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color )
+{
+       if( shader == NULL || color == NULL )
+               return;
+       shader->ambientColor[ 0 ] = color[ 0 ];
+       shader->ambientColor[ 1 ] = color[ 1 ];
+       shader->ambientColor[ 2 ] = color[ 2 ];
+       shader->ambientColor[ 3 ] = color[ 3 ];
+}
+
+
+
+void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color )
+{
+       if( shader == NULL || color == NULL )
+               return;
+       shader->diffuseColor[ 0 ] = color[ 0 ];
+       shader->diffuseColor[ 1 ] = color[ 1 ];
+       shader->diffuseColor[ 2 ] = color[ 2 ];
+       shader->diffuseColor[ 3 ] = color[ 3 ];
+}
+
+
+
+void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color )
+{
+       if( shader == NULL || color == NULL )
+               return;
+       shader->specularColor[ 0 ] = color[ 0 ];
+       shader->specularColor[ 1 ] = color[ 1 ];
+       shader->specularColor[ 2 ] = color[ 2 ];
+       shader->specularColor[ 3 ] = color[ 3 ];
+}
+
+
+
+void PicoSetShaderTransparency( picoShader_t *shader, float value )
+{
+       if( shader == NULL )
+               return;
+       shader->transparency = value;
+
+       /* cap to 0..1 range */
+       if (shader->transparency < 0.0)
+               shader->transparency = 0.0;
+       if (shader->transparency > 1.0)
+               shader->transparency = 1.0;
+}
+
+
+
+void PicoSetShaderShininess( picoShader_t *shader, float value )
+{
+       if( shader == NULL )
+               return;
+       shader->shininess = value;
+
+       /* cap to 0..127 range */
+       if (shader->shininess < 0.0)
+               shader->shininess = 0.0;
+       if (shader->shininess > 127.0)
+               shader->shininess = 127.0;
+}
+
+
+
+void PicoSetSurfaceData( picoSurface_t *surface, void *data )
+{
+       if( surface == NULL )
+               return;
+       surface->data = data;
+}
+
+
+
+void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type )
+{
+       if( surface == NULL )
+               return;
+       surface->type = type;
+}
+
+
+
+void PicoSetSurfaceName( picoSurface_t *surface, char *name )
+{
+       if( surface == NULL || name == NULL )
+               return;
+       if( surface->name != NULL )
+               _pico_free( surface->name );
+
+       surface->name = _pico_clone_alloc( name,-1 );
+}
+
+
+
+void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader )
+{
+       if( surface == NULL )
+               return;
+       surface->shader = shader;
+}
+
+
+
+void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz )
+{
+       if( surface == NULL || num < 0 || xyz == NULL )
+               return;
+       if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) )
+               return;
+       _pico_copy_vec( xyz, surface->xyz[ num ] );
+       if( surface->model != NULL )
+               _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs );
+}
+
+
+
+void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal )
+{
+       if( surface == NULL || num < 0 || normal == NULL )
+               return;
+       if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) )
+               return;
+       _pico_copy_vec( normal, surface->normal[ num ] );
+}
+
+
+
+void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st )
+{
+       if( surface == NULL || num < 0 || st == NULL )
+               return;
+       if( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) )
+               return;
+       surface->st[ array ][ num ][ 0 ] = st[ 0 ];
+       surface->st[ array ][ num ][ 1 ] = st[ 1 ];
+}
+
+
+
+void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color )
+{
+       if( surface == NULL || num < 0 || color == NULL )
+               return;
+       if( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) )
+               return;
+       surface->color[ array ][ num ][ 0 ] = color[ 0 ];
+       surface->color[ array ][ num ][ 1 ] = color[ 1 ];
+       surface->color[ array ][ num ][ 2 ] = color[ 2 ];
+       surface->color[ array ][ num ][ 3 ] = color[ 3 ];
+}
+
+
+
+void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index )
+{
+       if( surface == NULL || num < 0 )
+               return;
+       if( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) )
+               return;
+       surface->index[ num ] = index;
+}
+
+
+
+void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count )
+{
+       if( num < 0 || index == NULL || count < 1 )
+               return;
+       if( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) )
+               return;
+       memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) );
+}
+
+
+
+void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal )
+{
+       if( surface == NULL || num < 0 || normal == NULL )
+               return;
+       if( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) )
+               return;
+       _pico_copy_vec( normal, surface->faceNormal[ num ] );
+}
+
+
+void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special )
+{
+       if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL )
+               return;
+       surface->special[ num ] = special;
+}
+
+
+
+/*----------------------------------------------------------------------------
+  PicoGet*() Getter Functions
+----------------------------------------------------------------------------*/
+
+char *PicoGetModelName( picoModel_t *model )
+{
+       if( model == NULL )
+               return NULL;
+       if( model->name == NULL)
+               return (char*) "";
+       return model->name;
+}
+
+
+
+char *PicoGetModelFileName( picoModel_t *model )
+{
+       if( model == NULL )
+               return NULL;
+       if( model->fileName == NULL)
+               return (char*) "";
+       return model->fileName;
+}
+
+
+
+int PicoGetModelFrameNum( picoModel_t *model )
+{
+       if( model == NULL )
+               return 0;
+       return model->frameNum;
+}
+
+
+
+int PicoGetModelNumFrames( picoModel_t *model )
+{
+       if( model == NULL )
+               return 0;
+       return model->numFrames;
+}
+
+
+
+void *PicoGetModelData( picoModel_t *model )
+{
+       if( model == NULL )
+               return NULL;
+       return model->data;
+}
+
+
+
+int PicoGetModelNumShaders( picoModel_t *model )
+{
+       if( model == NULL )
+               return 0;
+       return model->numShaders;
+}
+
+
+
+picoShader_t *PicoGetModelShader( picoModel_t *model, int num )
+{
+       /* a few sanity checks */
+       if( model == NULL )
+               return NULL;
+       if( model->shader == NULL)
+               return NULL;
+       if( num < 0 || num >= model->numShaders )
+               return NULL;
+       
+       /* return the shader */
+       return model->shader[ num ];
+}
+
+
+
+int PicoGetModelNumSurfaces( picoModel_t *model )
+{
+       if( model == NULL )
+               return 0;
+       return model->numSurfaces;
+}
+
+
+
+picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num )
+{
+       /* a few sanity checks */
+       if( model == NULL )
+               return NULL;
+       if( model->surface == NULL)
+               return NULL;
+       if( num < 0 || num >= model->numSurfaces )
+               return NULL;
+       
+       /* return the surface */
+       return model->surface[ num ];
+}
+
+
+
+int PicoGetModelTotalVertexes( picoModel_t *model )
+{
+       int             i, count;
+       
+       
+       if( model == NULL )
+               return 0;
+       if( model->surface == NULL )
+               return 0;
+       
+       count = 0;
+       for( i = 0; i < model->numSurfaces; i++ )
+                count += PicoGetSurfaceNumVertexes( model->surface[ i ] );
+       
+       return count;
+}
+
+
+
+int PicoGetModelTotalIndexes( picoModel_t *model )
+{
+       int             i, count;
+       
+       
+       if( model == NULL )
+               return 0;
+       if( model->surface == NULL )
+               return 0;
+       
+       count = 0;
+       for( i = 0; i < model->numSurfaces; i++ )
+                count += PicoGetSurfaceNumIndexes( model->surface[ i ] );
+       
+       return count;
+}
+
+
+
+char *PicoGetShaderName( picoShader_t *shader )
+{
+       if( shader == NULL )
+               return NULL;
+       if( shader->name == NULL)
+               return (char*) "";
+       return shader->name;
+}
+
+
+
+char *PicoGetShaderMapName( picoShader_t *shader )
+{
+       if( shader == NULL )
+               return NULL;
+       if( shader->mapName == NULL)
+               return (char*) "";
+       return shader->mapName;
+}
+
+
+
+picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader )
+{
+       if( shader == NULL )
+               return NULL;
+       return shader->ambientColor;
+}
+
+
+
+picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader )
+{
+       if( shader == NULL )
+               return NULL;
+       return shader->diffuseColor;
+}
+
+
+
+picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader )
+{
+       if( shader == NULL )
+               return NULL;
+       return shader->specularColor;
+}
+
+
+
+float PicoGetShaderTransparency( picoShader_t *shader )
+{
+       if( shader == NULL )
+               return 0.0f;
+       return shader->transparency;
+}
+
+
+
+float PicoGetShaderShininess( picoShader_t *shader )
+{
+       if( shader == NULL )
+               return 0.0f;
+       return shader->shininess;
+}
+
+
+
+void *PicoGetSurfaceData( picoSurface_t *surface )
+{
+       if( surface == NULL )
+               return NULL;
+       return surface->data;
+}
+
+
+
+picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface )
+{
+       if( surface == NULL )
+               return PICO_BAD;
+       return surface->type;
+}
+
+
+
+char *PicoGetSurfaceName( picoSurface_t *surface )
+{
+       if( surface == NULL )
+               return NULL;
+       if( surface->name == NULL )
+               return (char*) "";
+       return surface->name;
+}
+
+
+
+picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface )
+{
+       if( surface == NULL )
+               return NULL;
+       return surface->shader;
+}
+
+
+
+int PicoGetSurfaceNumVertexes( picoSurface_t *surface )
+{
+       if( surface == NULL )
+               return 0;
+       return surface->numVertexes;
+}
+
+
+
+picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num )
+{
+       if( surface == NULL || num < 0 || num > surface->numVertexes )
+               return NULL;
+       return surface->xyz[ num ];
+}
+
+
+
+picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num )
+{
+       if( surface == NULL || num < 0 || num > surface->numVertexes )
+               return NULL;
+       return surface->normal[ num ];
+}
+
+
+
+picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num  )
+{
+       if( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes )
+               return NULL;
+       return surface->st[ array ][ num ];
+}
+
+
+
+picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num )
+{
+       if( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes )
+               return NULL;
+       return surface->color[ array ][ num ];
+}
+
+
+
+int PicoGetSurfaceNumIndexes( picoSurface_t *surface )
+{
+       if( surface == NULL )
+               return 0;
+       return surface->numIndexes;
+}
+
+
+
+picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num )
+{
+       if( surface == NULL || num < 0 || num > surface->numIndexes )
+               return 0;
+       return surface->index[ num ];
+}
+
+
+
+picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num )
+{
+       if( surface == NULL || num < 0 || num > surface->numIndexes )
+               return NULL;
+       return &surface->index[ num ];
+}
+
+
+picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num )
+{
+       if( surface == NULL || num < 0 || num > surface->numFaceNormals )
+               return NULL;
+       return surface->faceNormal[ num ];
+}
+
+
+int PicoGetSurfaceSpecial( picoSurface_t *surface, int num )
+{
+       if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL )
+               return 0;
+       return surface->special[ num ];
+}
+
+
+
+/* ----------------------------------------------------------------------------
+hashtable related functions
+---------------------------------------------------------------------------- */
+
+/* hashtable code for faster vertex lookups */
+//#define HASHTABLE_SIZE 32768 // 2048                 /* power of 2, use & */
+#define HASHTABLE_SIZE 7919 // 32749 // 2039   /* prime, use % */
+
+int PicoGetHashTableSize( void )
+{
+       return HASHTABLE_SIZE;
+}
+
+#define HASH_USE_EPSILON
+
+#ifdef HASH_USE_EPSILON
+#define HASH_XYZ_EPSILON                                       0.01f
+#define HASH_XYZ_EPSILONSPACE_MULTIPLIER       1.f / HASH_XYZ_EPSILON
+#define HASH_ST_EPSILON                                                0.0001f
+#define HASH_NORMAL_EPSILON                                    0.02f
+#endif
+
+unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz )
+{
+       unsigned int hash = 0;
+
+#ifndef HASH_USE_EPSILON
+       hash += ~(*((unsigned int*) &xyz[ 0 ]) << 15);
+       hash ^= (*((unsigned int*) &xyz[ 0 ]) >> 10);
+       hash += (*((unsigned int*) &xyz[ 1 ]) << 3);
+       hash ^= (*((unsigned int*) &xyz[ 1 ]) >> 6);
+       hash += ~(*((unsigned int*) &xyz[ 2 ]) << 11);
+       hash ^= (*((unsigned int*) &xyz[ 2 ]) >> 16);
+#else
+       picoVec3_t xyz_epsilonspace;
+
+       _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace );
+       xyz_epsilonspace[ 0 ] = (float)floor(xyz_epsilonspace[ 0 ]);
+       xyz_epsilonspace[ 1 ] = (float)floor(xyz_epsilonspace[ 1 ]);
+       xyz_epsilonspace[ 2 ] = (float)floor(xyz_epsilonspace[ 2 ]);
+
+       hash += ~(*((unsigned int*) &xyz_epsilonspace[ 0 ]) << 15);
+       hash ^= (*((unsigned int*) &xyz_epsilonspace[ 0 ]) >> 10);
+       hash += (*((unsigned int*) &xyz_epsilonspace[ 1 ]) << 3);
+       hash ^= (*((unsigned int*) &xyz_epsilonspace[ 1 ]) >> 6);
+       hash += ~(*((unsigned int*) &xyz_epsilonspace[ 2 ]) << 11);
+       hash ^= (*((unsigned int*) &xyz_epsilonspace[ 2 ]) >> 16);
+#endif
+
+       //hash = hash & (HASHTABLE_SIZE-1);
+       hash = hash % (HASHTABLE_SIZE);
+       return hash;
+}
+
+picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void )
+{
+       picoVertexCombinationHash_t     **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) );
+
+       memset( hashTable, 0, HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) );
+
+       return hashTable;
+}
+
+void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable )
+{
+       int                                                     i;
+       picoVertexCombinationHash_t     *vertexCombinationHash;
+       picoVertexCombinationHash_t *nextVertexCombinationHash;
+
+       /* dummy check */
+       if (hashTable == NULL)
+               return;
+
+       for( i = 0; i < HASHTABLE_SIZE; i++ )
+       {
+               if (hashTable[ i ])
+               {
+                       nextVertexCombinationHash = NULL;
+
+                       for( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash )
+                       {
+                               nextVertexCombinationHash = vertexCombinationHash->next;
+                               if (vertexCombinationHash->data != NULL)
+                               {
+                                       _pico_free( vertexCombinationHash->data );
+                               }
+                               _pico_free( vertexCombinationHash );
+                       }
+               }
+       }
+
+       _pico_free( hashTable );
+}
+
+picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color )
+{
+       unsigned int                            hash;
+       picoVertexCombinationHash_t     *vertexCombinationHash;
+
+       /* dumy check */
+       if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL )
+               return NULL;
+
+       hash = PicoVertexCoordGenerateHash( xyz );
+
+       for( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next )
+       {
+#ifndef HASH_USE_EPSILON
+               /* check xyz */
+               if( (vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ]) )
+                       continue;
+
+               /* check normal */
+               if( (vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ]) )
+                       continue;
+               
+               /* check st */
+               if( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] )
+                       continue;
+#else
+               /* check xyz */
+               if( ( fabs(xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ]) ) > HASH_XYZ_EPSILON ||
+                       ( fabs(xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ]) ) > HASH_XYZ_EPSILON ||
+                       ( fabs(xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ]) ) > HASH_XYZ_EPSILON )
+                       continue;
+
+               /* check normal */
+               if( ( fabs(normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ]) ) > HASH_NORMAL_EPSILON ||
+                       ( fabs(normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ]) ) > HASH_NORMAL_EPSILON ||
+                       ( fabs(normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ]) ) > HASH_NORMAL_EPSILON )
+                       continue;
+               
+               /* check st */
+               if( ( fabs(st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ]) ) > HASH_ST_EPSILON ||
+                       ( fabs(st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ]) ) > HASH_ST_EPSILON )
+                       continue;
+#endif
+
+               /* check color */
+               if( *((int*) vertexCombinationHash->vcd.color) != *((int*) color) )
+                       continue;
+
+               /* gotcha */
+               return vertexCombinationHash;
+       }
+
+       return NULL;
+}
+
+picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index )
+{
+       unsigned int                            hash;
+       picoVertexCombinationHash_t     *vertexCombinationHash;
+
+       /* dumy check */
+       if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL )
+               return NULL;
+
+       vertexCombinationHash = _pico_alloc( sizeof(picoVertexCombinationHash_t) );
+
+       if (!vertexCombinationHash)
+               return NULL;
+
+       hash = PicoVertexCoordGenerateHash( xyz );
+
+       _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz );
+       _pico_copy_vec( normal, vertexCombinationHash->vcd.normal );
+       _pico_copy_vec2( st, vertexCombinationHash->vcd.st );
+       _pico_copy_color( color, vertexCombinationHash->vcd.color );
+       vertexCombinationHash->index = index;
+       vertexCombinationHash->data = NULL;
+       vertexCombinationHash->next = hashTable[ hash ];
+       hashTable[ hash ] = vertexCombinationHash;
+
+       return vertexCombinationHash;
+}
+
+/* ----------------------------------------------------------------------------
+specialized routines
+---------------------------------------------------------------------------- */
+
+/*
+PicoFindSurfaceVertex()
+finds a vertex matching the set parameters
+fixme: needs non-naive algorithm
+*/
+
+int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color )
+{
+       int             i, j;
+       
+       
+       /* dummy check */
+       if( surface == NULL || surface->numVertexes <= 0 )
+               return -1;
+       
+       /* walk vertex list */
+       for( i = 0; i < surface->numVertexes; i++ )
+       {
+               /* check xyz */
+               if( xyz != NULL && (surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ]) )
+                       continue;
+               
+               /* check normal */
+               if( normal != NULL && (surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ]) )
+                       continue;
+               
+               /* check st */
+               if( numSTs > 0 && st != NULL )
+               {
+                       for( j = 0; j < numSTs; j++ )
+                       {
+                               if( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] )
+                                       break;
+                       }
+                       if( j != numSTs )
+                               continue;
+               }
+               
+               /* check color */
+               if( numColors > 0 && color != NULL )
+               {
+                       for( j = 0; j < numSTs; j++ )
+                       {
+                               if( *((int*) surface->color[ j ]) != *((int*) color[ j ]) )
+                                       break;
+                       }
+                       if( j != numColors )
+                               continue;
+               }
+               
+               /* vertex matches */
+               return i;
+       }
+       
+       /* nada */
+       return -1;
+}
+
+
+
+/*
+PicoFixSurfaceNormals()
+fixes broken normals (certain formats bork normals)
+*/
+
+#define MAX_NORMAL_VOTES               128
+#define EQUAL_NORMAL_EPSILON   0.01
+#define BAD_NORMAL_EPSILON             0.5
+
+void PicoFixSurfaceNormals( picoSurface_t *surface )
+{
+       int                             i, j, k, a, b, c, numVotes, faceIndex;
+       picoVec3_t              votes[ MAX_NORMAL_VOTES ];
+       picoVec3_t              *normals, diff;
+       picoVec4_t              plane;
+       
+       
+       /* dummy check */
+       if( surface == NULL || surface->numVertexes == 0 )
+               return;
+       
+       /* fixme: handle other surface types */
+       if( surface->type != PICO_TRIANGLES )
+               return;
+       
+       /* allocate normal storage */
+       normals = _pico_alloc( surface->numVertexes * sizeof( *normals ) );
+       if( normals == NULL )
+       {
+               _pico_printf( PICO_ERROR, "PicoFixSurfaceNormals: Unable to allocate memory for temporary normal storage" );
+               return;
+       }
+       
+       /* zero it out */
+       memset( normals, 0, surface->numVertexes * sizeof( *normals ) );
+       
+       /* walk vertex list */
+       for( i = 0; i < surface->numVertexes; i++ )
+       {
+               /* zero out votes */
+               numVotes = 0;
+               
+               /* find all the triangles that reference this vertex */
+               for( j = 0, faceIndex = 0; j < surface->numIndexes; j += 3, faceIndex++ )
+               {
+                       /* get triangle */
+                       a = surface->index[ j ];
+                       b = surface->index[ j + 1 ];
+                       c = surface->index[ j + 2 ];
+                       
+                       /* ignore degenerate triangles */
+                       if( a == b || b == c || c == a )
+                               continue;
+                       
+                       /* ignore indexes out of range */
+                       if( a < 0 || a >= surface->numVertexes ||
+                               b < 0 || b >= surface->numVertexes ||
+                               c < 0 || c >= surface->numVertexes )
+                               continue;
+                       
+                       /* test triangle */
+                       if( a == i || b == i || c == i )
+                       {
+                               /* if this surface has face normals */
+                               if( surface->numFaceNormals && faceIndex < surface->numFaceNormals )
+                               {
+                                       _pico_copy_vec( surface->faceNormal[ faceIndex ], plane );
+                                       if( plane[ 0 ] == 0.f && plane[ 1 ] == 0.f && plane[ 2 ] == 0.f )
+                                       {
+                                               /* if null normal, make plane from the 3 points */
+                                               if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 )
+                                               {
+                                                       continue;
+                                               }
+                                       }
+                               }
+                               /* make a plane from the 3 points */
+                               else if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 )
+                               {
+                                       continue;
+                               }
+
+                               /* see if this normal has already been voted */
+                               for( k = 0; k < numVotes; k++ )
+                               {
+                                       _pico_subtract_vec( plane, votes[ k ], diff );
+                                       if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
+                                               fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
+                                               fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON )
+                                               break;
+                               }
+                               
+                               /* add a new vote? */
+                               if( k == numVotes && numVotes < MAX_NORMAL_VOTES )
+                               {
+                                       _pico_copy_vec( plane, votes[ numVotes ] );
+                                       numVotes++;
+                               }
+                       }
+               }
+               
+               /* tally votes */
+               if( numVotes > 0 )
+               {
+                       /* create average normal */
+                       _pico_zero_vec( normals[ i ] );
+                       for( k = 0; k < numVotes; k++ )
+                               _pico_add_vec( normals[ i ], votes[ k ], normals[ i ] );
+                       
+                       /* normalize it */
+                       if( _pico_normalize_vec( normals[ i ] ) )
+                       {
+                               /* test against actual normal */
+                               if( fabs( _pico_dot_vec( normals[ i ], surface->normal[ i ] ) - 1 ) > BAD_NORMAL_EPSILON )
+                               {
+                                       //%     printf( "Normal %8d: (%f %f %f) -> (%f %f %f)\n", i,
+                                       //%             surface->normal[ i ][ 0 ], surface->normal[ i ][ 1 ], surface->normal[ i ][ 2 ],
+                                       //%             normals[ i ][ 0 ], normals[ i ][ 1 ], normals[ i ][ 2 ] );
+                                       _pico_copy_vec( normals[ i ], surface->normal[ i ] );
+                               }
+                       }
+               }
+       }
+       
+       /* free normal storage */
+       _pico_free( normals );
+}
+
+
+
+
+/*
+PicoRemapModel() - sea
+remaps model material/etc. information using the remappings
+contained in the given 'remapFile' (full path to the ascii file to open)
+returns 1 on success or 0 on error
+*/
+
+#define _prm_error_return \
+{ \
+       _pico_free_parser( p ); \
+       _pico_free_file( remapBuffer ); \
+       return 0; \
+}
+
+int PicoRemapModel( picoModel_t *model, char *remapFile )
+{
+       picoParser_t    *p;
+       picoByte_t              *remapBuffer;
+       int                             remapBufSize;
+       
+       
+       /* sanity checks */
+       if( model == NULL || remapFile == NULL )
+               return 0;
+       
+       /* load remap file contents */
+       _pico_load_file( remapFile,&remapBuffer,&remapBufSize );
+       
+       /* check result */
+       if( remapBufSize == 0 )
+               return 1;       /* file is empty: no error */
+       if( remapBufSize < 0 )
+               return 0;       /* load failed: error */
+       
+       /* create a new pico parser */
+       p = _pico_new_parser( remapBuffer, remapBufSize );
+       if (p == NULL)
+       {
+               /* ram is really cheap nowadays... */
+               _prm_error_return;
+       }
+       
+       /* doo teh parse */
+       while( 1 )
+       {
+               /* get next token in remap file */
+               if (!_pico_parse( p,1 ))
+                       break;
+
+               /* skip over c++ style comment lines */
+               if (!_pico_stricmp(p->token,"//"))
+               {
+                       _pico_parse_skip_rest( p );
+                       continue;
+               }
+               
+               /* block for quick material shader name remapping */
+               /* materials { "m" (=>|->|=) "s" } */
+               if( !_pico_stricmp(p->token, "materials" ) )
+               {
+                       int level = 1;
+
+                       /* check bracket */
+                       if (!_pico_parse_check( p,1,"{" ))
+                               _prm_error_return;
+
+                       /* process assignments */
+                       while( 1 )
+                       {
+                               picoShader_t    *shader;
+                               char                    *materialName;
+                               
+                               
+                               /* get material name */
+                               if (_pico_parse( p,1 ) == NULL) break;
+                               if (!strlen(p->token)) continue;
+                               materialName = _pico_clone_alloc( p->token,-1 );
+                               if (materialName == NULL)
+                                       _prm_error_return;
+
+                               /* handle levels */
+                               if (p->token[0] == '{') level++;
+                               if (p->token[0] == '}') level--;
+                               if (!level) break;
+
+                               /* get next token (assignment token or shader name) */
+                               if (!_pico_parse( p,0 ))
+                               {
+                                       _pico_free( materialName );
+                                       _prm_error_return;
+                               }
+                               /* skip assignment token (if present) */
+                               if (!strcmp(p->token,"=>") ||
+                                       !strcmp(p->token,"->") ||
+                                       !strcmp(p->token,"="))
+                               {
+                                       /* simply grab the next token */
+                                       if (!_pico_parse( p,0 ))
+                                       {
+                                               _pico_free( materialName );
+                                               _prm_error_return;
+                                       }
+                               }
+                               /* try to find material by name */
+                               shader = PicoFindShader( model,materialName,0 );
+
+                               /* we've found a material matching the name */
+                               if (shader != NULL)
+                               {
+                                       PicoSetShaderName( shader,p->token );
+                               }
+                               /* free memory used by material name */
+                               _pico_free( materialName );
+
+                               /* skip rest */
+                               _pico_parse_skip_rest( p );
+                       }
+               }
+               /* block for detailed single material remappings */
+               /* materials[ "m" ] { key data... } */
+               else if (!_pico_stricmp(p->token,"materials["))
+               {
+                       picoShader_t *shader;
+                       char *tempMaterialName;
+                       int level = 1;
+
+                       /* get material name */
+                       if (!_pico_parse( p,0 ))
+                               _prm_error_return;
+
+                       /* temporary copy of material name */
+                       tempMaterialName = _pico_clone_alloc( p->token,-1 );
+                       if (tempMaterialName == NULL)
+                               _prm_error_return;
+
+                       /* check square closing bracket */
+                       if (!_pico_parse_check( p,0,"]" ))
+                               _prm_error_return;                      
+
+                       /* try to find material by name */
+                       shader = PicoFindShader( model,tempMaterialName,0 );
+
+                       /* free memory used by temporary material name */
+                       _pico_free( tempMaterialName );
+
+                       /* we haven't found a material matching the name */
+                       /* so we simply skip the braced section now and */
+                       /* continue parsing with the next main token */
+                       if (shader == NULL)
+                       {
+                               _pico_parse_skip_braced( p );
+                               continue;
+                       }
+                       /* check opening bracket */
+                       if (!_pico_parse_check( p,1,"{" ))
+                               _prm_error_return;
+
+                       /* process material info keys */
+                       while( 1 )
+                       {
+                               /* get key name */
+                               if (_pico_parse( p,1 ) == NULL) break;
+                               if (!strlen(p->token)) continue;
+
+                               /* handle levels */
+                               if (p->token[0] == '{') level++;
+                               if (p->token[0] == '}') level--;
+                               if (!level) break;
+
+                               /* remap shader name */
+                               if (!_pico_stricmp(p->token,"shader"))
+                               {
+                                       if (!_pico_parse( p,0 )) _prm_error_return;
+                                       PicoSetShaderName( shader,p->token );
+                               }
+                               /* remap shader map name */
+                               else if (!_pico_stricmp(p->token,"mapname"))
+                               {
+                                       if (!_pico_parse( p,0 )) _prm_error_return;
+                                       PicoSetShaderMapName( shader,p->token );
+                               }
+                               /* remap shader's ambient color */
+                               else if (!_pico_stricmp(p->token,"ambient"))
+                               {
+                                       picoColor_t color;
+                                       picoVec3_t  v;
+
+                                       /* get vector from parser */
+                                       if (!_pico_parse_vec( p,v )) _prm_error_return;
+
+                                       /* store as color */
+                                       color[ 0 ] = (picoByte_t)v[ 0 ];
+                                       color[ 1 ] = (picoByte_t)v[ 1 ];
+                                       color[ 2 ] = (picoByte_t)v[ 2 ];
+
+                                       /* set new ambient color */
+                                       PicoSetShaderAmbientColor( shader,color );
+                               }
+                               /* remap shader's diffuse color */
+                               else if (!_pico_stricmp(p->token,"diffuse"))
+                               {
+                                       picoColor_t color;
+                                       picoVec3_t  v;
+
+                                       /* get vector from parser */
+                                       if (!_pico_parse_vec( p,v )) _prm_error_return;
+
+                                       /* store as color */
+                                       color[ 0 ] = (picoByte_t)v[ 0 ];
+                                       color[ 1 ] = (picoByte_t)v[ 1 ];
+                                       color[ 2 ] = (picoByte_t)v[ 2 ];
+
+                                       /* set new ambient color */
+                                       PicoSetShaderDiffuseColor( shader,color );
+                               }
+                               /* remap shader's specular color */
+                               else if (!_pico_stricmp(p->token,"specular"))
+                               {
+                                       picoColor_t color;
+                                       picoVec3_t  v;
+
+                                       /* get vector from parser */
+                                       if (!_pico_parse_vec( p,v )) _prm_error_return;
+
+                                       /* store as color */
+                                       color[ 0 ] = (picoByte_t)v[ 0 ];
+                                       color[ 1 ] = (picoByte_t)v[ 1 ];
+                                       color[ 2 ] = (picoByte_t)v[ 2 ];
+
+                                       /* set new ambient color */
+                                       PicoSetShaderSpecularColor( shader,color );
+                               }
+                               /* skip rest */
+                               _pico_parse_skip_rest( p );
+                       }
+               }
+               /* end 'materials[' */
+       }
+       
+       /* free both parser and file buffer */
+       _pico_free_parser( p );
+       _pico_free_file( remapBuffer );
+
+       /* return with success */
+       return 1;
+}
+
+
+/*
+PicoAddTriangleToModel() - jhefty
+A nice way to add individual triangles to the model.
+Chooses an appropriate surface based on the shader, or adds a new surface if necessary
+*/
+
+void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, 
+                                                       int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors,
+                                                       picoShader_t* shader )
+{
+       int i,j;
+       int vertDataIndex;
+       picoSurface_t* workSurface = NULL;
+
+       /* see if a surface already has the shader */
+       for ( i = 0 ; i < model->numSurfaces ; i++ )
+       {
+               workSurface = model->surface[i];
+               if ( workSurface->shader == shader )
+               {                       
+                       break;
+               }
+       }
+
+       /* no surface uses this shader yet, so create a new surface */
+       if ( !workSurface || i >=model->numSurfaces )
+       {
+               /* create a new surface in the model for the unique shader */
+               workSurface = PicoNewSurface(model);
+               if ( !workSurface )
+               {
+                       _pico_printf ( PICO_ERROR , "Could not allocate a new surface!\n" );
+                       return;
+               }
+
+               /* do surface setup */
+               PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
+               PicoSetSurfaceName( workSurface, shader->name );
+               PicoSetSurfaceShader( workSurface, shader );
+       }
+
+       /* add the triangle data to the surface */
+       for ( i = 0 ; i < 3 ; i++ )     
+       {
+               /* get the next free spot in the index array */
+               int newVertIndex = PicoGetSurfaceNumIndexes ( workSurface );
+
+               /* get the index of the vertex that we're going to store at newVertIndex */
+               vertDataIndex = PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i]);
+
+               /* the vertex wasn't found, so create a new vertex in the pool from the data we have */
+               if ( vertDataIndex == -1 )
+               {                       
+                       /* find the next spot for a new vertex */
+                       vertDataIndex = PicoGetSurfaceNumVertexes ( workSurface );                      
+
+                       /* assign the data to it */
+                       PicoSetSurfaceXYZ ( workSurface ,vertDataIndex , *xyz[i] );
+                       PicoSetSurfaceNormal ( workSurface , vertDataIndex , *normals[i] );                     
+
+                       /* make sure to copy over all available ST's and colors for the vertex */
+                       for ( j = 0 ; j < numColors ; j++ )
+                       {
+                               PicoSetSurfaceColor( workSurface , j , vertDataIndex , colors[i][j] );
+                       }
+                       for ( j = 0 ; j < numSTs ; j++ )
+                       {
+                               PicoSetSurfaceST ( workSurface , j , vertDataIndex , st[i][j] );
+                       }
+               }
+
+               /* add this vertex to the triangle */           
+               PicoSetSurfaceIndex ( workSurface , newVertIndex , vertDataIndex );
+       }       
+}