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
53 /* successfully initialized -sea */
61 shuts the pico model library down
64 void PicoShutdown( void ){
65 /* do something interesting here in the future */
73 returns last picomodel error code (see PME_* defines)
76 int PicoError( void ){
77 /* todo: do something here */
85 sets the ptr to the malloc function
88 void PicoSetMallocFunc( void *( *func )( size_t ) ){
90 _pico_ptr_malloc = func;
98 sets the ptr to the free function
101 void PicoSetFreeFunc( void ( *func )( void* ) ){
102 if ( func != NULL ) {
103 _pico_ptr_free = func;
110 PicoSetLoadFileFunc()
111 sets the ptr to the file load function
114 void PicoSetLoadFileFunc( void ( *func )( char*, unsigned char**, int* ) ){
115 if ( func != NULL ) {
116 _pico_ptr_load_file = func;
123 PicoSetFreeFileFunc()
124 sets the ptr to the free function
127 void PicoSetFreeFileFunc( void ( *func )( void* ) ){
128 if ( func != NULL ) {
129 _pico_ptr_free_file = func;
137 sets the ptr to the print function
140 void PicoSetPrintFunc( void ( *func )( int, const char* ) ){
141 if ( func != NULL ) {
142 _pico_ptr_print = func;
150 the meat and potatoes function
153 picoModel_t *PicoLoadModel( char *fileName, int frameNum ){
154 const picoModule_t **modules, *pm;
158 char *modelFileName, *remapFileName;
164 /* make sure we've got a file name */
165 if ( fileName == NULL ) {
166 _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" );
170 /* load file data (buffer is allocated by host app) */
171 _pico_load_file( fileName, &buffer, &bufSize );
173 _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName );
177 /* get ptr to list of supported modules */
178 modules = PicoModuleList( NULL );
180 /* run it through the various loader functions and try */
181 /* to find a loader that fits the given file data */
182 for ( ; *modules != NULL; modules++ )
192 /* module must be able to load */
193 if ( pm->canload == NULL || pm->load == NULL ) {
197 /* see whether this module can load the model file or not */
198 if ( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK ) {
199 /* use loader provided by module to read the model data */
200 model = pm->load( fileName, frameNum, buffer, bufSize );
201 if ( model == NULL ) {
202 _pico_free_file( buffer );
206 /* assign pointer to file format module */
209 /* get model file name */
210 modelFileName = PicoGetModelFileName( model );
212 /* apply model remappings from <model>.remap */
213 if ( strlen( modelFileName ) ) {
214 /* alloc copy of model file name */
215 remapFileName = _pico_alloc( strlen( modelFileName ) + 20 );
216 if ( remapFileName != NULL ) {
217 /* copy model file name and change extension */
218 strcpy( remapFileName, modelFileName );
219 _pico_setfext( remapFileName, "remap" );
221 /* try to remap model; we don't handle the result */
222 PicoRemapModel( model, remapFileName );
224 /* free the remap file name string */
225 _pico_free( remapFileName );
229 /* model was loaded, so break out of loop */
234 /* free memory used by file buffer */
236 _pico_free_file( buffer );
245 /* ----------------------------------------------------------------------------
247 ---------------------------------------------------------------------------- */
251 creates a new pico model
254 picoModel_t *PicoNewModel( void ){
258 model = _pico_alloc( sizeof( picoModel_t ) );
259 if ( model == NULL ) {
264 memset( model,0,sizeof( picoModel_t ) );
267 _pico_zero_bounds( model->mins,model->maxs );
269 /* set initial frame count to 1 -sea */
270 model->numFrames = 1;
272 /* return ptr to new model */
280 frees a model and all associated data
283 void PicoFreeModel( picoModel_t *model ){
288 if ( model == NULL ) {
294 _pico_free( model->name );
298 for ( i = 0; i < model->numShaders; i++ )
299 PicoFreeShader( model->shader[ i ] );
300 free( model->shader );
303 for ( i = 0; i < model->numSurfaces; i++ )
304 PicoFreeSurface( model->surface[ i ] );
305 free( model->surface );
315 adjusts a models's memory allocations to handle the requested sizes.
316 will always grow, never shrink
319 int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ){
321 if ( model == NULL ) {
326 /* sea: null surface/shader fix (1s=>0s) */
327 if ( numShaders < 0 ) {
330 if ( numSurfaces < 0 ) {
334 /* additional shaders? */
335 while ( numShaders > model->maxShaders )
337 model->maxShaders += PICO_GROW_SHADERS;
338 if ( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) ) {
343 /* set shader count to higher */
344 if ( numShaders > model->numShaders ) {
345 model->numShaders = numShaders;
348 /* additional surfaces? */
349 while ( numSurfaces > model->maxSurfaces )
351 model->maxSurfaces += PICO_GROW_SURFACES;
352 if ( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) ) {
357 /* set shader count to higher */
358 if ( numSurfaces > model->numSurfaces ) {
359 model->numSurfaces = numSurfaces;
368 /* ----------------------------------------------------------------------------
370 ---------------------------------------------------------------------------- */
374 creates a new pico shader and returns its index. -sea
377 picoShader_t *PicoNewShader( picoModel_t *model ){
378 picoShader_t *shader;
381 /* allocate and clear */
382 shader = _pico_alloc( sizeof( picoShader_t ) );
383 if ( shader == NULL ) {
386 memset( shader, 0, sizeof( picoShader_t ) );
388 /* attach it to the model */
389 if ( model != NULL ) {
391 if ( !PicoAdjustModel( model, model->numShaders + 1, 0 ) ) {
392 _pico_free( shader );
396 model->shader[ model->numShaders - 1 ] = shader;
397 shader->model = model;
399 /* setup default shader colors */
400 _pico_set_color( shader->ambientColor,0,0,0,0 );
401 _pico_set_color( shader->diffuseColor,255,255,255,1 );
402 _pico_set_color( shader->specularColor,0,0,0,0 );
404 /* no need to do this, but i do it anyway */
405 shader->transparency = 0;
406 shader->shininess = 0;
408 /* return the newly created shader */
416 frees a shader and all associated data -sea
419 void PicoFreeShader( picoShader_t *shader ){
421 if ( shader == NULL ) {
426 if ( shader->name ) {
427 _pico_free( shader->name );
429 if ( shader->mapName ) {
430 _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 ){
449 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 ) {
462 /* compare the shader name with name we're looking for */
463 if ( caseSensitive ) {
464 if ( !strcmp( name, model->shader[ i ]->name ) ) {
465 return model->shader[ i ];
468 else if ( !_pico_stricmp( name, model->shader[ i ]->name ) ) {
469 return model->shader[ i ];
473 /* named shader not found */
479 /* ----------------------------------------------------------------------------
481 ---------------------------------------------------------------------------- */
485 creates a new pico surface
488 picoSurface_t *PicoNewSurface( picoModel_t *model ){
489 picoSurface_t *surface;
490 char surfaceName[64];
492 /* allocate and clear */
493 surface = _pico_alloc( sizeof( *surface ) );
494 if ( surface == NULL ) {
497 memset( surface, 0, sizeof( *surface ) );
499 /* attach it to the model */
500 if ( model != NULL ) {
502 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 ){
531 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 ){
566 if ( surface == NULL ) {
571 if ( numVertexes < 1 ) {
574 if ( numSTArrays < 1 ) {
577 if ( numColorArrays < 1 ) {
580 if ( numIndexes < 1 ) {
584 /* additional vertexes? */
585 while ( numVertexes > surface->maxVertexes ) /* fix */
587 surface->maxVertexes += PICO_GROW_VERTEXES;
588 if ( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) ) {
591 if ( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) ) {
594 for ( i = 0; i < surface->numSTArrays; i++ )
595 if ( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) ) {
598 for ( i = 0; i < surface->numColorArrays; i++ )
599 if ( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) ) {
604 /* set vertex count to higher */
605 if ( numVertexes > surface->numVertexes ) {
606 surface->numVertexes = numVertexes;
609 /* additional st arrays? */
610 while ( numSTArrays > surface->maxSTArrays ) /* fix */
612 surface->maxSTArrays += PICO_GROW_ARRAYS;
613 if ( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) ) {
616 while ( surface->numSTArrays < numSTArrays )
618 surface->st[ surface->numSTArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
619 memset( surface->st[ surface->numSTArrays ], 0, surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
620 surface->numSTArrays++;
624 /* additional color arrays? */
625 while ( numColorArrays > surface->maxColorArrays ) /* fix */
627 surface->maxColorArrays += PICO_GROW_ARRAYS;
628 if ( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) ) {
631 while ( surface->numColorArrays < numColorArrays )
633 surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
634 memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
635 surface->numColorArrays++;
639 /* additional indexes? */
640 while ( numIndexes > surface->maxIndexes ) /* fix */
642 surface->maxIndexes += PICO_GROW_INDEXES;
643 if ( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) ) {
648 /* set index count to higher */
649 if ( numIndexes > surface->numIndexes ) {
650 surface->numIndexes = numIndexes;
653 /* additional face normals? */
654 while ( numFaceNormals > surface->maxFaceNormals ) /* fix */
656 surface->maxFaceNormals += PICO_GROW_FACES;
657 if ( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) ) {
662 /* set face normal count to higher */
663 if ( numFaceNormals > surface->numFaceNormals ) {
664 surface->numFaceNormals = numFaceNormals;
673 * Finds first matching named surface in a model.
675 picoSurface_t *PicoFindSurface(
676 picoModel_t *model, char *name, int caseSensitive ){
680 if ( model == NULL || name == NULL ) {
685 for ( i = 0; i < model->numSurfaces; i++ )
687 /* skip null surfaces or surfaces with null names */
688 if ( model->surface[ i ] == NULL ||
689 model->surface[ i ]->name == NULL ) {
693 /* compare the surface name with name we're looking for */
694 if ( caseSensitive ) {
695 if ( !strcmp( name,model->surface[ i ]->name ) ) {
696 return model->surface[ i ];
700 if ( !_pico_stricmp( name,model->surface[ i ]->name ) ) {
701 return model->surface[ i ];
705 /* named surface not found */
711 /*----------------------------------------------------------------------------
712 PicoSet*() Setter Functions
713 ----------------------------------------------------------------------------*/
715 void PicoSetModelName( picoModel_t *model, char *name ){
716 if ( model == NULL || name == NULL ) {
719 if ( model->name != NULL ) {
720 _pico_free( model->name );
723 model->name = _pico_clone_alloc( name,-1 );
728 void PicoSetModelFileName( picoModel_t *model, char *fileName ){
729 if ( model == NULL || fileName == NULL ) {
732 if ( model->fileName != NULL ) {
733 _pico_free( model->fileName );
736 model->fileName = _pico_clone_alloc( fileName,-1 );
741 void PicoSetModelFrameNum( picoModel_t *model, int frameNum ){
742 if ( model == NULL ) {
745 model->frameNum = frameNum;
750 void PicoSetModelNumFrames( picoModel_t *model, int numFrames ){
751 if ( model == NULL ) {
754 model->numFrames = numFrames;
759 void PicoSetModelData( picoModel_t *model, void *data ){
760 if ( model == NULL ) {
768 void PicoSetShaderName( picoShader_t *shader, char *name ){
769 if ( shader == NULL || name == NULL ) {
772 if ( shader->name != NULL ) {
773 _pico_free( shader->name );
776 shader->name = _pico_clone_alloc( name,-1 );
781 void PicoSetShaderMapName( picoShader_t *shader, char *mapName ){
782 if ( shader == NULL || mapName == NULL ) {
785 if ( shader->mapName != NULL ) {
786 _pico_free( shader->mapName );
789 shader->mapName = _pico_clone_alloc( mapName,-1 );
794 void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ){
795 if ( shader == NULL || color == NULL ) {
798 shader->ambientColor[ 0 ] = color[ 0 ];
799 shader->ambientColor[ 1 ] = color[ 1 ];
800 shader->ambientColor[ 2 ] = color[ 2 ];
801 shader->ambientColor[ 3 ] = color[ 3 ];
806 void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ){
807 if ( shader == NULL || color == NULL ) {
810 shader->diffuseColor[ 0 ] = color[ 0 ];
811 shader->diffuseColor[ 1 ] = color[ 1 ];
812 shader->diffuseColor[ 2 ] = color[ 2 ];
813 shader->diffuseColor[ 3 ] = color[ 3 ];
818 void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ){
819 if ( shader == NULL || color == NULL ) {
822 shader->specularColor[ 0 ] = color[ 0 ];
823 shader->specularColor[ 1 ] = color[ 1 ];
824 shader->specularColor[ 2 ] = color[ 2 ];
825 shader->specularColor[ 3 ] = color[ 3 ];
830 void PicoSetShaderTransparency( picoShader_t *shader, float value ){
831 if ( shader == NULL ) {
834 shader->transparency = value;
836 /* cap to 0..1 range */
837 if ( shader->transparency < 0.0 ) {
838 shader->transparency = 0.0;
840 if ( shader->transparency > 1.0 ) {
841 shader->transparency = 1.0;
847 void PicoSetShaderShininess( picoShader_t *shader, float value ){
848 if ( shader == NULL ) {
851 shader->shininess = value;
853 /* cap to 0..127 range */
854 if ( shader->shininess < 0.0 ) {
855 shader->shininess = 0.0;
857 if ( shader->shininess > 127.0 ) {
858 shader->shininess = 127.0;
864 void PicoSetSurfaceData( picoSurface_t *surface, void *data ){
865 if ( surface == NULL ) {
868 surface->data = data;
873 void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ){
874 if ( surface == NULL ) {
877 surface->type = type;
882 void PicoSetSurfaceName( picoSurface_t *surface, char *name ){
883 if ( surface == NULL || name == NULL ) {
886 if ( surface->name != NULL ) {
887 _pico_free( surface->name );
890 surface->name = _pico_clone_alloc( name,-1 );
895 void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ){
896 if ( surface == NULL ) {
899 surface->shader = shader;
904 void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ){
905 if ( surface == NULL || num < 0 || xyz == NULL ) {
908 if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
911 _pico_copy_vec( xyz, surface->xyz[ num ] );
912 if ( surface->model != NULL ) {
913 _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs );
919 void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ){
920 if ( surface == NULL || num < 0 || normal == NULL ) {
923 if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
926 _pico_copy_vec( normal, surface->normal[ num ] );
931 void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ){
932 if ( surface == NULL || num < 0 || st == NULL ) {
935 if ( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) ) {
938 surface->st[ array ][ num ][ 0 ] = st[ 0 ];
939 surface->st[ array ][ num ][ 1 ] = st[ 1 ];
944 void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color ){
945 if ( surface == NULL || num < 0 || color == NULL ) {
948 if ( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) ) {
951 surface->color[ array ][ num ][ 0 ] = color[ 0 ];
952 surface->color[ array ][ num ][ 1 ] = color[ 1 ];
953 surface->color[ array ][ num ][ 2 ] = color[ 2 ];
954 surface->color[ array ][ num ][ 3 ] = color[ 3 ];
959 void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ){
960 if ( surface == NULL || num < 0 ) {
963 if ( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) ) {
966 surface->index[ num ] = index;
971 void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ){
972 if ( num < 0 || index == NULL || count < 1 ) {
975 if ( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) ) {
978 memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) );
983 void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ){
984 if ( surface == NULL || num < 0 || normal == NULL ) {
987 if ( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) ) {
990 _pico_copy_vec( normal, surface->faceNormal[ num ] );
994 void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ){
995 if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
998 surface->special[ num ] = special;
1003 /*----------------------------------------------------------------------------
1004 PicoGet*() Getter Functions
1005 ----------------------------------------------------------------------------*/
1007 char *PicoGetModelName( picoModel_t *model ){
1008 if ( model == NULL ) {
1011 if ( model->name == NULL ) {
1019 char *PicoGetModelFileName( picoModel_t *model ){
1020 if ( model == NULL ) {
1023 if ( model->fileName == NULL ) {
1026 return model->fileName;
1031 int PicoGetModelFrameNum( picoModel_t *model ){
1032 if ( model == NULL ) {
1035 return model->frameNum;
1040 int PicoGetModelNumFrames( picoModel_t *model ){
1041 if ( model == NULL ) {
1044 return model->numFrames;
1049 void *PicoGetModelData( picoModel_t *model ){
1050 if ( model == NULL ) {
1058 int PicoGetModelNumShaders( picoModel_t *model ){
1059 if ( model == NULL ) {
1062 return model->numShaders;
1067 picoShader_t *PicoGetModelShader( picoModel_t *model, int num ){
1068 /* a few sanity checks */
1069 if ( model == NULL ) {
1072 if ( model->shader == NULL ) {
1075 if ( num < 0 || num >= model->numShaders ) {
1079 /* return the shader */
1080 return model->shader[ num ];
1085 int PicoGetModelNumSurfaces( picoModel_t *model ){
1086 if ( model == NULL ) {
1089 return model->numSurfaces;
1094 picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ){
1095 /* a few sanity checks */
1096 if ( model == NULL ) {
1099 if ( model->surface == NULL ) {
1102 if ( num < 0 || num >= model->numSurfaces ) {
1106 /* return the surface */
1107 return model->surface[ num ];
1112 int PicoGetModelTotalVertexes( picoModel_t *model ){
1116 if ( model == NULL ) {
1119 if ( model->surface == NULL ) {
1124 for ( i = 0; i < model->numSurfaces; i++ )
1125 count += PicoGetSurfaceNumVertexes( model->surface[ i ] );
1132 int PicoGetModelTotalIndexes( picoModel_t *model ){
1136 if ( model == NULL ) {
1139 if ( model->surface == NULL ) {
1144 for ( i = 0; i < model->numSurfaces; i++ )
1145 count += PicoGetSurfaceNumIndexes( model->surface[ i ] );
1152 char *PicoGetShaderName( picoShader_t *shader ){
1153 if ( shader == NULL ) {
1156 if ( shader->name == NULL ) {
1159 return shader->name;
1164 char *PicoGetShaderMapName( picoShader_t *shader ){
1165 if ( shader == NULL ) {
1168 if ( shader->mapName == NULL ) {
1171 return shader->mapName;
1176 picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ){
1177 if ( shader == NULL ) {
1180 return shader->ambientColor;
1185 picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ){
1186 if ( shader == NULL ) {
1189 return shader->diffuseColor;
1194 picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ){
1195 if ( shader == NULL ) {
1198 return shader->specularColor;
1203 float PicoGetShaderTransparency( picoShader_t *shader ){
1204 if ( shader == NULL ) {
1207 return shader->transparency;
1212 float PicoGetShaderShininess( picoShader_t *shader ){
1213 if ( shader == NULL ) {
1216 return shader->shininess;
1221 void *PicoGetSurfaceData( picoSurface_t *surface ){
1222 if ( surface == NULL ) {
1225 return surface->data;
1230 picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ){
1231 if ( surface == NULL ) {
1234 return surface->type;
1239 char *PicoGetSurfaceName( picoSurface_t *surface ){
1240 if ( surface == NULL ) {
1243 if ( surface->name == NULL ) {
1246 return surface->name;
1251 picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ){
1252 if ( surface == NULL ) {
1255 return surface->shader;
1260 int PicoGetSurfaceNumVertexes( picoSurface_t *surface ){
1261 if ( surface == NULL ) {
1264 return surface->numVertexes;
1269 picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ){
1270 if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
1273 return surface->xyz[ num ];
1278 picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ){
1279 if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
1282 return surface->normal[ num ];
1287 picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ){
1288 if ( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes ) {
1291 return surface->st[ array ][ num ];
1296 picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ){
1297 if ( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes ) {
1300 return surface->color[ array ][ num ];
1305 int PicoGetSurfaceNumIndexes( picoSurface_t *surface ){
1306 if ( surface == NULL ) {
1309 return surface->numIndexes;
1314 picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ){
1315 if ( surface == NULL || num < 0 || num > surface->numIndexes ) {
1318 return surface->index[ num ];
1323 picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ){
1324 if ( surface == NULL || num < 0 || num > surface->numIndexes ) {
1327 return &surface->index[ num ];
1331 picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ){
1332 if ( surface == NULL || num < 0 || num > surface->numFaceNormals ) {
1335 return surface->faceNormal[ num ];
1339 int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ){
1340 if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
1343 return surface->special[ num ];
1348 /* ----------------------------------------------------------------------------
1349 hashtable related functions
1350 ---------------------------------------------------------------------------- */
1352 /* hashtable code for faster vertex lookups */
1353 //#define HASHTABLE_SIZE 32768 // 2048 /* power of 2, use & */
1354 #define HASHTABLE_SIZE 7919 // 32749 // 2039 /* prime, use % */
1356 int PicoGetHashTableSize( void ){
1357 return HASHTABLE_SIZE;
1360 #define HASH_USE_EPSILON
1362 #ifdef HASH_USE_EPSILON
1363 #define HASH_XYZ_EPSILON 0.01f
1364 #define HASH_XYZ_EPSILONSPACE_MULTIPLIER 1.f / HASH_XYZ_EPSILON
1365 #define HASH_ST_EPSILON 0.0001f
1366 #define HASH_NORMAL_EPSILON 0.02f
1369 unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ){
1370 unsigned int hash = 0;
1372 #ifndef HASH_USE_EPSILON
1373 hash += ~( *( (unsigned int*) &xyz[ 0 ] ) << 15 );
1374 hash ^= ( *( (unsigned int*) &xyz[ 0 ] ) >> 10 );
1375 hash += ( *( (unsigned int*) &xyz[ 1 ] ) << 3 );
1376 hash ^= ( *( (unsigned int*) &xyz[ 1 ] ) >> 6 );
1377 hash += ~( *( (unsigned int*) &xyz[ 2 ] ) << 11 );
1378 hash ^= ( *( (unsigned int*) &xyz[ 2 ] ) >> 16 );
1380 picoVec3_t xyz_epsilonspace;
1382 _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace );
1383 xyz_epsilonspace[ 0 ] = (float)floor( xyz_epsilonspace[ 0 ] );
1384 xyz_epsilonspace[ 1 ] = (float)floor( xyz_epsilonspace[ 1 ] );
1385 xyz_epsilonspace[ 2 ] = (float)floor( xyz_epsilonspace[ 2 ] );
1387 hash += ~( *( (unsigned int*) &xyz_epsilonspace[ 0 ] ) << 15 );
1388 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 0 ] ) >> 10 );
1389 hash += ( *( (unsigned int*) &xyz_epsilonspace[ 1 ] ) << 3 );
1390 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 1 ] ) >> 6 );
1391 hash += ~( *( (unsigned int*) &xyz_epsilonspace[ 2 ] ) << 11 );
1392 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 2 ] ) >> 16 );
1395 //hash = hash & (HASHTABLE_SIZE-1);
1396 hash = hash % ( HASHTABLE_SIZE );
1400 picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ){
1401 picoVertexCombinationHash_t **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof( picoVertexCombinationHash_t* ) );
1403 memset( hashTable, 0, HASHTABLE_SIZE * sizeof( picoVertexCombinationHash_t* ) );
1408 void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ){
1410 picoVertexCombinationHash_t *vertexCombinationHash;
1411 picoVertexCombinationHash_t *nextVertexCombinationHash;
1414 if ( hashTable == NULL ) {
1418 for ( i = 0; i < HASHTABLE_SIZE; i++ )
1420 if ( hashTable[ i ] ) {
1421 nextVertexCombinationHash = NULL;
1423 for ( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash )
1425 nextVertexCombinationHash = vertexCombinationHash->next;
1426 if ( vertexCombinationHash->data != NULL ) {
1427 _pico_free( vertexCombinationHash->data );
1429 _pico_free( vertexCombinationHash );
1434 _pico_free( hashTable );
1437 picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ){
1439 picoVertexCombinationHash_t *vertexCombinationHash;
1442 if ( hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) {
1446 hash = PicoVertexCoordGenerateHash( xyz );
1448 for ( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next )
1450 #ifndef HASH_USE_EPSILON
1452 if ( ( vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ] ) ) {
1457 if ( ( vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ] ) ) {
1462 if ( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] ) {
1467 if ( ( fabs( xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ] ) ) > HASH_XYZ_EPSILON ||
1468 ( fabs( xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ] ) ) > HASH_XYZ_EPSILON ||
1469 ( fabs( xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ] ) ) > HASH_XYZ_EPSILON ) {
1474 if ( ( fabs( normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ] ) ) > HASH_NORMAL_EPSILON ||
1475 ( fabs( normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ] ) ) > HASH_NORMAL_EPSILON ||
1476 ( fabs( normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ] ) ) > HASH_NORMAL_EPSILON ) {
1481 if ( ( fabs( st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ] ) ) > HASH_ST_EPSILON ||
1482 ( fabs( st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ] ) ) > HASH_ST_EPSILON ) {
1488 if ( *( (int*) vertexCombinationHash->vcd.color ) != *( (int*) color ) ) {
1493 return vertexCombinationHash;
1499 picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ){
1501 picoVertexCombinationHash_t *vertexCombinationHash;
1504 if ( hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) {
1508 vertexCombinationHash = _pico_alloc( sizeof( picoVertexCombinationHash_t ) );
1510 if ( !vertexCombinationHash ) {
1514 hash = PicoVertexCoordGenerateHash( xyz );
1516 _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz );
1517 _pico_copy_vec( normal, vertexCombinationHash->vcd.normal );
1518 _pico_copy_vec2( st, vertexCombinationHash->vcd.st );
1519 _pico_copy_color( color, vertexCombinationHash->vcd.color );
1520 vertexCombinationHash->index = index;
1521 vertexCombinationHash->data = NULL;
1522 vertexCombinationHash->next = hashTable[ hash ];
1523 hashTable[ hash ] = vertexCombinationHash;
1525 return vertexCombinationHash;
1528 /* ----------------------------------------------------------------------------
1529 specialized routines
1530 ---------------------------------------------------------------------------- */
1533 PicoFindSurfaceVertex()
1534 finds a vertex matching the set parameters
1535 fixme: needs non-naive algorithm
1538 int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ){
1543 if ( surface == NULL || surface->numVertexes <= 0 ) {
1547 /* walk vertex list */
1548 for ( i = 0; i < surface->numVertexes; i++ )
1551 if ( xyz != NULL && ( surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ] ) ) {
1556 if ( normal != NULL && ( surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ] ) ) {
1561 if ( numSTs > 0 && st != NULL ) {
1562 for ( j = 0; j < numSTs; j++ )
1564 if ( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] ) {
1568 if ( j != numSTs ) {
1574 if ( numColors > 0 && color != NULL ) {
1575 for ( j = 0; j < numSTs; j++ )
1577 if ( *( (int*) surface->color[ j ] ) != *( (int*) color[ j ] ) ) {
1581 if ( j != numColors ) {
1586 /* vertex matches */
1597 PicoFixSurfaceNormals()
1598 fixes broken normals (certain formats bork normals)
1601 #define MAX_NORMAL_VOTES 128
1602 #define EQUAL_NORMAL_EPSILON 0.01
1603 #define BAD_NORMAL_EPSILON 0.5
1605 void PicoFixSurfaceNormals( picoSurface_t *surface ){
1606 int i, j, k, a, b, c, numVotes, faceIndex;
1607 picoVec3_t votes[ MAX_NORMAL_VOTES ];
1608 picoVec3_t *normals, diff;
1613 if ( surface == NULL || surface->numVertexes == 0 ) {
1617 /* fixme: handle other surface types */
1618 if ( surface->type != PICO_TRIANGLES ) {
1622 /* allocate normal storage */
1623 normals = _pico_alloc( surface->numVertexes * sizeof( *normals ) );
1624 if ( normals == NULL ) {
1625 _pico_printf( PICO_ERROR, "PicoFixSurfaceNormals: Unable to allocate memory for temporary normal storage" );
1630 memset( normals, 0, surface->numVertexes * sizeof( *normals ) );
1632 /* walk vertex list */
1633 for ( i = 0; i < surface->numVertexes; i++ )
1635 /* zero out votes */
1638 /* find all the triangles that reference this vertex */
1639 for ( j = 0, faceIndex = 0; j < surface->numIndexes; j += 3, faceIndex++ )
1642 a = surface->index[ j ];
1643 b = surface->index[ j + 1 ];
1644 c = surface->index[ j + 2 ];
1646 /* ignore degenerate triangles */
1647 if ( a == b || b == c || c == a ) {
1651 /* ignore indexes out of range */
1652 if ( a < 0 || a >= surface->numVertexes ||
1653 b < 0 || b >= surface->numVertexes ||
1654 c < 0 || c >= surface->numVertexes ) {
1659 if ( a == i || b == i || c == i ) {
1660 /* if this surface has face normals */
1661 if ( surface->numFaceNormals && faceIndex < surface->numFaceNormals ) {
1662 _pico_copy_vec( surface->faceNormal[ faceIndex ], plane );
1663 if ( plane[ 0 ] == 0.f && plane[ 1 ] == 0.f && plane[ 2 ] == 0.f ) {
1664 /* if null normal, make plane from the 3 points */
1665 if ( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) {
1670 /* make a plane from the 3 points */
1671 else if ( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) {
1675 /* see if this normal has already been voted */
1676 for ( k = 0; k < numVotes; k++ )
1678 _pico_subtract_vec( plane, votes[ k ], diff );
1679 if ( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
1680 fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
1681 fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON ) {
1686 /* add a new vote? */
1687 if ( k == numVotes && numVotes < MAX_NORMAL_VOTES ) {
1688 _pico_copy_vec( plane, votes[ numVotes ] );
1695 if ( numVotes > 0 ) {
1696 /* create average normal */
1697 _pico_zero_vec( normals[ i ] );
1698 for ( k = 0; k < numVotes; k++ )
1699 _pico_add_vec( normals[ i ], votes[ k ], normals[ i ] );
1702 if ( _pico_normalize_vec( normals[ i ] ) ) {
1703 /* test against actual normal */
1704 if ( fabs( _pico_dot_vec( normals[ i ], surface->normal[ i ] ) - 1 ) > BAD_NORMAL_EPSILON ) {
1705 //% printf( "Normal %8d: (%f %f %f) -> (%f %f %f)\n", i,
1706 //% surface->normal[ i ][ 0 ], surface->normal[ i ][ 1 ], surface->normal[ i ][ 2 ],
1707 //% normals[ i ][ 0 ], normals[ i ][ 1 ], normals[ i ][ 2 ] );
1708 _pico_copy_vec( normals[ i ], surface->normal[ i ] );
1714 /* free normal storage */
1715 _pico_free( normals );
1722 PicoRemapModel() - sea
1723 remaps model material/etc. information using the remappings
1724 contained in the given 'remapFile' (full path to the ascii file to open)
1725 returns 1 on success or 0 on error
1728 #define _prm_error_return \
1730 _pico_free_parser( p ); \
1731 _pico_free_file( remapBuffer ); \
1735 int PicoRemapModel( picoModel_t *model, char *remapFile ){
1737 picoByte_t *remapBuffer;
1742 if ( model == NULL || remapFile == NULL ) {
1746 /* load remap file contents */
1747 _pico_load_file( remapFile,&remapBuffer,&remapBufSize );
1750 if ( remapBufSize == 0 ) {
1751 return 1; /* file is empty: no error */
1753 if ( remapBufSize < 0 ) {
1754 return 0; /* load failed: error */
1757 /* create a new pico parser */
1758 p = _pico_new_parser( remapBuffer, remapBufSize );
1760 /* ram is really cheap nowadays... */
1767 /* get next token in remap file */
1768 if ( !_pico_parse( p,1 ) ) {
1772 /* skip over c++ style comment lines */
1773 if ( !_pico_stricmp( p->token,"//" ) ) {
1774 _pico_parse_skip_rest( p );
1778 /* block for quick material shader name remapping */
1779 /* materials { "m" (=>|->|=) "s" } */
1780 if ( !_pico_stricmp( p->token, "materials" ) ) {
1784 if ( !_pico_parse_check( p,1,"{" ) ) {
1788 /* process assignments */
1791 picoShader_t *shader;
1795 /* get material name */
1796 if ( _pico_parse( p,1 ) == NULL ) {
1799 if ( !strlen( p->token ) ) {
1802 materialName = _pico_clone_alloc( p->token,-1 );
1803 if ( materialName == NULL ) {
1808 if ( p->token[0] == '{' ) {
1811 if ( p->token[0] == '}' ) {
1818 /* get next token (assignment token or shader name) */
1819 if ( !_pico_parse( p,0 ) ) {
1820 _pico_free( materialName );
1823 /* skip assignment token (if present) */
1824 if ( !strcmp( p->token,"=>" ) ||
1825 !strcmp( p->token,"->" ) ||
1826 !strcmp( p->token,"=" ) ) {
1827 /* simply grab the next token */
1828 if ( !_pico_parse( p,0 ) ) {
1829 _pico_free( materialName );
1833 /* try to find material by name */
1834 shader = PicoFindShader( model,materialName,0 );
1836 /* we've found a material matching the name */
1837 if ( shader != NULL ) {
1838 PicoSetShaderName( shader,p->token );
1840 /* free memory used by material name */
1841 _pico_free( materialName );
1844 _pico_parse_skip_rest( p );
1847 /* block for detailed single material remappings */
1848 /* materials[ "m" ] { key data... } */
1849 else if ( !_pico_stricmp( p->token,"materials[" ) ) {
1850 picoShader_t *shader;
1851 char *tempMaterialName;
1854 /* get material name */
1855 if ( !_pico_parse( p,0 ) ) {
1859 /* temporary copy of material name */
1860 tempMaterialName = _pico_clone_alloc( p->token,-1 );
1861 if ( tempMaterialName == NULL ) {
1865 /* check square closing bracket */
1866 if ( !_pico_parse_check( p,0,"]" ) ) {
1870 /* try to find material by name */
1871 shader = PicoFindShader( model,tempMaterialName,0 );
1873 /* free memory used by temporary material name */
1874 _pico_free( tempMaterialName );
1876 /* we haven't found a material matching the name */
1877 /* so we simply skip the braced section now and */
1878 /* continue parsing with the next main token */
1879 if ( shader == NULL ) {
1880 _pico_parse_skip_braced( p );
1883 /* check opening bracket */
1884 if ( !_pico_parse_check( p,1,"{" ) ) {
1888 /* process material info keys */
1892 if ( _pico_parse( p,1 ) == NULL ) {
1895 if ( !strlen( p->token ) ) {
1900 if ( p->token[0] == '{' ) {
1903 if ( p->token[0] == '}' ) {
1910 /* remap shader name */
1911 if ( !_pico_stricmp( p->token,"shader" ) ) {
1912 if ( !_pico_parse( p,0 ) ) {
1915 PicoSetShaderName( shader,p->token );
1917 /* remap shader map name */
1918 else if ( !_pico_stricmp( p->token,"mapname" ) ) {
1919 if ( !_pico_parse( p,0 ) ) {
1922 PicoSetShaderMapName( shader,p->token );
1924 /* remap shader's ambient color */
1925 else if ( !_pico_stricmp( p->token,"ambient" ) ) {
1929 /* get vector from parser */
1930 if ( !_pico_parse_vec( p,v ) ) {
1934 /* store as color */
1935 color[ 0 ] = (picoByte_t)v[ 0 ];
1936 color[ 1 ] = (picoByte_t)v[ 1 ];
1937 color[ 2 ] = (picoByte_t)v[ 2 ];
1940 /* set new ambient color */
1941 PicoSetShaderAmbientColor( shader,color );
1943 /* remap shader's diffuse color */
1944 else if ( !_pico_stricmp( p->token,"diffuse" ) ) {
1948 /* get vector from parser */
1949 if ( !_pico_parse_vec( p,v ) ) {
1953 /* store as color */
1954 color[ 0 ] = (picoByte_t)v[ 0 ];
1955 color[ 1 ] = (picoByte_t)v[ 1 ];
1956 color[ 2 ] = (picoByte_t)v[ 2 ];
1959 /* set new ambient color */
1960 PicoSetShaderDiffuseColor( shader,color );
1962 /* remap shader's specular color */
1963 else if ( !_pico_stricmp( p->token,"specular" ) ) {
1967 /* get vector from parser */
1968 if ( !_pico_parse_vec( p,v ) ) {
1972 /* store as color */
1973 color[ 0 ] = (picoByte_t)v[ 0 ];
1974 color[ 1 ] = (picoByte_t)v[ 1 ];
1975 color[ 2 ] = (picoByte_t)v[ 2 ];
1978 /* set new ambient color */
1979 PicoSetShaderSpecularColor( shader,color );
1982 _pico_parse_skip_rest( p );
1985 /* end 'materials[' */
1988 /* free both parser and file buffer */
1989 _pico_free_parser( p );
1990 _pico_free_file( remapBuffer );
1992 /* return with success */
1998 PicoAddTriangleToModel() - jhefty
1999 A nice way to add individual triangles to the model.
2000 Chooses an appropriate surface based on the shader, or adds a new surface if necessary
2003 void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals,
2004 int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors,
2005 picoShader_t* shader ){
2008 picoSurface_t* workSurface = NULL;
2010 /* see if a surface already has the shader */
2011 for ( i = 0 ; i < model->numSurfaces ; i++ )
2013 workSurface = model->surface[i];
2014 if ( workSurface->shader == shader ) {
2019 /* no surface uses this shader yet, so create a new surface */
2020 if ( !workSurface || i >= model->numSurfaces ) {
2021 /* create a new surface in the model for the unique shader */
2022 workSurface = PicoNewSurface( model );
2023 if ( !workSurface ) {
2024 _pico_printf( PICO_ERROR, "Could not allocate a new surface!\n" );
2028 /* do surface setup */
2029 PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
2030 PicoSetSurfaceName( workSurface, shader->name );
2031 PicoSetSurfaceShader( workSurface, shader );
2034 /* add the triangle data to the surface */
2035 for ( i = 0 ; i < 3 ; i++ )
2037 /* get the next free spot in the index array */
2038 int newVertIndex = PicoGetSurfaceNumIndexes( workSurface );
2040 /* get the index of the vertex that we're going to store at newVertIndex */
2041 vertDataIndex = PicoFindSurfaceVertexNum( workSurface, *xyz[i], *normals[i], numSTs, st[i], numColors, colors[i] );
2043 /* the vertex wasn't found, so create a new vertex in the pool from the data we have */
2044 if ( vertDataIndex == -1 ) {
2045 /* find the next spot for a new vertex */
2046 vertDataIndex = PicoGetSurfaceNumVertexes( workSurface );
2048 /* assign the data to it */
2049 PicoSetSurfaceXYZ( workSurface,vertDataIndex, *xyz[i] );
2050 PicoSetSurfaceNormal( workSurface, vertDataIndex, *normals[i] );
2052 /* make sure to copy over all available ST's and colors for the vertex */
2053 for ( j = 0 ; j < numColors ; j++ )
2055 PicoSetSurfaceColor( workSurface, j, vertDataIndex, colors[i][j] );
2057 for ( j = 0 ; j < numSTs ; j++ )
2059 PicoSetSurfaceST( workSurface, j, vertDataIndex, st[i][j] );
2063 /* add this vertex to the triangle */
2064 PicoSetSurfaceIndex( workSurface, newVertIndex, vertDataIndex );