1 /* -----------------------------------------------------------------------------
5 Copyright (c) 2002, Randy Reddig & seaw0lf
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
11 Redistributions of source code must retain the above copyright notice, this list
12 of conditions and the following disclaimer.
14 Redistributions in binary form must reproduce the above copyright notice, this
15 list of conditions and the following disclaimer in the documentation and/or
16 other materials provided with the distribution.
18 Neither the names of the copyright holders nor the names of its contributors may
19 be used to endorse or promote products derived from this software without
20 specific prior written permission.
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 ----------------------------------------------------------------------------- */
43 #include "picointernal.h"
49 initializes the picomodel library
54 /* successfully initialized -sea */
62 shuts the pico model library down
65 void PicoShutdown( void )
67 /* do something interesting here in the future */
75 returns last picomodel error code (see PME_* defines)
80 /* todo: do something here */
88 sets the ptr to the malloc function
91 void PicoSetMallocFunc( void *(*func)( size_t ) )
94 _pico_ptr_malloc = func;
101 sets the ptr to the free function
104 void PicoSetFreeFunc( void (*func)( void* ) )
107 _pico_ptr_free = func;
113 PicoSetLoadFileFunc()
114 sets the ptr to the file load function
117 void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) )
120 _pico_ptr_load_file = func;
126 PicoSetFreeFileFunc()
127 sets the ptr to the free function
130 void PicoSetFreeFileFunc( void (*func)( void* ) )
133 _pico_ptr_free_file = func;
140 sets the ptr to the print function
143 void PicoSetPrintFunc( void (*func)( int, const char* ) )
146 _pico_ptr_print = func;
153 the meat and potatoes function
156 picoModel_t *PicoLoadModel( char *fileName, int frameNum )
158 const picoModule_t **modules, *pm;
162 char *modelFileName, *remapFileName;
168 /* make sure we've got a file name */
169 if( fileName == NULL )
171 _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" );
175 /* load file data (buffer is allocated by host app) */
176 _pico_load_file( fileName, &buffer, &bufSize );
179 _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName );
183 /* get ptr to list of supported modules */
184 modules = PicoModuleList( NULL );
186 /* run it through the various loader functions and try */
187 /* to find a loader that fits the given file data */
188 for( ; *modules != NULL; modules++ )
197 /* module must be able to load */
198 if( pm->canload == NULL || pm->load == NULL )
201 /* see whether this module can load the model file or not */
202 if( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK )
204 /* use loader provided by module to read the model data */
205 model = pm->load( fileName, frameNum, buffer, bufSize );
208 _pico_free_file( buffer );
212 /* assign pointer to file format module */
215 /* get model file name */
216 modelFileName = PicoGetModelFileName( model );
218 /* apply model remappings from <model>.remap */
219 if( strlen( modelFileName ) )
221 /* alloc copy of model file name */
222 remapFileName = _pico_alloc( strlen( modelFileName ) + 20 );
223 if( remapFileName != NULL )
225 /* copy model file name and change extension */
226 strcpy( remapFileName, modelFileName );
227 _pico_setfext( remapFileName, "remap" );
229 /* try to remap model; we don't handle the result */
230 PicoRemapModel( model, remapFileName );
232 /* free the remap file name string */
233 _pico_free( remapFileName );
237 /* model was loaded, so break out of loop */
242 /* free memory used by file buffer */
244 _pico_free_file( buffer );
252 /* ----------------------------------------------------------------------------
254 ---------------------------------------------------------------------------- */
258 creates a new pico model
261 picoModel_t *PicoNewModel( void )
266 model = _pico_alloc( sizeof(picoModel_t) );
271 memset( model,0,sizeof(picoModel_t) );
274 _pico_zero_bounds( model->mins,model->maxs );
276 /* set initial frame count to 1 -sea */
277 model->numFrames = 1;
279 /* return ptr to new model */
287 frees a model and all associated data
290 void PicoFreeModel( picoModel_t *model )
301 _pico_free( model->name );
304 for( i = 0; i < model->numShaders; i++ )
305 PicoFreeShader( model->shader[ i ] );
306 free( model->shader );
309 for( i = 0; i < model->numSurfaces; i++ )
310 PicoFreeSurface( model->surface[ i ] );
311 free( model->surface );
321 adjusts a models's memory allocations to handle the requested sizes.
322 will always grow, never shrink
325 int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces )
332 /* sea: null surface/shader fix (1s=>0s) */
335 if( numSurfaces < 0 )
338 /* additional shaders? */
339 while( numShaders > model->maxShaders )
341 model->maxShaders += PICO_GROW_SHADERS;
342 if( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) )
346 /* set shader count to higher */
347 if( numShaders > model->numShaders )
348 model->numShaders = numShaders;
350 /* additional surfaces? */
351 while( numSurfaces > model->maxSurfaces )
353 model->maxSurfaces += PICO_GROW_SURFACES;
354 if( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) )
358 /* set shader count to higher */
359 if( numSurfaces > model->numSurfaces )
360 model->numSurfaces = numSurfaces;
368 /* ----------------------------------------------------------------------------
370 ---------------------------------------------------------------------------- */
374 creates a new pico shader and returns its index. -sea
377 picoShader_t *PicoNewShader( picoModel_t *model )
379 picoShader_t *shader;
382 /* allocate and clear */
383 shader = _pico_alloc( sizeof(picoShader_t) );
386 memset( shader, 0, sizeof(picoShader_t) );
388 /* attach it to the model */
392 if( !PicoAdjustModel( model, model->numShaders + 1, 0 ) )
394 _pico_free( shader );
398 model->shader[ model->numShaders - 1 ] = shader;
399 shader->model = model;
401 /* setup default shader colors */
402 _pico_set_color( shader->ambientColor,0,0,0,0 );
403 _pico_set_color( shader->diffuseColor,255,255,255,1 );
404 _pico_set_color( shader->specularColor,0,0,0,0 );
406 /* no need to do this, but i do it anyway */
407 shader->transparency = 0;
408 shader->shininess = 0;
410 /* return the newly created shader */
418 frees a shader and all associated data -sea
421 void PicoFreeShader( picoShader_t *shader )
429 _pico_free( shader->name );
430 if( shader->mapName )
431 _pico_free( shader->mapName );
433 /* free the shader */
434 _pico_free( shader );
441 finds a named shader in a model
444 picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive )
450 if( model == NULL || name == NULL ) /* sea: null name fix */
454 for( i = 0; i < model->numShaders; i++ )
456 /* skip null shaders or shaders with null names */
457 if( model->shader[ i ] == NULL ||
458 model->shader[ i ]->name == NULL )
461 /* compare the shader name with name we're looking for */
464 if( !strcmp( name, model->shader[ i ]->name ) )
465 return model->shader[ i ];
467 else if( !_pico_stricmp( name, model->shader[ i ]->name ) )
468 return model->shader[ i ];
471 /* named shader not found */
477 /* ----------------------------------------------------------------------------
479 ---------------------------------------------------------------------------- */
483 creates a new pico surface
486 picoSurface_t *PicoNewSurface( picoModel_t *model )
488 picoSurface_t *surface;
489 char surfaceName[64];
491 /* allocate and clear */
492 surface = _pico_alloc( sizeof( *surface ) );
493 if( surface == NULL )
495 memset( surface, 0, sizeof( *surface ) );
497 /* attach it to the model */
501 if( !PicoAdjustModel( model, 0, model->numSurfaces + 1 ) )
503 _pico_free( surface );
508 model->surface[ model->numSurfaces - 1 ] = surface;
509 surface->model = model;
511 /* set default name */
512 sprintf( surfaceName, "Unnamed_%d", model->numSurfaces );
513 PicoSetSurfaceName( surface, surfaceName );
524 frees a surface and all associated data
526 void PicoFreeSurface( picoSurface_t *surface )
532 if( surface == NULL )
536 _pico_free( surface->xyz );
537 _pico_free( surface->normal );
538 _pico_free( surface->index );
539 _pico_free( surface->faceNormal );
542 for( i = 0; i < surface->numSTArrays; i++ )
543 _pico_free( surface->st[ i ] );
545 for( i = 0; i < surface->numColorArrays; i++ )
546 _pico_free( surface->color[ i ] );
547 free( surface->color );
549 /* free the surface */
550 _pico_free( surface );
557 adjusts a surface's memory allocations to handle the requested sizes.
558 will always grow, never shrink
561 int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals )
567 if( surface == NULL )
571 if( numVertexes < 1 )
573 if( numSTArrays < 1 )
575 if( numColorArrays < 1 )
580 /* additional vertexes? */
581 while( numVertexes > surface->maxVertexes ) /* fix */
583 surface->maxVertexes += PICO_GROW_VERTEXES;
584 if( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) )
586 if( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) )
588 for( i = 0; i < surface->numSTArrays; i++ )
589 if( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) )
591 for( i = 0; i < surface->numColorArrays; i++ )
592 if( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) )
596 /* set vertex count to higher */
597 if( numVertexes > surface->numVertexes )
598 surface->numVertexes = numVertexes;
600 /* additional st arrays? */
601 while( numSTArrays > surface->maxSTArrays ) /* fix */
603 surface->maxSTArrays += PICO_GROW_ARRAYS;
604 if( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) )
606 while( surface->numSTArrays < numSTArrays )
608 surface->st[ surface->numSTArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
609 memset( surface->st[ surface->numSTArrays ], 0, surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
610 surface->numSTArrays++;
614 /* additional color arrays? */
615 while( numColorArrays > surface->maxColorArrays ) /* fix */
617 surface->maxColorArrays += PICO_GROW_ARRAYS;
618 if( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) )
620 while( surface->numColorArrays < numColorArrays )
622 surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
623 memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
624 surface->numColorArrays++;
628 /* additional indexes? */
629 while( numIndexes > surface->maxIndexes ) /* fix */
631 surface->maxIndexes += PICO_GROW_INDEXES;
632 if( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) )
636 /* set index count to higher */
637 if( numIndexes > surface->numIndexes )
638 surface->numIndexes = numIndexes;
640 /* additional face normals? */
641 while( numFaceNormals > surface->maxFaceNormals ) /* fix */
643 surface->maxFaceNormals += PICO_GROW_FACES;
644 if( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) )
648 /* set face normal count to higher */
649 if( numFaceNormals > surface->numFaceNormals )
650 surface->numFaceNormals = numFaceNormals;
658 * Finds first matching named surface in a model.
660 picoSurface_t *PicoFindSurface(
661 picoModel_t *model, char *name, int caseSensitive )
666 if( model == NULL || name == NULL )
670 for( i = 0; i < model->numSurfaces; i++ )
672 /* skip null surfaces or surfaces with null names */
673 if( model->surface[ i ] == NULL ||
674 model->surface[ i ]->name == NULL )
677 /* compare the surface name with name we're looking for */
679 if( !strcmp(name,model->surface[ i ]->name) )
680 return model->surface[ i ];
682 if( !_pico_stricmp(name,model->surface[ i ]->name) )
683 return model->surface[ i ];
686 /* named surface not found */
692 /*----------------------------------------------------------------------------
693 PicoSet*() Setter Functions
694 ----------------------------------------------------------------------------*/
696 void PicoSetModelName( picoModel_t *model, char *name )
698 if( model == NULL || name == NULL )
700 if( model->name != NULL )
701 _pico_free( model->name );
703 model->name = _pico_clone_alloc( name,-1 );
708 void PicoSetModelFileName( picoModel_t *model, char *fileName )
710 if( model == NULL || fileName == NULL )
712 if( model->fileName != NULL )
713 _pico_free( model->fileName );
715 model->fileName = _pico_clone_alloc( fileName,-1 );
720 void PicoSetModelFrameNum( picoModel_t *model, int frameNum )
724 model->frameNum = frameNum;
729 void PicoSetModelNumFrames( picoModel_t *model, int numFrames )
733 model->numFrames = numFrames;
738 void PicoSetModelData( picoModel_t *model, void *data )
747 void PicoSetShaderName( picoShader_t *shader, char *name )
749 if( shader == NULL || name == NULL )
751 if( shader->name != NULL )
752 _pico_free( shader->name );
754 shader->name = _pico_clone_alloc( name,-1 );
759 void PicoSetShaderMapName( picoShader_t *shader, char *mapName )
761 if( shader == NULL || mapName == NULL )
763 if( shader->mapName != NULL )
764 _pico_free( shader->mapName );
766 shader->mapName = _pico_clone_alloc( mapName,-1 );
771 void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color )
773 if( shader == NULL || color == NULL )
775 shader->ambientColor[ 0 ] = color[ 0 ];
776 shader->ambientColor[ 1 ] = color[ 1 ];
777 shader->ambientColor[ 2 ] = color[ 2 ];
778 shader->ambientColor[ 3 ] = color[ 3 ];
783 void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color )
785 if( shader == NULL || color == NULL )
787 shader->diffuseColor[ 0 ] = color[ 0 ];
788 shader->diffuseColor[ 1 ] = color[ 1 ];
789 shader->diffuseColor[ 2 ] = color[ 2 ];
790 shader->diffuseColor[ 3 ] = color[ 3 ];
795 void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color )
797 if( shader == NULL || color == NULL )
799 shader->specularColor[ 0 ] = color[ 0 ];
800 shader->specularColor[ 1 ] = color[ 1 ];
801 shader->specularColor[ 2 ] = color[ 2 ];
802 shader->specularColor[ 3 ] = color[ 3 ];
807 void PicoSetShaderTransparency( picoShader_t *shader, float value )
811 shader->transparency = value;
813 /* cap to 0..1 range */
814 if (shader->transparency < 0.0)
815 shader->transparency = 0.0;
816 if (shader->transparency > 1.0)
817 shader->transparency = 1.0;
822 void PicoSetShaderShininess( picoShader_t *shader, float value )
826 shader->shininess = value;
828 /* cap to 0..127 range */
829 if (shader->shininess < 0.0)
830 shader->shininess = 0.0;
831 if (shader->shininess > 127.0)
832 shader->shininess = 127.0;
837 void PicoSetSurfaceData( picoSurface_t *surface, void *data )
839 if( surface == NULL )
841 surface->data = data;
846 void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type )
848 if( surface == NULL )
850 surface->type = type;
855 void PicoSetSurfaceName( picoSurface_t *surface, char *name )
857 if( surface == NULL || name == NULL )
859 if( surface->name != NULL )
860 _pico_free( surface->name );
862 surface->name = _pico_clone_alloc( name,-1 );
867 void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader )
869 if( surface == NULL )
871 surface->shader = shader;
876 void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz )
878 if( surface == NULL || num < 0 || xyz == NULL )
880 if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) )
882 _pico_copy_vec( xyz, surface->xyz[ num ] );
883 if( surface->model != NULL )
884 _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs );
889 void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal )
891 if( surface == NULL || num < 0 || normal == NULL )
893 if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) )
895 _pico_copy_vec( normal, surface->normal[ num ] );
900 void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st )
902 if( surface == NULL || num < 0 || st == NULL )
904 if( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) )
906 surface->st[ array ][ num ][ 0 ] = st[ 0 ];
907 surface->st[ array ][ num ][ 1 ] = st[ 1 ];
912 void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color )
914 if( surface == NULL || num < 0 || color == NULL )
916 if( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) )
918 surface->color[ array ][ num ][ 0 ] = color[ 0 ];
919 surface->color[ array ][ num ][ 1 ] = color[ 1 ];
920 surface->color[ array ][ num ][ 2 ] = color[ 2 ];
921 surface->color[ array ][ num ][ 3 ] = color[ 3 ];
926 void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index )
928 if( surface == NULL || num < 0 )
930 if( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) )
932 surface->index[ num ] = index;
937 void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count )
939 if( num < 0 || index == NULL || count < 1 )
941 if( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) )
943 memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) );
948 void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal )
950 if( surface == NULL || num < 0 || normal == NULL )
952 if( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) )
954 _pico_copy_vec( normal, surface->faceNormal[ num ] );
958 void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special )
960 if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL )
962 surface->special[ num ] = special;
967 /*----------------------------------------------------------------------------
968 PicoGet*() Getter Functions
969 ----------------------------------------------------------------------------*/
971 char *PicoGetModelName( picoModel_t *model )
975 if( model->name == NULL)
982 char *PicoGetModelFileName( picoModel_t *model )
986 if( model->fileName == NULL)
988 return model->fileName;
993 int PicoGetModelFrameNum( picoModel_t *model )
997 return model->frameNum;
1002 int PicoGetModelNumFrames( picoModel_t *model )
1006 return model->numFrames;
1011 void *PicoGetModelData( picoModel_t *model )
1020 int PicoGetModelNumShaders( picoModel_t *model )
1024 return model->numShaders;
1029 picoShader_t *PicoGetModelShader( picoModel_t *model, int num )
1031 /* a few sanity checks */
1034 if( model->shader == NULL)
1036 if( num < 0 || num >= model->numShaders )
1039 /* return the shader */
1040 return model->shader[ num ];
1045 int PicoGetModelNumSurfaces( picoModel_t *model )
1049 return model->numSurfaces;
1054 picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num )
1056 /* a few sanity checks */
1059 if( model->surface == NULL)
1061 if( num < 0 || num >= model->numSurfaces )
1064 /* return the surface */
1065 return model->surface[ num ];
1070 int PicoGetModelTotalVertexes( picoModel_t *model )
1077 if( model->surface == NULL )
1081 for( i = 0; i < model->numSurfaces; i++ )
1082 count += PicoGetSurfaceNumVertexes( model->surface[ i ] );
1089 int PicoGetModelTotalIndexes( picoModel_t *model )
1096 if( model->surface == NULL )
1100 for( i = 0; i < model->numSurfaces; i++ )
1101 count += PicoGetSurfaceNumIndexes( model->surface[ i ] );
1108 char *PicoGetShaderName( picoShader_t *shader )
1110 if( shader == NULL )
1112 if( shader->name == NULL)
1114 return shader->name;
1119 char *PicoGetShaderMapName( picoShader_t *shader )
1121 if( shader == NULL )
1123 if( shader->mapName == NULL)
1125 return shader->mapName;
1130 picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader )
1132 if( shader == NULL )
1134 return shader->ambientColor;
1139 picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader )
1141 if( shader == NULL )
1143 return shader->diffuseColor;
1148 picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader )
1150 if( shader == NULL )
1152 return shader->specularColor;
1157 float PicoGetShaderTransparency( picoShader_t *shader )
1159 if( shader == NULL )
1161 return shader->transparency;
1166 float PicoGetShaderShininess( picoShader_t *shader )
1168 if( shader == NULL )
1170 return shader->shininess;
1175 void *PicoGetSurfaceData( picoSurface_t *surface )
1177 if( surface == NULL )
1179 return surface->data;
1184 picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface )
1186 if( surface == NULL )
1188 return surface->type;
1193 char *PicoGetSurfaceName( picoSurface_t *surface )
1195 if( surface == NULL )
1197 if( surface->name == NULL )
1199 return surface->name;
1204 picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface )
1206 if( surface == NULL )
1208 return surface->shader;
1213 int PicoGetSurfaceNumVertexes( picoSurface_t *surface )
1215 if( surface == NULL )
1217 return surface->numVertexes;
1222 picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num )
1224 if( surface == NULL || num < 0 || num > surface->numVertexes )
1226 return surface->xyz[ num ];
1231 picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num )
1233 if( surface == NULL || num < 0 || num > surface->numVertexes )
1235 return surface->normal[ num ];
1240 picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num )
1242 if( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes )
1244 return surface->st[ array ][ num ];
1249 picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num )
1251 if( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes )
1253 return surface->color[ array ][ num ];
1258 int PicoGetSurfaceNumIndexes( picoSurface_t *surface )
1260 if( surface == NULL )
1262 return surface->numIndexes;
1267 picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num )
1269 if( surface == NULL || num < 0 || num > surface->numIndexes )
1271 return surface->index[ num ];
1276 picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num )
1278 if( surface == NULL || num < 0 || num > surface->numIndexes )
1280 return &surface->index[ num ];
1284 picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num )
1286 if( surface == NULL || num < 0 || num > surface->numFaceNormals )
1288 return surface->faceNormal[ num ];
1292 int PicoGetSurfaceSpecial( picoSurface_t *surface, int num )
1294 if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL )
1296 return surface->special[ num ];
1301 /* ----------------------------------------------------------------------------
1302 hashtable related functions
1303 ---------------------------------------------------------------------------- */
1305 /* hashtable code for faster vertex lookups */
1306 //#define HASHTABLE_SIZE 32768 // 2048 /* power of 2, use & */
1307 #define HASHTABLE_SIZE 7919 // 32749 // 2039 /* prime, use % */
1309 int PicoGetHashTableSize( void )
1311 return HASHTABLE_SIZE;
1314 #define HASH_USE_EPSILON
1316 #ifdef HASH_USE_EPSILON
1317 #define HASH_XYZ_EPSILON 0.01f
1318 #define HASH_XYZ_EPSILONSPACE_MULTIPLIER 1.f / HASH_XYZ_EPSILON
1319 #define HASH_ST_EPSILON 0.0001f
1320 #define HASH_NORMAL_EPSILON 0.02f
1323 unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz )
1325 unsigned int hash = 0;
1327 #ifndef HASH_USE_EPSILON
1328 hash += ~(*((unsigned int*) &xyz[ 0 ]) << 15);
1329 hash ^= (*((unsigned int*) &xyz[ 0 ]) >> 10);
1330 hash += (*((unsigned int*) &xyz[ 1 ]) << 3);
1331 hash ^= (*((unsigned int*) &xyz[ 1 ]) >> 6);
1332 hash += ~(*((unsigned int*) &xyz[ 2 ]) << 11);
1333 hash ^= (*((unsigned int*) &xyz[ 2 ]) >> 16);
1335 picoVec3_t xyz_epsilonspace;
1337 _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace );
1338 xyz_epsilonspace[ 0 ] = (float)floor(xyz_epsilonspace[ 0 ]);
1339 xyz_epsilonspace[ 1 ] = (float)floor(xyz_epsilonspace[ 1 ]);
1340 xyz_epsilonspace[ 2 ] = (float)floor(xyz_epsilonspace[ 2 ]);
1342 hash += ~(*((unsigned int*) &xyz_epsilonspace[ 0 ]) << 15);
1343 hash ^= (*((unsigned int*) &xyz_epsilonspace[ 0 ]) >> 10);
1344 hash += (*((unsigned int*) &xyz_epsilonspace[ 1 ]) << 3);
1345 hash ^= (*((unsigned int*) &xyz_epsilonspace[ 1 ]) >> 6);
1346 hash += ~(*((unsigned int*) &xyz_epsilonspace[ 2 ]) << 11);
1347 hash ^= (*((unsigned int*) &xyz_epsilonspace[ 2 ]) >> 16);
1350 //hash = hash & (HASHTABLE_SIZE-1);
1351 hash = hash % (HASHTABLE_SIZE);
1355 picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void )
1357 picoVertexCombinationHash_t **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) );
1359 memset( hashTable, 0, HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) );
1364 void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable )
1367 picoVertexCombinationHash_t *vertexCombinationHash;
1368 picoVertexCombinationHash_t *nextVertexCombinationHash;
1371 if (hashTable == NULL)
1374 for( i = 0; i < HASHTABLE_SIZE; i++ )
1378 nextVertexCombinationHash = NULL;
1380 for( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash )
1382 nextVertexCombinationHash = vertexCombinationHash->next;
1383 if (vertexCombinationHash->data != NULL)
1385 _pico_free( vertexCombinationHash->data );
1387 _pico_free( vertexCombinationHash );
1392 _pico_free( hashTable );
1395 picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color )
1398 picoVertexCombinationHash_t *vertexCombinationHash;
1401 if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL )
1404 hash = PicoVertexCoordGenerateHash( xyz );
1406 for( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next )
1408 #ifndef HASH_USE_EPSILON
1410 if( (vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ]) )
1414 if( (vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ]) )
1418 if( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] )
1422 if( ( fabs(xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ]) ) > HASH_XYZ_EPSILON ||
1423 ( fabs(xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ]) ) > HASH_XYZ_EPSILON ||
1424 ( fabs(xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ]) ) > HASH_XYZ_EPSILON )
1428 if( ( fabs(normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ]) ) > HASH_NORMAL_EPSILON ||
1429 ( fabs(normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ]) ) > HASH_NORMAL_EPSILON ||
1430 ( fabs(normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ]) ) > HASH_NORMAL_EPSILON )
1434 if( ( fabs(st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ]) ) > HASH_ST_EPSILON ||
1435 ( fabs(st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ]) ) > HASH_ST_EPSILON )
1440 if( *((int*) vertexCombinationHash->vcd.color) != *((int*) color) )
1444 return vertexCombinationHash;
1450 picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index )
1453 picoVertexCombinationHash_t *vertexCombinationHash;
1456 if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL )
1459 vertexCombinationHash = _pico_alloc( sizeof(picoVertexCombinationHash_t) );
1461 if (!vertexCombinationHash)
1464 hash = PicoVertexCoordGenerateHash( xyz );
1466 _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz );
1467 _pico_copy_vec( normal, vertexCombinationHash->vcd.normal );
1468 _pico_copy_vec2( st, vertexCombinationHash->vcd.st );
1469 _pico_copy_color( color, vertexCombinationHash->vcd.color );
1470 vertexCombinationHash->index = index;
1471 vertexCombinationHash->data = NULL;
1472 vertexCombinationHash->next = hashTable[ hash ];
1473 hashTable[ hash ] = vertexCombinationHash;
1475 return vertexCombinationHash;
1478 /* ----------------------------------------------------------------------------
1479 specialized routines
1480 ---------------------------------------------------------------------------- */
1483 PicoFindSurfaceVertex()
1484 finds a vertex matching the set parameters
1485 fixme: needs non-naive algorithm
1488 int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color )
1494 if( surface == NULL || surface->numVertexes <= 0 )
1497 /* walk vertex list */
1498 for( i = 0; i < surface->numVertexes; i++ )
1501 if( xyz != NULL && (surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ]) )
1505 if( normal != NULL && (surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ]) )
1509 if( numSTs > 0 && st != NULL )
1511 for( j = 0; j < numSTs; j++ )
1513 if( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] )
1521 if( numColors > 0 && color != NULL )
1523 for( j = 0; j < numSTs; j++ )
1525 if( *((int*) surface->color[ j ]) != *((int*) color[ j ]) )
1528 if( j != numColors )
1532 /* vertex matches */
1543 PicoFixSurfaceNormals()
1544 fixes broken normals (certain formats bork normals)
1547 #define MAX_NORMAL_VOTES 128
1548 #define EQUAL_NORMAL_EPSILON 0.01
1549 #define BAD_NORMAL_EPSILON 0.5
1551 void PicoFixSurfaceNormals( picoSurface_t *surface )
1553 int i, j, k, a, b, c, numVotes, faceIndex;
1554 picoVec3_t votes[ MAX_NORMAL_VOTES ];
1555 picoVec3_t *normals, diff;
1560 if( surface == NULL || surface->numVertexes == 0 )
1563 /* fixme: handle other surface types */
1564 if( surface->type != PICO_TRIANGLES )
1567 /* allocate normal storage */
1568 normals = _pico_alloc( surface->numVertexes * sizeof( *normals ) );
1569 if( normals == NULL )
1571 _pico_printf( PICO_ERROR, "PicoFixSurfaceNormals: Unable to allocate memory for temporary normal storage" );
1576 memset( normals, 0, surface->numVertexes * sizeof( *normals ) );
1578 /* walk vertex list */
1579 for( i = 0; i < surface->numVertexes; i++ )
1581 /* zero out votes */
1584 /* find all the triangles that reference this vertex */
1585 for( j = 0, faceIndex = 0; j < surface->numIndexes; j += 3, faceIndex++ )
1588 a = surface->index[ j ];
1589 b = surface->index[ j + 1 ];
1590 c = surface->index[ j + 2 ];
1592 /* ignore degenerate triangles */
1593 if( a == b || b == c || c == a )
1596 /* ignore indexes out of range */
1597 if( a < 0 || a >= surface->numVertexes ||
1598 b < 0 || b >= surface->numVertexes ||
1599 c < 0 || c >= surface->numVertexes )
1603 if( a == i || b == i || c == i )
1605 /* if this surface has face normals */
1606 if( surface->numFaceNormals && faceIndex < surface->numFaceNormals )
1608 _pico_copy_vec( surface->faceNormal[ faceIndex ], plane );
1609 if( plane[ 0 ] == 0.f && plane[ 1 ] == 0.f && plane[ 2 ] == 0.f )
1611 /* if null normal, make plane from the 3 points */
1612 if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 )
1618 /* make a plane from the 3 points */
1619 else if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 )
1624 /* see if this normal has already been voted */
1625 for( k = 0; k < numVotes; k++ )
1627 _pico_subtract_vec( plane, votes[ k ], diff );
1628 if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
1629 fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
1630 fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON )
1634 /* add a new vote? */
1635 if( k == numVotes && numVotes < MAX_NORMAL_VOTES )
1637 _pico_copy_vec( plane, votes[ numVotes ] );
1646 /* create average normal */
1647 _pico_zero_vec( normals[ i ] );
1648 for( k = 0; k < numVotes; k++ )
1649 _pico_add_vec( normals[ i ], votes[ k ], normals[ i ] );
1652 if( _pico_normalize_vec( normals[ i ] ) )
1654 /* test against actual normal */
1655 if( fabs( _pico_dot_vec( normals[ i ], surface->normal[ i ] ) - 1 ) > BAD_NORMAL_EPSILON )
1657 //% printf( "Normal %8d: (%f %f %f) -> (%f %f %f)\n", i,
1658 //% surface->normal[ i ][ 0 ], surface->normal[ i ][ 1 ], surface->normal[ i ][ 2 ],
1659 //% normals[ i ][ 0 ], normals[ i ][ 1 ], normals[ i ][ 2 ] );
1660 _pico_copy_vec( normals[ i ], surface->normal[ i ] );
1666 /* free normal storage */
1667 _pico_free( normals );
1674 PicoRemapModel() - sea
1675 remaps model material/etc. information using the remappings
1676 contained in the given 'remapFile' (full path to the ascii file to open)
1677 returns 1 on success or 0 on error
1680 #define _prm_error_return \
1682 _pico_free_parser( p ); \
1683 _pico_free_file( remapBuffer ); \
1687 int PicoRemapModel( picoModel_t *model, char *remapFile )
1690 picoByte_t *remapBuffer;
1695 if( model == NULL || remapFile == NULL )
1698 /* load remap file contents */
1699 _pico_load_file( remapFile,&remapBuffer,&remapBufSize );
1702 if( remapBufSize == 0 )
1703 return 1; /* file is empty: no error */
1704 if( remapBufSize < 0 )
1705 return 0; /* load failed: error */
1707 /* create a new pico parser */
1708 p = _pico_new_parser( remapBuffer, remapBufSize );
1711 /* ram is really cheap nowadays... */
1718 /* get next token in remap file */
1719 if (!_pico_parse( p,1 ))
1722 /* skip over c++ style comment lines */
1723 if (!_pico_stricmp(p->token,"//"))
1725 _pico_parse_skip_rest( p );
1729 /* block for quick material shader name remapping */
1730 /* materials { "m" (=>|->|=) "s" } */
1731 if( !_pico_stricmp(p->token, "materials" ) )
1736 if (!_pico_parse_check( p,1,"{" ))
1739 /* process assignments */
1742 picoShader_t *shader;
1746 /* get material name */
1747 if (_pico_parse( p,1 ) == NULL) break;
1748 if (!strlen(p->token)) continue;
1749 materialName = _pico_clone_alloc( p->token,-1 );
1750 if (materialName == NULL)
1754 if (p->token[0] == '{') level++;
1755 if (p->token[0] == '}') level--;
1758 /* get next token (assignment token or shader name) */
1759 if (!_pico_parse( p,0 ))
1761 _pico_free( materialName );
1764 /* skip assignment token (if present) */
1765 if (!strcmp(p->token,"=>") ||
1766 !strcmp(p->token,"->") ||
1767 !strcmp(p->token,"="))
1769 /* simply grab the next token */
1770 if (!_pico_parse( p,0 ))
1772 _pico_free( materialName );
1776 /* try to find material by name */
1777 shader = PicoFindShader( model,materialName,0 );
1779 /* we've found a material matching the name */
1782 PicoSetShaderName( shader,p->token );
1784 /* free memory used by material name */
1785 _pico_free( materialName );
1788 _pico_parse_skip_rest( p );
1791 /* block for detailed single material remappings */
1792 /* materials[ "m" ] { key data... } */
1793 else if (!_pico_stricmp(p->token,"materials["))
1795 picoShader_t *shader;
1796 char *tempMaterialName;
1799 /* get material name */
1800 if (!_pico_parse( p,0 ))
1803 /* temporary copy of material name */
1804 tempMaterialName = _pico_clone_alloc( p->token,-1 );
1805 if (tempMaterialName == NULL)
1808 /* check square closing bracket */
1809 if (!_pico_parse_check( p,0,"]" ))
1812 /* try to find material by name */
1813 shader = PicoFindShader( model,tempMaterialName,0 );
1815 /* free memory used by temporary material name */
1816 _pico_free( tempMaterialName );
1818 /* we haven't found a material matching the name */
1819 /* so we simply skip the braced section now and */
1820 /* continue parsing with the next main token */
1823 _pico_parse_skip_braced( p );
1826 /* check opening bracket */
1827 if (!_pico_parse_check( p,1,"{" ))
1830 /* process material info keys */
1834 if (_pico_parse( p,1 ) == NULL) break;
1835 if (!strlen(p->token)) continue;
1838 if (p->token[0] == '{') level++;
1839 if (p->token[0] == '}') level--;
1842 /* remap shader name */
1843 if (!_pico_stricmp(p->token,"shader"))
1845 if (!_pico_parse( p,0 )) _prm_error_return;
1846 PicoSetShaderName( shader,p->token );
1848 /* remap shader map name */
1849 else if (!_pico_stricmp(p->token,"mapname"))
1851 if (!_pico_parse( p,0 )) _prm_error_return;
1852 PicoSetShaderMapName( shader,p->token );
1854 /* remap shader's ambient color */
1855 else if (!_pico_stricmp(p->token,"ambient"))
1860 /* get vector from parser */
1861 if (!_pico_parse_vec( p,v )) _prm_error_return;
1863 /* store as color */
1864 color[ 0 ] = (picoByte_t)v[ 0 ];
1865 color[ 1 ] = (picoByte_t)v[ 1 ];
1866 color[ 2 ] = (picoByte_t)v[ 2 ];
1869 /* set new ambient color */
1870 PicoSetShaderAmbientColor( shader,color );
1872 /* remap shader's diffuse color */
1873 else if (!_pico_stricmp(p->token,"diffuse"))
1878 /* get vector from parser */
1879 if (!_pico_parse_vec( p,v )) _prm_error_return;
1881 /* store as color */
1882 color[ 0 ] = (picoByte_t)v[ 0 ];
1883 color[ 1 ] = (picoByte_t)v[ 1 ];
1884 color[ 2 ] = (picoByte_t)v[ 2 ];
1887 /* set new ambient color */
1888 PicoSetShaderDiffuseColor( shader,color );
1890 /* remap shader's specular color */
1891 else if (!_pico_stricmp(p->token,"specular"))
1896 /* get vector from parser */
1897 if (!_pico_parse_vec( p,v )) _prm_error_return;
1899 /* store as color */
1900 color[ 0 ] = (picoByte_t)v[ 0 ];
1901 color[ 1 ] = (picoByte_t)v[ 1 ];
1902 color[ 2 ] = (picoByte_t)v[ 2 ];
1905 /* set new ambient color */
1906 PicoSetShaderSpecularColor( shader,color );
1909 _pico_parse_skip_rest( p );
1912 /* end 'materials[' */
1915 /* free both parser and file buffer */
1916 _pico_free_parser( p );
1917 _pico_free_file( remapBuffer );
1919 /* return with success */
1925 PicoAddTriangleToModel() - jhefty
1926 A nice way to add individual triangles to the model.
1927 Chooses an appropriate surface based on the shader, or adds a new surface if necessary
1930 void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals,
1931 int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors,
1932 picoShader_t* shader )
1936 picoSurface_t* workSurface = NULL;
1938 /* see if a surface already has the shader */
1939 for ( i = 0 ; i < model->numSurfaces ; i++ )
1941 workSurface = model->surface[i];
1942 if ( workSurface->shader == shader )
1948 /* no surface uses this shader yet, so create a new surface */
1949 if ( !workSurface || i >=model->numSurfaces )
1951 /* create a new surface in the model for the unique shader */
1952 workSurface = PicoNewSurface(model);
1955 _pico_printf ( PICO_ERROR , "Could not allocate a new surface!\n" );
1959 /* do surface setup */
1960 PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
1961 PicoSetSurfaceName( workSurface, shader->name );
1962 PicoSetSurfaceShader( workSurface, shader );
1965 /* add the triangle data to the surface */
1966 for ( i = 0 ; i < 3 ; i++ )
1968 /* get the next free spot in the index array */
1969 int newVertIndex = PicoGetSurfaceNumIndexes ( workSurface );
1971 /* get the index of the vertex that we're going to store at newVertIndex */
1972 vertDataIndex = PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i]);
1974 /* the vertex wasn't found, so create a new vertex in the pool from the data we have */
1975 if ( vertDataIndex == -1 )
1977 /* find the next spot for a new vertex */
1978 vertDataIndex = PicoGetSurfaceNumVertexes ( workSurface );
1980 /* assign the data to it */
1981 PicoSetSurfaceXYZ ( workSurface ,vertDataIndex , *xyz[i] );
1982 PicoSetSurfaceNormal ( workSurface , vertDataIndex , *normals[i] );
1984 /* make sure to copy over all available ST's and colors for the vertex */
1985 for ( j = 0 ; j < numColors ; j++ )
1987 PicoSetSurfaceColor( workSurface , j , vertDataIndex , colors[i][j] );
1989 for ( j = 0 ; j < numSTs ; j++ )
1991 PicoSetSurfaceST ( workSurface , j , vertDataIndex , st[i][j] );
1995 /* add this vertex to the triangle */
1996 PicoSetSurfaceIndex ( workSurface , newVertIndex , vertDataIndex );