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