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 ----------------------------------------------------------------------------- */
36 #include "picointernal.h"
42 initializes the picomodel library
46 /* successfully initialized -sea */
54 shuts the pico model library down
57 void PicoShutdown( void ){
58 /* do something interesting here in the future */
66 returns last picomodel error code (see PME_* defines)
69 int PicoError( void ){
70 /* todo: do something here */
78 sets the ptr to the malloc function
81 void PicoSetMallocFunc( void *( *func )( size_t ) ){
83 _pico_ptr_malloc = func;
91 sets the ptr to the free function
94 void PicoSetFreeFunc( void ( *func )( void* ) ){
96 _pico_ptr_free = func;
103 PicoSetLoadFileFunc()
104 sets the ptr to the file load function
107 void PicoSetLoadFileFunc( void ( *func )( const char*, unsigned char**, int* ) ){
108 if ( func != NULL ) {
109 _pico_ptr_load_file = func;
116 PicoSetFreeFileFunc()
117 sets the ptr to the free function
120 void PicoSetFreeFileFunc( void ( *func )( void* ) ){
121 if ( func != NULL ) {
122 _pico_ptr_free_file = func;
130 sets the ptr to the print function
133 void PicoSetPrintFunc( void ( *func )( int, const char* ) ){
134 if ( func != NULL ) {
135 _pico_ptr_print = func;
141 picoModel_t *PicoModuleLoadModel( const picoModule_t* pm, const char* fileName, picoByte_t* buffer, int bufSize, int frameNum ){
142 char *modelFileName, *remapFileName;
144 /* see whether this module can load the model file or not */
145 if ( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK ) {
146 /* use loader provided by module to read the model data */
147 picoModel_t* model = pm->load( fileName, frameNum, buffer, bufSize );
148 if ( model == NULL ) {
149 _pico_free_file( buffer );
153 /* assign pointer to file format module */
156 /* get model file name */
157 modelFileName = PicoGetModelFileName( model );
159 /* apply model remappings from <model>.remap */
160 if ( strlen( modelFileName ) ) {
161 /* alloc copy of model file name */
162 remapFileName = _pico_alloc( strlen( modelFileName ) + 20 );
163 if ( remapFileName != NULL ) {
164 /* copy model file name and change extension */
165 strcpy( remapFileName, modelFileName );
166 _pico_setfext( remapFileName, "remap" );
168 /* try to remap model; we don't handle the result */
169 PicoRemapModel( model, remapFileName );
171 /* free the remap file name string */
172 _pico_free( remapFileName );
184 the meat and potatoes function
187 picoModel_t *PicoLoadModel( const char *fileName, int frameNum ){
188 const picoModule_t **modules, *pm;
197 /* make sure we've got a file name */
198 if ( fileName == NULL ) {
199 _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" );
203 /* load file data (buffer is allocated by host app) */
204 _pico_load_file( fileName, &buffer, &bufSize );
206 _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName );
210 /* get ptr to list of supported modules */
211 modules = PicoModuleList( NULL );
213 /* run it through the various loader functions and try */
214 /* to find a loader that fits the given file data */
215 for ( ; *modules != NULL; modules++ )
225 /* module must be able to load */
226 if ( pm->canload == NULL || pm->load == NULL ) {
230 model = PicoModuleLoadModel( pm, fileName, buffer, bufSize, frameNum );
231 if ( model != NULL ) {
232 /* model was loaded, so break out of loop */
237 /* free memory used by file buffer */
239 _pico_free_file( buffer );
246 picoModel_t *PicoModuleLoadModelStream( const picoModule_t* module, void* inputStream, PicoInputStreamReadFunc inputStreamRead, size_t streamLength, int frameNum, const char *fileName ){
255 if ( inputStream == NULL ) {
256 _pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStream == NULL)" );
260 if ( inputStreamRead == NULL ) {
261 _pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStreamRead == NULL)" );
265 buffer = _pico_alloc( streamLength + 1 );
267 bufSize = (int)inputStreamRead( inputStream, buffer, streamLength );
268 buffer[bufSize] = '\0';
270 model = PicoModuleLoadModel( module, fileName, buffer, bufSize, frameNum );
273 _pico_free( buffer );
281 /* ----------------------------------------------------------------------------
283 ---------------------------------------------------------------------------- */
287 creates a new pico model
290 picoModel_t *PicoNewModel( void ){
294 model = _pico_alloc( sizeof( picoModel_t ) );
295 if ( model == NULL ) {
300 memset( model,0,sizeof( picoModel_t ) );
303 _pico_zero_bounds( model->mins,model->maxs );
305 /* set initial frame count to 1 -sea */
306 model->numFrames = 1;
308 /* return ptr to new model */
316 frees a model and all associated data
319 void PicoFreeModel( picoModel_t *model ){
324 if ( model == NULL ) {
330 _pico_free( model->name );
333 if ( model->fileName ) {
334 _pico_free( model->fileName );
338 for ( i = 0; i < model->numShaders; i++ )
339 PicoFreeShader( model->shader[ i ] );
340 free( model->shader );
343 for ( i = 0; i < model->numSurfaces; i++ )
344 PicoFreeSurface( model->surface[ i ] );
345 free( model->surface );
355 adjusts a models's memory allocations to handle the requested sizes.
356 will always grow, never shrink
359 int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ){
361 if ( model == NULL ) {
366 /* sea: null surface/shader fix (1s=>0s) */
367 if ( numShaders < 0 ) {
370 if ( numSurfaces < 0 ) {
374 /* additional shaders? */
375 while ( numShaders > model->maxShaders )
377 model->maxShaders += PICO_GROW_SHADERS;
378 if ( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) ) {
383 /* set shader count to higher */
384 if ( numShaders > model->numShaders ) {
385 model->numShaders = numShaders;
388 /* additional surfaces? */
389 while ( numSurfaces > model->maxSurfaces )
391 model->maxSurfaces += PICO_GROW_SURFACES;
392 if ( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) ) {
397 /* set shader count to higher */
398 if ( numSurfaces > model->numSurfaces ) {
399 model->numSurfaces = numSurfaces;
408 /* ----------------------------------------------------------------------------
410 ---------------------------------------------------------------------------- */
414 creates a new pico shader and returns its index. -sea
417 picoShader_t *PicoNewShader( picoModel_t *model ){
418 picoShader_t *shader;
421 /* allocate and clear */
422 shader = _pico_alloc( sizeof( picoShader_t ) );
423 if ( shader == NULL ) {
426 memset( shader, 0, sizeof( picoShader_t ) );
428 /* attach it to the model */
429 if ( model != NULL ) {
431 if ( !PicoAdjustModel( model, model->numShaders + 1, 0 ) ) {
432 _pico_free( shader );
437 model->shader[ model->numShaders - 1 ] = shader;
438 shader->model = model;
441 /* setup default shader colors */
442 _pico_set_color( shader->ambientColor,0,0,0,0 );
443 _pico_set_color( shader->diffuseColor,255,255,255,1 );
444 _pico_set_color( shader->specularColor,0,0,0,0 );
446 /* no need to do this, but i do it anyway */
447 shader->transparency = 0;
448 shader->shininess = 0;
450 /* return the newly created shader */
458 frees a shader and all associated data -sea
461 void PicoFreeShader( picoShader_t *shader ){
463 if ( shader == NULL ) {
468 if ( shader->name ) {
469 _pico_free( shader->name );
471 if ( shader->mapName ) {
472 _pico_free( shader->mapName );
475 /* free the shader */
476 _pico_free( shader );
483 finds a named shader in a model
486 picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ){
491 if ( model == NULL || name == NULL ) { /* sea: null name fix */
496 for ( i = 0; i < model->numShaders; i++ )
498 /* skip null shaders or shaders with null names */
499 if ( model->shader[ i ] == NULL ||
500 model->shader[ i ]->name == NULL ) {
504 /* compare the shader name with name we're looking for */
505 if ( caseSensitive ) {
506 if ( !strcmp( name, model->shader[ i ]->name ) ) {
507 return model->shader[ i ];
510 else if ( !_pico_stricmp( name, model->shader[ i ]->name ) ) {
511 return model->shader[ i ];
515 /* named shader not found */
521 /* ----------------------------------------------------------------------------
523 ---------------------------------------------------------------------------- */
527 creates a new pico surface
530 picoSurface_t *PicoNewSurface( picoModel_t *model ){
531 picoSurface_t *surface;
532 char surfaceName[64];
534 /* allocate and clear */
535 surface = _pico_alloc( sizeof( *surface ) );
536 if ( surface == NULL ) {
539 memset( surface, 0, sizeof( *surface ) );
541 /* attach it to the model */
542 if ( model != NULL ) {
544 if ( !PicoAdjustModel( model, 0, model->numSurfaces + 1 ) ) {
545 _pico_free( surface );
550 model->surface[ model->numSurfaces - 1 ] = surface;
551 surface->model = model;
553 /* set default name */
554 sprintf( surfaceName, "Unnamed_%d", model->numSurfaces );
555 PicoSetSurfaceName( surface, surfaceName );
566 frees a surface and all associated data
568 void PicoFreeSurface( picoSurface_t *surface ){
573 if ( surface == NULL ) {
578 _pico_free( surface->xyz );
579 _pico_free( surface->normal );
580 _pico_free( surface->smoothingGroup );
581 _pico_free( surface->index );
582 _pico_free( surface->faceNormal );
584 if ( surface->name ) {
585 _pico_free( surface->name );
589 for ( i = 0; i < surface->numSTArrays; i++ )
590 _pico_free( surface->st[ i ] );
592 for ( i = 0; i < surface->numColorArrays; i++ )
593 _pico_free( surface->color[ i ] );
594 free( surface->color );
596 /* free the surface */
597 _pico_free( surface );
604 adjusts a surface's memory allocations to handle the requested sizes.
605 will always grow, never shrink
608 int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ){
613 if ( surface == NULL ) {
618 if ( numVertexes < 1 ) {
621 if ( numSTArrays < 1 ) {
624 if ( numColorArrays < 1 ) {
627 if ( numIndexes < 1 ) {
631 /* additional vertexes? */
632 while ( numVertexes > surface->maxVertexes ) /* fix */
634 surface->maxVertexes += PICO_GROW_VERTEXES;
635 if ( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) ) {
638 if ( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) ) {
641 if ( !_pico_realloc( (void *) &surface->smoothingGroup, surface->numVertexes * sizeof( *surface->smoothingGroup ), surface->maxVertexes * sizeof( *surface->smoothingGroup ) ) ) {
644 for ( i = 0; i < surface->numSTArrays; i++ )
645 if ( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) ) {
648 for ( i = 0; i < surface->numColorArrays; i++ )
649 if ( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) ) {
654 /* set vertex count to higher */
655 if ( numVertexes > surface->numVertexes ) {
656 surface->numVertexes = numVertexes;
659 /* additional st arrays? */
660 while ( numSTArrays > surface->maxSTArrays ) /* fix */
662 surface->maxSTArrays += PICO_GROW_ARRAYS;
663 if ( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) ) {
666 while ( surface->numSTArrays < numSTArrays )
668 surface->st[ surface->numSTArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
669 memset( surface->st[ surface->numSTArrays ], 0, surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
670 surface->numSTArrays++;
674 /* additional color arrays? */
675 while ( numColorArrays > surface->maxColorArrays ) /* fix */
677 surface->maxColorArrays += PICO_GROW_ARRAYS;
678 if ( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) ) {
681 while ( surface->numColorArrays < numColorArrays )
683 surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
684 memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
685 surface->numColorArrays++;
689 /* additional indexes? */
690 while ( numIndexes > surface->maxIndexes ) /* fix */
692 surface->maxIndexes += PICO_GROW_INDEXES;
693 if ( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) ) {
698 /* set index count to higher */
699 if ( numIndexes > surface->numIndexes ) {
700 surface->numIndexes = numIndexes;
703 /* additional face normals? */
704 while ( numFaceNormals > surface->maxFaceNormals ) /* fix */
706 surface->maxFaceNormals += PICO_GROW_FACES;
707 if ( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) ) {
712 /* set face normal count to higher */
713 if ( numFaceNormals > surface->numFaceNormals ) {
714 surface->numFaceNormals = numFaceNormals;
723 * Finds first matching named surface in a model.
725 picoSurface_t *PicoFindSurface(
726 picoModel_t *model, char *name, int caseSensitive ){
730 if ( model == NULL || name == NULL ) {
735 for ( i = 0; i < model->numSurfaces; i++ )
737 /* skip null surfaces or surfaces with null names */
738 if ( model->surface[ i ] == NULL ||
739 model->surface[ i ]->name == NULL ) {
743 /* compare the surface name with name we're looking for */
744 if ( caseSensitive ) {
745 if ( !strcmp( name,model->surface[ i ]->name ) ) {
746 return model->surface[ i ];
750 if ( !_pico_stricmp( name,model->surface[ i ]->name ) ) {
751 return model->surface[ i ];
755 /* named surface not found */
761 /*----------------------------------------------------------------------------
762 PicoSet*() Setter Functions
763 ----------------------------------------------------------------------------*/
765 void PicoSetModelName( picoModel_t *model, const char *name ){
766 if ( model == NULL || name == NULL ) {
769 if ( model->name != NULL ) {
770 _pico_free( model->name );
773 model->name = _pico_clone_alloc( name );
778 void PicoSetModelFileName( picoModel_t *model, const char *fileName ){
779 if ( model == NULL || fileName == NULL ) {
782 if ( model->fileName != NULL ) {
783 _pico_free( model->fileName );
786 model->fileName = _pico_clone_alloc( fileName );
791 void PicoSetModelFrameNum( picoModel_t *model, int frameNum ){
792 if ( model == NULL ) {
795 model->frameNum = frameNum;
800 void PicoSetModelNumFrames( picoModel_t *model, int numFrames ){
801 if ( model == NULL ) {
804 model->numFrames = numFrames;
809 void PicoSetModelData( picoModel_t *model, void *data ){
810 if ( model == NULL ) {
818 void PicoSetShaderName( picoShader_t *shader, char *name ){
819 if ( shader == NULL || name == NULL ) {
822 if ( shader->name != NULL ) {
823 _pico_free( shader->name );
826 shader->name = _pico_clone_alloc( name );
831 void PicoSetShaderMapName( picoShader_t *shader, char *mapName ){
832 if ( shader == NULL || mapName == NULL ) {
835 if ( shader->mapName != NULL ) {
836 _pico_free( shader->mapName );
839 shader->mapName = _pico_clone_alloc( mapName );
844 void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ){
845 if ( shader == NULL || color == NULL ) {
848 shader->ambientColor[ 0 ] = color[ 0 ];
849 shader->ambientColor[ 1 ] = color[ 1 ];
850 shader->ambientColor[ 2 ] = color[ 2 ];
851 shader->ambientColor[ 3 ] = color[ 3 ];
856 void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ){
857 if ( shader == NULL || color == NULL ) {
860 shader->diffuseColor[ 0 ] = color[ 0 ];
861 shader->diffuseColor[ 1 ] = color[ 1 ];
862 shader->diffuseColor[ 2 ] = color[ 2 ];
863 shader->diffuseColor[ 3 ] = color[ 3 ];
868 void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ){
869 if ( shader == NULL || color == NULL ) {
872 shader->specularColor[ 0 ] = color[ 0 ];
873 shader->specularColor[ 1 ] = color[ 1 ];
874 shader->specularColor[ 2 ] = color[ 2 ];
875 shader->specularColor[ 3 ] = color[ 3 ];
880 void PicoSetShaderTransparency( picoShader_t *shader, float value ){
881 if ( shader == NULL ) {
884 shader->transparency = value;
886 /* cap to 0..1 range */
887 if ( shader->transparency < 0.0 ) {
888 shader->transparency = 0.0;
890 if ( shader->transparency > 1.0 ) {
891 shader->transparency = 1.0;
897 void PicoSetShaderShininess( picoShader_t *shader, float value ){
898 if ( shader == NULL ) {
901 shader->shininess = value;
903 /* cap to 0..127 range */
904 if ( shader->shininess < 0.0 ) {
905 shader->shininess = 0.0;
907 if ( shader->shininess > 127.0 ) {
908 shader->shininess = 127.0;
914 void PicoSetSurfaceData( picoSurface_t *surface, void *data ){
915 if ( surface == NULL ) {
918 surface->data = data;
923 void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ){
924 if ( surface == NULL ) {
927 surface->type = type;
932 void PicoSetSurfaceName( picoSurface_t *surface, const char *name ){
933 if ( surface == NULL || name == NULL ) {
936 if ( surface->name != NULL ) {
937 _pico_free( surface->name );
940 surface->name = _pico_clone_alloc( name );
945 void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ){
946 if ( surface == NULL ) {
949 surface->shader = shader;
954 void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ){
955 if ( surface == NULL || num < 0 || xyz == NULL ) {
958 if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
961 _pico_copy_vec( xyz, surface->xyz[ num ] );
962 if ( surface->model != NULL ) {
963 _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs );
969 void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ){
970 if ( surface == NULL || num < 0 || normal == NULL ) {
973 if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
976 _pico_copy_vec( normal, surface->normal[ num ] );
981 void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ){
982 if ( surface == NULL || num < 0 || st == NULL ) {
985 if ( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) ) {
988 surface->st[ array ][ num ][ 0 ] = st[ 0 ];
989 surface->st[ array ][ num ][ 1 ] = st[ 1 ];
994 void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color ){
995 if ( surface == NULL || num < 0 || color == NULL ) {
998 if ( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) ) {
1001 surface->color[ array ][ num ][ 0 ] = color[ 0 ];
1002 surface->color[ array ][ num ][ 1 ] = color[ 1 ];
1003 surface->color[ array ][ num ][ 2 ] = color[ 2 ];
1004 surface->color[ array ][ num ][ 3 ] = color[ 3 ];
1009 void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ){
1010 if ( surface == NULL || num < 0 ) {
1013 if ( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) ) {
1016 surface->index[ num ] = index;
1021 void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ){
1022 if ( num < 0 || index == NULL || count < 1 ) {
1025 if ( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) ) {
1028 memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) );
1033 void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ){
1034 if ( surface == NULL || num < 0 || normal == NULL ) {
1037 if ( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) ) {
1040 _pico_copy_vec( normal, surface->faceNormal[ num ] );
1044 void PicoSetSurfaceSmoothingGroup( picoSurface_t *surface, int num, picoIndex_t smoothingGroup ){
1048 if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
1051 surface->smoothingGroup[ num ] = smoothingGroup;
1055 void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ){
1056 if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
1059 surface->special[ num ] = special;
1064 /*----------------------------------------------------------------------------
1065 PicoGet*() Getter Functions
1066 ----------------------------------------------------------------------------*/
1068 char *PicoGetModelName( picoModel_t *model ){
1069 if ( model == NULL ) {
1072 if ( model->name == NULL ) {
1080 char *PicoGetModelFileName( picoModel_t *model ){
1081 if ( model == NULL ) {
1084 if ( model->fileName == NULL ) {
1087 return model->fileName;
1092 int PicoGetModelFrameNum( picoModel_t *model ){
1093 if ( model == NULL ) {
1096 return model->frameNum;
1101 int PicoGetModelNumFrames( picoModel_t *model ){
1102 if ( model == NULL ) {
1105 return model->numFrames;
1110 void *PicoGetModelData( picoModel_t *model ){
1111 if ( model == NULL ) {
1119 int PicoGetModelNumShaders( picoModel_t *model ){
1120 if ( model == NULL ) {
1123 return model->numShaders;
1128 picoShader_t *PicoGetModelShader( picoModel_t *model, int num ){
1129 /* a few sanity checks */
1130 if ( model == NULL ) {
1133 if ( model->shader == NULL ) {
1136 if ( num < 0 || num >= model->numShaders ) {
1140 /* return the shader */
1141 return model->shader[ num ];
1146 int PicoGetModelNumSurfaces( picoModel_t *model ){
1147 if ( model == NULL ) {
1150 return model->numSurfaces;
1155 picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ){
1156 /* a few sanity checks */
1157 if ( model == NULL ) {
1160 if ( model->surface == NULL ) {
1163 if ( num < 0 || num >= model->numSurfaces ) {
1167 /* return the surface */
1168 return model->surface[ num ];
1173 int PicoGetModelTotalVertexes( picoModel_t *model ){
1177 if ( model == NULL ) {
1180 if ( model->surface == NULL ) {
1185 for ( i = 0; i < model->numSurfaces; i++ )
1186 count += PicoGetSurfaceNumVertexes( model->surface[ i ] );
1193 int PicoGetModelTotalIndexes( picoModel_t *model ){
1197 if ( model == NULL ) {
1200 if ( model->surface == NULL ) {
1205 for ( i = 0; i < model->numSurfaces; i++ )
1206 count += PicoGetSurfaceNumIndexes( model->surface[ i ] );
1213 char *PicoGetShaderName( picoShader_t *shader ){
1214 if ( shader == NULL ) {
1217 if ( shader->name == NULL ) {
1220 return shader->name;
1225 char *PicoGetShaderMapName( picoShader_t *shader ){
1226 if ( shader == NULL ) {
1229 if ( shader->mapName == NULL ) {
1232 return shader->mapName;
1237 picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ){
1238 if ( shader == NULL ) {
1241 return shader->ambientColor;
1246 picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ){
1247 if ( shader == NULL ) {
1250 return shader->diffuseColor;
1255 picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ){
1256 if ( shader == NULL ) {
1259 return shader->specularColor;
1264 float PicoGetShaderTransparency( picoShader_t *shader ){
1265 if ( shader == NULL ) {
1268 return shader->transparency;
1273 float PicoGetShaderShininess( picoShader_t *shader ){
1274 if ( shader == NULL ) {
1277 return shader->shininess;
1282 void *PicoGetSurfaceData( picoSurface_t *surface ){
1283 if ( surface == NULL ) {
1286 return surface->data;
1291 picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ){
1292 if ( surface == NULL ) {
1295 return surface->type;
1300 char *PicoGetSurfaceName( picoSurface_t *surface ){
1301 if ( surface == NULL ) {
1304 if ( surface->name == NULL ) {
1307 return surface->name;
1312 picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ){
1313 if ( surface == NULL ) {
1316 return surface->shader;
1321 int PicoGetSurfaceNumVertexes( picoSurface_t *surface ){
1322 if ( surface == NULL ) {
1325 return surface->numVertexes;
1330 picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ){
1331 if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
1334 return surface->xyz[ num ];
1339 picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ){
1340 if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
1343 return surface->normal[ num ];
1348 picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ){
1349 if ( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes ) {
1352 return surface->st[ array ][ num ];
1357 picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ){
1358 if ( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes ) {
1361 return surface->color[ array ][ num ];
1366 int PicoGetSurfaceNumIndexes( picoSurface_t *surface ){
1367 if ( surface == NULL ) {
1370 return surface->numIndexes;
1375 picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ){
1376 if ( surface == NULL || num < 0 || num > surface->numIndexes ) {
1379 return surface->index[ num ];
1384 picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ){
1385 if ( surface == NULL || num < 0 || num > surface->numIndexes ) {
1388 return &surface->index[ num ];
1392 picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ){
1393 if ( surface == NULL || num < 0 || num > surface->numFaceNormals ) {
1396 return surface->faceNormal[ num ];
1399 picoIndex_t PicoGetSurfaceSmoothingGroup( picoSurface_t *surface, int num ){
1400 if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
1403 return surface->smoothingGroup[ num ];
1407 int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ){
1408 if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
1411 return surface->special[ num ];
1416 /* ----------------------------------------------------------------------------
1417 hashtable related functions
1418 ---------------------------------------------------------------------------- */
1420 /* hashtable code for faster vertex lookups */
1421 //#define HASHTABLE_SIZE 32768 // 2048 /* power of 2, use & */
1422 const int HASHTABLE_SIZE = 7919; // 32749 // 2039 /* prime, use % */
1424 int PicoGetHashTableSize( void ){
1425 return HASHTABLE_SIZE;
1428 #define HASH_USE_EPSILON
1430 #ifdef HASH_USE_EPSILON
1431 #define HASH_XYZ_EPSILON 0.01f
1432 #define HASH_XYZ_EPSILONSPACE_MULTIPLIER 1.f / HASH_XYZ_EPSILON
1433 #define HASH_ST_EPSILON 0.0001f
1434 #define HASH_NORMAL_EPSILON 0.02f
1437 unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ){
1438 unsigned int hash = 0;
1440 #ifndef HASH_USE_EPSILON
1441 hash += ~( *( (unsigned int*) &xyz[ 0 ] ) << 15 );
1442 hash ^= ( *( (unsigned int*) &xyz[ 0 ] ) >> 10 );
1443 hash += ( *( (unsigned int*) &xyz[ 1 ] ) << 3 );
1444 hash ^= ( *( (unsigned int*) &xyz[ 1 ] ) >> 6 );
1445 hash += ~( *( (unsigned int*) &xyz[ 2 ] ) << 11 );
1446 hash ^= ( *( (unsigned int*) &xyz[ 2 ] ) >> 16 );
1448 picoVec3_t xyz_epsilonspace;
1450 _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace );
1451 xyz_epsilonspace[ 0 ] = (float)floor( xyz_epsilonspace[ 0 ] );
1452 xyz_epsilonspace[ 1 ] = (float)floor( xyz_epsilonspace[ 1 ] );
1453 xyz_epsilonspace[ 2 ] = (float)floor( xyz_epsilonspace[ 2 ] );
1455 hash += ~( *( (unsigned int*) &xyz_epsilonspace[ 0 ] ) << 15 );
1456 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 0 ] ) >> 10 );
1457 hash += ( *( (unsigned int*) &xyz_epsilonspace[ 1 ] ) << 3 );
1458 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 1 ] ) >> 6 );
1459 hash += ~( *( (unsigned int*) &xyz_epsilonspace[ 2 ] ) << 11 );
1460 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 2 ] ) >> 16 );
1463 //hash = hash & (HASHTABLE_SIZE-1);
1464 hash = hash % ( HASHTABLE_SIZE );
1468 picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ){
1469 picoVertexCombinationHash_t **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof( picoVertexCombinationHash_t* ) );
1471 memset( hashTable, 0, HASHTABLE_SIZE * sizeof( picoVertexCombinationHash_t* ) );
1476 void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ){
1478 picoVertexCombinationHash_t *vertexCombinationHash;
1479 picoVertexCombinationHash_t *nextVertexCombinationHash;
1482 if ( hashTable == NULL ) {
1486 for ( i = 0; i < HASHTABLE_SIZE; i++ )
1488 if ( hashTable[ i ] ) {
1489 nextVertexCombinationHash = NULL;
1491 for ( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash )
1493 nextVertexCombinationHash = vertexCombinationHash->next;
1494 if ( vertexCombinationHash->data != NULL ) {
1495 _pico_free( vertexCombinationHash->data );
1497 _pico_free( vertexCombinationHash );
1502 _pico_free( hashTable );
1505 picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ){
1507 picoVertexCombinationHash_t *vertexCombinationHash;
1510 if ( hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) {
1514 hash = PicoVertexCoordGenerateHash( xyz );
1516 for ( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next )
1518 #ifndef HASH_USE_EPSILON
1520 if ( ( vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ] ) ) {
1525 if ( ( vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ] ) ) {
1530 if ( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] ) {
1535 if ( ( fabs( xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ] ) ) > HASH_XYZ_EPSILON ||
1536 ( fabs( xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ] ) ) > HASH_XYZ_EPSILON ||
1537 ( fabs( xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ] ) ) > HASH_XYZ_EPSILON ) {
1542 if ( ( fabs( normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ] ) ) > HASH_NORMAL_EPSILON ||
1543 ( fabs( normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ] ) ) > HASH_NORMAL_EPSILON ||
1544 ( fabs( normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ] ) ) > HASH_NORMAL_EPSILON ) {
1549 if ( ( fabs( st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ] ) ) > HASH_ST_EPSILON ||
1550 ( fabs( st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ] ) ) > HASH_ST_EPSILON ) {
1556 if ( *( (int*) vertexCombinationHash->vcd.color ) != *( (int*) color ) ) {
1561 return vertexCombinationHash;
1567 picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ){
1569 picoVertexCombinationHash_t *vertexCombinationHash;
1572 if ( hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) {
1576 vertexCombinationHash = _pico_alloc( sizeof( picoVertexCombinationHash_t ) );
1578 if ( !vertexCombinationHash ) {
1582 hash = PicoVertexCoordGenerateHash( xyz );
1584 _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz );
1585 _pico_copy_vec( normal, vertexCombinationHash->vcd.normal );
1586 _pico_copy_vec2( st, vertexCombinationHash->vcd.st );
1587 _pico_copy_color( color, vertexCombinationHash->vcd.color );
1588 vertexCombinationHash->index = index;
1589 vertexCombinationHash->data = NULL;
1590 vertexCombinationHash->next = hashTable[ hash ];
1591 hashTable[ hash ] = vertexCombinationHash;
1593 return vertexCombinationHash;
1596 /* ----------------------------------------------------------------------------
1597 specialized routines
1598 ---------------------------------------------------------------------------- */
1601 PicoFindSurfaceVertex()
1602 finds a vertex matching the set parameters
1603 fixme: needs non-naive algorithm
1606 int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color, picoIndex_t smoothingGroup ){
1611 if ( surface == NULL || surface->numVertexes <= 0 ) {
1615 /* walk vertex list */
1616 for ( i = 0; i < surface->numVertexes; i++ )
1619 if ( xyz != NULL && ( surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ] ) ) {
1624 if ( normal != NULL && ( surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ] ) ) {
1629 if ( surface->smoothingGroup[ i ] != smoothingGroup ) {
1634 if ( numSTs > 0 && st != NULL ) {
1635 for ( j = 0; j < numSTs; j++ )
1637 if ( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] ) {
1641 if ( j != numSTs ) {
1647 if ( numColors > 0 && color != NULL ) {
1648 for ( j = 0; j < numSTs; j++ )
1650 if ( *( (int*) surface->color[ j ] ) != *( (int*) color[ j ] ) ) {
1654 if ( j != numColors ) {
1659 /* vertex matches */
1670 typedef struct _IndexArray IndexArray;
1677 void indexarray_push_back( IndexArray* self, picoIndex_t value ){
1678 *self->last++ = value;
1681 size_t indexarray_size( IndexArray* self ){
1682 return self->last - self->data;
1685 void indexarray_reserve( IndexArray* self, size_t size ){
1686 self->data = self->last = _pico_calloc( size, sizeof( picoIndex_t ) );
1689 void indexarray_clear( IndexArray* self ){
1690 _pico_free( self->data );
1693 typedef struct _BinaryTreeNode BinaryTreeNode;
1694 struct _BinaryTreeNode
1700 typedef struct _BinaryTree BinaryTree;
1703 BinaryTreeNode* data;
1704 BinaryTreeNode* last;
1707 void binarytree_extend( BinaryTree* self ){
1708 self->last->left = 0;
1709 self->last->right = 0;
1713 size_t binarytree_size( BinaryTree* self ){
1714 return self->last - self->data;
1717 void binarytree_reserve( BinaryTree* self, size_t size ){
1718 self->data = self->last = _pico_calloc( size, sizeof( BinaryTreeNode ) );
1721 void binarytree_clear( BinaryTree* self ){
1722 _pico_free( self->data );
1725 typedef int ( *LessFunc )( void*, picoIndex_t, picoIndex_t );
1727 typedef struct _UniqueIndices UniqueIndices;
1728 struct _UniqueIndices
1736 size_t UniqueIndices_size( UniqueIndices* self ){
1737 return binarytree_size( &self->tree );
1740 void UniqueIndices_reserve( UniqueIndices* self, size_t size ){
1741 binarytree_reserve( &self->tree, size );
1742 indexarray_reserve( &self->indices, size );
1745 void UniqueIndices_init( UniqueIndices* self, LessFunc lessFunc, void* lessData ){
1746 self->lessFunc = lessFunc;
1747 self->lessData = lessData;
1750 void UniqueIndices_destroy( UniqueIndices* self ){
1751 binarytree_clear( &self->tree );
1752 indexarray_clear( &self->indices );
1756 picoIndex_t UniqueIndices_find_or_insert( UniqueIndices* self, picoIndex_t value ){
1757 picoIndex_t index = 0;
1761 if ( self->lessFunc( self->lessData, value, self->indices.data[index] ) ) {
1762 BinaryTreeNode* node = self->tree.data + index;
1763 if ( node->left != 0 ) {
1769 node->left = (picoIndex_t)binarytree_size( &self->tree );
1770 binarytree_extend( &self->tree );
1771 indexarray_push_back( &self->indices, value );
1775 if ( self->lessFunc( self->lessData, self->indices.data[index], value ) ) {
1776 BinaryTreeNode* node = self->tree.data + index;
1777 if ( node->right != 0 ) {
1778 index = node->right;
1783 node->right = (picoIndex_t)binarytree_size( &self->tree );
1784 binarytree_extend( &self->tree );
1785 indexarray_push_back( &self->indices, value );
1794 picoIndex_t UniqueIndices_insert( UniqueIndices* self, picoIndex_t value ){
1795 if ( self->tree.data == self->tree.last ) {
1796 binarytree_extend( &self->tree );
1797 indexarray_push_back( &self->indices, value );
1802 return UniqueIndices_find_or_insert( self, value );
1806 typedef struct picoSmoothVertices_s picoSmoothVertices_t;
1807 struct picoSmoothVertices_s
1810 picoIndex_t* smoothingGroups;
1813 int lessSmoothVertex( void* data, picoIndex_t first, picoIndex_t second ){
1814 picoSmoothVertices_t* smoothVertices = data;
1816 if ( smoothVertices->xyz[first][0] != smoothVertices->xyz[second][0] ) {
1817 return smoothVertices->xyz[first][0] < smoothVertices->xyz[second][0];
1819 if ( smoothVertices->xyz[first][1] != smoothVertices->xyz[second][1] ) {
1820 return smoothVertices->xyz[first][1] < smoothVertices->xyz[second][1];
1822 if ( smoothVertices->xyz[first][2] != smoothVertices->xyz[second][2] ) {
1823 return smoothVertices->xyz[first][2] < smoothVertices->xyz[second][2];
1825 if ( smoothVertices->smoothingGroups[first] != smoothVertices->smoothingGroups[second] ) {
1826 return smoothVertices->smoothingGroups[first] < smoothVertices->smoothingGroups[second];
1831 void _pico_vertices_combine_shared_normals( picoVec3_t* xyz, picoIndex_t* smoothingGroups, picoVec3_t* normals, picoIndex_t numVertices ){
1832 UniqueIndices vertices;
1834 picoSmoothVertices_t smoothVertices = { xyz, smoothingGroups };
1835 UniqueIndices_init( &vertices, lessSmoothVertex, &smoothVertices );
1836 UniqueIndices_reserve( &vertices, numVertices );
1837 indexarray_reserve( &indices, numVertices );
1842 for (; i < numVertices; ++i )
1844 size_t size = UniqueIndices_size( &vertices );
1845 picoIndex_t index = UniqueIndices_insert( &vertices, i );
1846 if ( (size_t)index != size ) {
1847 float* normal = normals[vertices.indices.data[index]];
1848 _pico_add_vec( normal, normals[i], normal );
1850 indexarray_push_back( &indices, index );
1855 picoIndex_t maxIndex = 0;
1856 picoIndex_t* i = indices.data;
1857 for (; i != indices.last; ++i )
1859 if ( *i <= maxIndex ) {
1860 _pico_copy_vec( normals[vertices.indices.data[*i]], normals[i - indices.data] );
1869 UniqueIndices_destroy( &vertices );
1870 indexarray_clear( &indices );
1873 typedef picoVec3_t* picoNormalIter_t;
1874 typedef picoIndex_t* picoIndexIter_t;
1876 #define THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL 1
1878 void _pico_triangles_generate_weighted_normals( picoIndexIter_t first, picoIndexIter_t end, picoVec3_t* xyz, picoVec3_t* normals ){
1879 for (; first != end; first += 3 )
1881 #if ( THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL )
1882 picoVec3_t weightedNormal;
1884 float* a = xyz[*( first + 0 )];
1885 float* b = xyz[*( first + 1 )];
1886 float* c = xyz[*( first + 2 )];
1888 _pico_subtract_vec( b, a, ba );
1889 _pico_subtract_vec( c, a, ca );
1890 _pico_cross_vec( ca, ba, weightedNormal );
1897 float* normal = normals[*( first + j )];
1898 #if ( !THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL )
1899 picoVec3_t weightedNormal;
1901 float* a = xyz[*( first + ( ( j + 0 ) % 3 ) )];
1902 float* b = xyz[*( first + ( ( j + 1 ) % 3 ) )];
1903 float* c = xyz[*( first + ( ( j + 2 ) % 3 ) )];
1905 _pico_subtract_vec( b, a, ba );
1906 _pico_subtract_vec( c, a, ca );
1907 _pico_cross_vec( ca, ba, weightedNormal );
1910 _pico_add_vec( weightedNormal, normal, normal );
1916 void _pico_normals_zero( picoNormalIter_t first, picoNormalIter_t last ){
1917 for (; first != last; ++first )
1919 _pico_zero_vec( *first );
1923 void _pico_normals_normalize( picoNormalIter_t first, picoNormalIter_t last ){
1924 for (; first != last; ++first )
1926 _pico_normalize_vec( *first );
1930 double _pico_length_vec( picoVec3_t vec ){
1931 return sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] );
1934 #define NORMAL_UNIT_LENGTH_EPSILON 0.01
1935 #define FLOAT_EQUAL_EPSILON( f, other, epsilon ) ( fabs( f - other ) < epsilon )
1937 int _pico_normal_is_unit_length( picoVec3_t normal ){
1938 return FLOAT_EQUAL_EPSILON( _pico_length_vec( normal ), 1.0, NORMAL_UNIT_LENGTH_EPSILON );
1941 int _pico_normal_within_tolerance( picoVec3_t normal, picoVec3_t other ){
1942 return _pico_dot_vec( normal, other ) > 0.0f;
1946 void _pico_normals_assign_generated_normals( picoNormalIter_t first, picoNormalIter_t last, picoNormalIter_t generated ){
1947 for (; first != last; ++first, ++generated )
1949 if ( !_pico_normal_is_unit_length( *first ) || !_pico_normal_within_tolerance( *first, *generated ) ) {
1950 _pico_copy_vec( *generated, *first );
1955 void PicoFixSurfaceNormals( picoSurface_t* surface ){
1956 picoVec3_t* normals = (picoVec3_t*)_pico_calloc( surface->numVertexes, sizeof( picoVec3_t ) );
1958 _pico_normals_zero( normals, normals + surface->numVertexes );
1960 _pico_triangles_generate_weighted_normals( surface->index, surface->index + surface->numIndexes, surface->xyz, normals );
1961 _pico_vertices_combine_shared_normals( surface->xyz, surface->smoothingGroup, normals, surface->numVertexes );
1963 _pico_normals_normalize( normals, normals + surface->numVertexes );
1965 _pico_normals_assign_generated_normals( surface->normal, surface->normal + surface->numVertexes, normals );
1967 _pico_free( normals );
1972 PicoRemapModel() - sea
1973 remaps model material/etc. information using the remappings
1974 contained in the given 'remapFile' (full path to the ascii file to open)
1975 returns 1 on success or 0 on error
1978 #define _prm_error_return \
1980 _pico_free_parser( p ); \
1981 _pico_free_file( remapBuffer ); \
1985 int PicoRemapModel( picoModel_t *model, char *remapFile ){
1987 picoByte_t *remapBuffer;
1992 if ( model == NULL || remapFile == NULL ) {
1996 /* load remap file contents */
1997 _pico_load_file( remapFile,&remapBuffer,&remapBufSize );
2000 if ( remapBufSize == 0 ) {
2001 return 1; /* file is empty: no error */
2003 if ( remapBufSize < 0 ) {
2004 return 0; /* load failed: error */
2007 /* create a new pico parser */
2008 p = _pico_new_parser( remapBuffer, remapBufSize );
2010 /* ram is really cheap nowadays... */
2017 /* get next token in remap file */
2018 if ( !_pico_parse( p,1 ) ) {
2022 /* skip over c++ style comment lines */
2023 if ( !_pico_stricmp( p->token,"//" ) ) {
2024 _pico_parse_skip_rest( p );
2028 /* block for quick material shader name remapping */
2029 /* materials { "m" (=>|->|=) "s" } */
2030 if ( !_pico_stricmp( p->token, "materials" ) ) {
2034 if ( !_pico_parse_check( p,1,"{" ) ) {
2038 /* process assignments */
2041 picoShader_t *shader;
2045 /* get material name */
2046 if ( _pico_parse( p,1 ) == NULL ) {
2049 if ( !strlen( p->token ) ) {
2052 materialName = _pico_clone_alloc( p->token );
2053 if ( materialName == NULL ) {
2058 if ( p->token[0] == '{' ) {
2061 if ( p->token[0] == '}' ) {
2068 /* get next token (assignment token or shader name) */
2069 if ( !_pico_parse( p,0 ) ) {
2070 _pico_free( materialName );
2073 /* skip assignment token (if present) */
2074 if ( !strcmp( p->token,"=>" ) ||
2075 !strcmp( p->token,"->" ) ||
2076 !strcmp( p->token,"=" ) ) {
2077 /* simply grab the next token */
2078 if ( !_pico_parse( p,0 ) ) {
2079 _pico_free( materialName );
2083 /* try to find material by name */
2084 shader = PicoFindShader( model,materialName,0 );
2086 /* we've found a material matching the name */
2087 if ( shader != NULL ) {
2088 PicoSetShaderName( shader,p->token );
2090 /* free memory used by material name */
2091 _pico_free( materialName );
2094 _pico_parse_skip_rest( p );
2097 /* block for detailed single material remappings */
2098 /* materials[ "m" ] { key data... } */
2099 else if ( !_pico_stricmp( p->token,"materials[" ) ) {
2100 picoShader_t *shader;
2101 char *tempMaterialName;
2104 /* get material name */
2105 if ( !_pico_parse( p,0 ) ) {
2109 /* temporary copy of material name */
2110 tempMaterialName = _pico_clone_alloc( p->token );
2111 if ( tempMaterialName == NULL ) {
2115 /* check square closing bracket */
2116 if ( !_pico_parse_check( p,0,"]" ) ) {
2120 /* try to find material by name */
2121 shader = PicoFindShader( model,tempMaterialName,0 );
2123 /* free memory used by temporary material name */
2124 _pico_free( tempMaterialName );
2126 /* we haven't found a material matching the name */
2127 /* so we simply skip the braced section now and */
2128 /* continue parsing with the next main token */
2129 if ( shader == NULL ) {
2130 _pico_parse_skip_braced( p );
2133 /* check opening bracket */
2134 if ( !_pico_parse_check( p,1,"{" ) ) {
2138 /* process material info keys */
2142 if ( _pico_parse( p,1 ) == NULL ) {
2145 if ( !strlen( p->token ) ) {
2150 if ( p->token[0] == '{' ) {
2153 if ( p->token[0] == '}' ) {
2160 /* remap shader name */
2161 if ( !_pico_stricmp( p->token,"shader" ) ) {
2162 if ( !_pico_parse( p,0 ) ) {
2165 PicoSetShaderName( shader,p->token );
2167 /* remap shader map name */
2168 else if ( !_pico_stricmp( p->token,"mapname" ) ) {
2169 if ( !_pico_parse( p,0 ) ) {
2172 PicoSetShaderMapName( shader,p->token );
2174 /* remap shader's ambient color */
2175 else if ( !_pico_stricmp( p->token,"ambient" ) ) {
2179 /* get vector from parser */
2180 if ( !_pico_parse_vec( p,v ) ) {
2184 /* store as color */
2185 color[ 0 ] = (picoByte_t)v[ 0 ];
2186 color[ 1 ] = (picoByte_t)v[ 1 ];
2187 color[ 2 ] = (picoByte_t)v[ 2 ];
2189 /* set new ambient color */
2190 PicoSetShaderAmbientColor( shader,color );
2192 /* remap shader's diffuse color */
2193 else if ( !_pico_stricmp( p->token,"diffuse" ) ) {
2197 /* get vector from parser */
2198 if ( !_pico_parse_vec( p,v ) ) {
2202 /* store as color */
2203 color[ 0 ] = (picoByte_t)v[ 0 ];
2204 color[ 1 ] = (picoByte_t)v[ 1 ];
2205 color[ 2 ] = (picoByte_t)v[ 2 ];
2207 /* set new ambient color */
2208 PicoSetShaderDiffuseColor( shader,color );
2210 /* remap shader's specular color */
2211 else if ( !_pico_stricmp( p->token,"specular" ) ) {
2215 /* get vector from parser */
2216 if ( !_pico_parse_vec( p,v ) ) {
2220 /* store as color */
2221 color[ 0 ] = (picoByte_t)v[ 0 ];
2222 color[ 1 ] = (picoByte_t)v[ 1 ];
2223 color[ 2 ] = (picoByte_t)v[ 2 ];
2225 /* set new ambient color */
2226 PicoSetShaderSpecularColor( shader,color );
2229 _pico_parse_skip_rest( p );
2232 /* end 'materials[' */
2235 /* free both parser and file buffer */
2236 _pico_free_parser( p );
2237 _pico_free_file( remapBuffer );
2239 /* return with success */
2245 PicoAddTriangleToModel() - jhefty
2246 A nice way to add individual triangles to the model.
2247 Chooses an appropriate surface based on the shader, or adds a new surface if necessary
2250 void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals,
2251 int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors,
2252 picoShader_t* shader, const char *name, picoIndex_t* smoothingGroup ){
2255 picoSurface_t* workSurface = NULL;
2257 /* see if a surface already has the shader */
2258 for ( i = 0 ; i < model->numSurfaces ; i++ )
2260 workSurface = model->surface[i];
2261 if ( !name || !strcmp( workSurface->name, name ) ) {
2262 if ( workSurface->shader == shader ) {
2268 /* no surface uses this shader yet, so create a new surface */
2269 if ( !workSurface || i >= model->numSurfaces ) {
2270 /* create a new surface in the model for the unique shader */
2271 workSurface = PicoNewSurface( model );
2272 if ( !workSurface ) {
2273 _pico_printf( PICO_ERROR, "Could not allocate a new surface!\n" );
2277 /* do surface setup */
2278 PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
2279 PicoSetSurfaceName( workSurface, name ? name : shader->name );
2280 PicoSetSurfaceShader( workSurface, shader );
2283 /* add the triangle data to the surface */
2284 for ( i = 0 ; i < 3 ; i++ )
2286 /* get the next free spot in the index array */
2287 int newVertIndex = PicoGetSurfaceNumIndexes( workSurface );
2289 /* get the index of the vertex that we're going to store at newVertIndex */
2290 vertDataIndex = PicoFindSurfaceVertexNum( workSurface, *xyz[i], *normals[i], numSTs, st[i], numColors, colors[i], smoothingGroup[i] );
2292 /* the vertex wasn't found, so create a new vertex in the pool from the data we have */
2293 if ( vertDataIndex == -1 ) {
2294 /* find the next spot for a new vertex */
2295 vertDataIndex = PicoGetSurfaceNumVertexes( workSurface );
2297 /* assign the data to it */
2298 PicoSetSurfaceXYZ( workSurface,vertDataIndex, *xyz[i] );
2299 PicoSetSurfaceNormal( workSurface, vertDataIndex, *normals[i] );
2301 /* make sure to copy over all available ST's and colors for the vertex */
2302 for ( j = 0 ; j < numColors ; j++ )
2304 PicoSetSurfaceColor( workSurface, j, vertDataIndex, colors[i][j] );
2306 for ( j = 0 ; j < numSTs ; j++ )
2308 PicoSetSurfaceST( workSurface, j, vertDataIndex, st[i][j] );
2311 PicoSetSurfaceSmoothingGroup( workSurface, vertDataIndex, smoothingGroup[i] );
2314 /* add this vertex to the triangle */
2315 PicoSetSurfaceIndex( workSurface, newVertIndex, vertDataIndex );