1 /* -----------------------------------------------------------------------------
5 Copyright (c) 2002, Randy Reddig & seaw0lf
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
11 Redistributions of source code must retain the above copyright notice, this list
12 of conditions and the following disclaimer.
14 Redistributions in binary form must reproduce the above copyright notice, this
15 list of conditions and the following disclaimer in the documentation and/or
16 other materials provided with the distribution.
18 Neither the names of the copyright holders nor the names of its contributors may
19 be used to endorse or promote products derived from this software without
20 specific prior written permission.
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 ----------------------------------------------------------------------------- */
43 #include "picointernal.h"
49 initializes the picomodel library
53 /* successfully initialized -sea */
61 shuts the pico model library down
64 void PicoShutdown( void ){
65 /* do something interesting here in the future */
73 returns last picomodel error code (see PME_* defines)
76 int PicoError( void ){
77 /* todo: do something here */
85 sets the ptr to the malloc function
88 void PicoSetMallocFunc( void *( *func )( size_t ) ){
90 _pico_ptr_malloc = func;
98 sets the ptr to the free function
101 void PicoSetFreeFunc( void ( *func )( void* ) ){
102 if ( func != NULL ) {
103 _pico_ptr_free = func;
110 PicoSetLoadFileFunc()
111 sets the ptr to the file load function
114 void PicoSetLoadFileFunc( void ( *func )( const char*, unsigned char**, int* ) ){
115 if ( func != NULL ) {
116 _pico_ptr_load_file = func;
123 PicoSetFreeFileFunc()
124 sets the ptr to the free function
127 void PicoSetFreeFileFunc( void ( *func )( void* ) ){
128 if ( func != NULL ) {
129 _pico_ptr_free_file = func;
137 sets the ptr to the print function
140 void PicoSetPrintFunc( void ( *func )( int, const char* ) ){
141 if ( func != NULL ) {
142 _pico_ptr_print = func;
148 picoModel_t *PicoModuleLoadModel( const picoModule_t* pm, const char* fileName, picoByte_t* buffer, int bufSize, int frameNum ){
149 char *modelFileName, *remapFileName;
151 /* see whether this module can load the model file or not */
152 if ( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK ) {
153 /* use loader provided by module to read the model data */
154 picoModel_t* model = pm->load( fileName, frameNum, buffer, bufSize );
155 if ( model == NULL ) {
156 _pico_free_file( buffer );
160 /* assign pointer to file format module */
163 /* get model file name */
164 modelFileName = PicoGetModelFileName( model );
166 /* apply model remappings from <model>.remap */
167 if ( strlen( modelFileName ) ) {
168 /* alloc copy of model file name */
169 remapFileName = _pico_alloc( strlen( modelFileName ) + 20 );
170 if ( remapFileName != NULL ) {
171 /* copy model file name and change extension */
172 strcpy( remapFileName, modelFileName );
173 _pico_setfext( remapFileName, "remap" );
175 /* try to remap model; we don't handle the result */
176 PicoRemapModel( model, remapFileName );
178 /* free the remap file name string */
179 _pico_free( remapFileName );
191 the meat and potatoes function
194 picoModel_t *PicoLoadModel( const char *fileName, int frameNum ){
195 const picoModule_t **modules, *pm;
204 /* make sure we've got a file name */
205 if ( fileName == NULL ) {
206 _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" );
210 /* load file data (buffer is allocated by host app) */
211 _pico_load_file( fileName, &buffer, &bufSize );
213 _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName );
217 /* get ptr to list of supported modules */
218 modules = PicoModuleList( NULL );
220 /* run it through the various loader functions and try */
221 /* to find a loader that fits the given file data */
222 for ( ; *modules != NULL; modules++ )
232 /* module must be able to load */
233 if ( pm->canload == NULL || pm->load == NULL ) {
237 model = PicoModuleLoadModel( pm, fileName, buffer, bufSize, frameNum );
238 if ( model != NULL ) {
239 /* model was loaded, so break out of loop */
244 /* free memory used by file buffer */
246 _pico_free_file( buffer );
253 picoModel_t *PicoModuleLoadModelStream( const picoModule_t* module, void* inputStream, PicoInputStreamReadFunc inputStreamRead, size_t streamLength, int frameNum, const char *fileName ){
262 if ( inputStream == NULL ) {
263 _pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStream == NULL)" );
267 if ( inputStreamRead == NULL ) {
268 _pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStreamRead == NULL)" );
272 buffer = _pico_alloc( streamLength + 1 );
274 bufSize = (int)inputStreamRead( inputStream, buffer, streamLength );
275 buffer[bufSize] = '\0';
277 model = PicoModuleLoadModel( module, fileName, buffer, bufSize, frameNum );
280 _pico_free( buffer );
288 /* ----------------------------------------------------------------------------
290 ---------------------------------------------------------------------------- */
294 creates a new pico model
297 picoModel_t *PicoNewModel( void ){
301 model = _pico_alloc( sizeof( picoModel_t ) );
302 if ( model == NULL ) {
307 memset( model,0,sizeof( picoModel_t ) );
310 _pico_zero_bounds( model->mins,model->maxs );
312 /* set initial frame count to 1 -sea */
313 model->numFrames = 1;
315 /* return ptr to new model */
323 frees a model and all associated data
326 void PicoFreeModel( picoModel_t *model ){
331 if ( model == NULL ) {
337 _pico_free( model->name );
340 if ( model->fileName ) {
341 _pico_free( model->fileName );
345 for ( i = 0; i < model->numShaders; i++ )
346 PicoFreeShader( model->shader[ i ] );
347 free( model->shader );
350 for ( i = 0; i < model->numSurfaces; i++ )
351 PicoFreeSurface( model->surface[ i ] );
352 free( model->surface );
362 adjusts a models's memory allocations to handle the requested sizes.
363 will always grow, never shrink
366 int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ){
368 if ( model == NULL ) {
373 /* sea: null surface/shader fix (1s=>0s) */
374 if ( numShaders < 0 ) {
377 if ( numSurfaces < 0 ) {
381 /* additional shaders? */
382 while ( numShaders > model->maxShaders )
384 model->maxShaders += PICO_GROW_SHADERS;
385 if ( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) ) {
390 /* set shader count to higher */
391 if ( numShaders > model->numShaders ) {
392 model->numShaders = numShaders;
395 /* additional surfaces? */
396 while ( numSurfaces > model->maxSurfaces )
398 model->maxSurfaces += PICO_GROW_SURFACES;
399 if ( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) ) {
404 /* set shader count to higher */
405 if ( numSurfaces > model->numSurfaces ) {
406 model->numSurfaces = numSurfaces;
415 /* ----------------------------------------------------------------------------
417 ---------------------------------------------------------------------------- */
421 creates a new pico shader and returns its index. -sea
424 picoShader_t *PicoNewShader( picoModel_t *model ){
425 picoShader_t *shader;
428 /* allocate and clear */
429 shader = _pico_alloc( sizeof( picoShader_t ) );
430 if ( shader == NULL ) {
433 memset( shader, 0, sizeof( picoShader_t ) );
435 /* attach it to the model */
436 if ( model != NULL ) {
438 if ( !PicoAdjustModel( model, model->numShaders + 1, 0 ) ) {
439 _pico_free( shader );
444 model->shader[ model->numShaders - 1 ] = shader;
445 shader->model = model;
448 /* setup default shader colors */
449 _pico_set_color( shader->ambientColor,0,0,0,0 );
450 _pico_set_color( shader->diffuseColor,255,255,255,1 );
451 _pico_set_color( shader->specularColor,0,0,0,0 );
453 /* no need to do this, but i do it anyway */
454 shader->transparency = 0;
455 shader->shininess = 0;
457 /* return the newly created shader */
465 frees a shader and all associated data -sea
468 void PicoFreeShader( picoShader_t *shader ){
470 if ( shader == NULL ) {
475 if ( shader->name ) {
476 _pico_free( shader->name );
478 if ( shader->mapName ) {
479 _pico_free( shader->mapName );
482 /* free the shader */
483 _pico_free( shader );
490 finds a named shader in a model
493 picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ){
498 if ( model == NULL || name == NULL ) { /* sea: null name fix */
503 for ( i = 0; i < model->numShaders; i++ )
505 /* skip null shaders or shaders with null names */
506 if ( model->shader[ i ] == NULL ||
507 model->shader[ i ]->name == NULL ) {
511 /* compare the shader name with name we're looking for */
512 if ( caseSensitive ) {
513 if ( !strcmp( name, model->shader[ i ]->name ) ) {
514 return model->shader[ i ];
517 else if ( !_pico_stricmp( name, model->shader[ i ]->name ) ) {
518 return model->shader[ i ];
522 /* named shader not found */
528 /* ----------------------------------------------------------------------------
530 ---------------------------------------------------------------------------- */
534 creates a new pico surface
537 picoSurface_t *PicoNewSurface( picoModel_t *model ){
538 picoSurface_t *surface;
539 char surfaceName[64];
541 /* allocate and clear */
542 surface = _pico_alloc( sizeof( *surface ) );
543 if ( surface == NULL ) {
546 memset( surface, 0, sizeof( *surface ) );
548 /* attach it to the model */
549 if ( model != NULL ) {
551 if ( !PicoAdjustModel( model, 0, model->numSurfaces + 1 ) ) {
552 _pico_free( surface );
557 model->surface[ model->numSurfaces - 1 ] = surface;
558 surface->model = model;
560 /* set default name */
561 sprintf( surfaceName, "Unnamed_%d", model->numSurfaces );
562 PicoSetSurfaceName( surface, surfaceName );
573 frees a surface and all associated data
575 void PicoFreeSurface( picoSurface_t *surface ){
580 if ( surface == NULL ) {
585 _pico_free( surface->xyz );
586 _pico_free( surface->normal );
587 _pico_free( surface->smoothingGroup );
588 _pico_free( surface->index );
589 _pico_free( surface->faceNormal );
591 if ( surface->name ) {
592 _pico_free( surface->name );
596 for ( i = 0; i < surface->numSTArrays; i++ )
597 _pico_free( surface->st[ i ] );
599 for ( i = 0; i < surface->numColorArrays; i++ )
600 _pico_free( surface->color[ i ] );
601 free( surface->color );
603 /* free the surface */
604 _pico_free( surface );
611 adjusts a surface's memory allocations to handle the requested sizes.
612 will always grow, never shrink
615 int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ){
620 if ( surface == NULL ) {
625 if ( numVertexes < 1 ) {
628 if ( numSTArrays < 1 ) {
631 if ( numColorArrays < 1 ) {
634 if ( numIndexes < 1 ) {
638 /* additional vertexes? */
639 while ( numVertexes > surface->maxVertexes ) /* fix */
641 surface->maxVertexes += PICO_GROW_VERTEXES;
642 if ( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) ) {
645 if ( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) ) {
648 if ( !_pico_realloc( (void *) &surface->smoothingGroup, surface->numVertexes * sizeof( *surface->smoothingGroup ), surface->maxVertexes * sizeof( *surface->smoothingGroup ) ) ) {
651 for ( i = 0; i < surface->numSTArrays; i++ )
652 if ( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) ) {
655 for ( i = 0; i < surface->numColorArrays; i++ )
656 if ( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) ) {
661 /* set vertex count to higher */
662 if ( numVertexes > surface->numVertexes ) {
663 surface->numVertexes = numVertexes;
666 /* additional st arrays? */
667 while ( numSTArrays > surface->maxSTArrays ) /* fix */
669 surface->maxSTArrays += PICO_GROW_ARRAYS;
670 if ( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) ) {
673 while ( surface->numSTArrays < numSTArrays )
675 surface->st[ surface->numSTArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
676 memset( surface->st[ surface->numSTArrays ], 0, surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
677 surface->numSTArrays++;
681 /* additional color arrays? */
682 while ( numColorArrays > surface->maxColorArrays ) /* fix */
684 surface->maxColorArrays += PICO_GROW_ARRAYS;
685 if ( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) ) {
688 while ( surface->numColorArrays < numColorArrays )
690 surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
691 memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
692 surface->numColorArrays++;
696 /* additional indexes? */
697 while ( numIndexes > surface->maxIndexes ) /* fix */
699 surface->maxIndexes += PICO_GROW_INDEXES;
700 if ( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) ) {
705 /* set index count to higher */
706 if ( numIndexes > surface->numIndexes ) {
707 surface->numIndexes = numIndexes;
710 /* additional face normals? */
711 while ( numFaceNormals > surface->maxFaceNormals ) /* fix */
713 surface->maxFaceNormals += PICO_GROW_FACES;
714 if ( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) ) {
719 /* set face normal count to higher */
720 if ( numFaceNormals > surface->numFaceNormals ) {
721 surface->numFaceNormals = numFaceNormals;
730 * Finds first matching named surface in a model.
732 picoSurface_t *PicoFindSurface(
733 picoModel_t *model, char *name, int caseSensitive ){
737 if ( model == NULL || name == NULL ) {
742 for ( i = 0; i < model->numSurfaces; i++ )
744 /* skip null surfaces or surfaces with null names */
745 if ( model->surface[ i ] == NULL ||
746 model->surface[ i ]->name == NULL ) {
750 /* compare the surface name with name we're looking for */
751 if ( caseSensitive ) {
752 if ( !strcmp( name,model->surface[ i ]->name ) ) {
753 return model->surface[ i ];
757 if ( !_pico_stricmp( name,model->surface[ i ]->name ) ) {
758 return model->surface[ i ];
762 /* named surface not found */
768 /*----------------------------------------------------------------------------
769 PicoSet*() Setter Functions
770 ----------------------------------------------------------------------------*/
772 void PicoSetModelName( picoModel_t *model, const char *name ){
773 if ( model == NULL || name == NULL ) {
776 if ( model->name != NULL ) {
777 _pico_free( model->name );
780 model->name = _pico_clone_alloc( name );
785 void PicoSetModelFileName( picoModel_t *model, const char *fileName ){
786 if ( model == NULL || fileName == NULL ) {
789 if ( model->fileName != NULL ) {
790 _pico_free( model->fileName );
793 model->fileName = _pico_clone_alloc( fileName );
798 void PicoSetModelFrameNum( picoModel_t *model, int frameNum ){
799 if ( model == NULL ) {
802 model->frameNum = frameNum;
807 void PicoSetModelNumFrames( picoModel_t *model, int numFrames ){
808 if ( model == NULL ) {
811 model->numFrames = numFrames;
816 void PicoSetModelData( picoModel_t *model, void *data ){
817 if ( model == NULL ) {
825 void PicoSetShaderName( picoShader_t *shader, char *name ){
826 if ( shader == NULL || name == NULL ) {
829 if ( shader->name != NULL ) {
830 _pico_free( shader->name );
833 shader->name = _pico_clone_alloc( name );
838 void PicoSetShaderMapName( picoShader_t *shader, char *mapName ){
839 if ( shader == NULL || mapName == NULL ) {
842 if ( shader->mapName != NULL ) {
843 _pico_free( shader->mapName );
846 shader->mapName = _pico_clone_alloc( mapName );
851 void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ){
852 if ( shader == NULL || color == NULL ) {
855 shader->ambientColor[ 0 ] = color[ 0 ];
856 shader->ambientColor[ 1 ] = color[ 1 ];
857 shader->ambientColor[ 2 ] = color[ 2 ];
858 shader->ambientColor[ 3 ] = color[ 3 ];
863 void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ){
864 if ( shader == NULL || color == NULL ) {
867 shader->diffuseColor[ 0 ] = color[ 0 ];
868 shader->diffuseColor[ 1 ] = color[ 1 ];
869 shader->diffuseColor[ 2 ] = color[ 2 ];
870 shader->diffuseColor[ 3 ] = color[ 3 ];
875 void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ){
876 if ( shader == NULL || color == NULL ) {
879 shader->specularColor[ 0 ] = color[ 0 ];
880 shader->specularColor[ 1 ] = color[ 1 ];
881 shader->specularColor[ 2 ] = color[ 2 ];
882 shader->specularColor[ 3 ] = color[ 3 ];
887 void PicoSetShaderTransparency( picoShader_t *shader, float value ){
888 if ( shader == NULL ) {
891 shader->transparency = value;
893 /* cap to 0..1 range */
894 if ( shader->transparency < 0.0 ) {
895 shader->transparency = 0.0;
897 if ( shader->transparency > 1.0 ) {
898 shader->transparency = 1.0;
904 void PicoSetShaderShininess( picoShader_t *shader, float value ){
905 if ( shader == NULL ) {
908 shader->shininess = value;
910 /* cap to 0..127 range */
911 if ( shader->shininess < 0.0 ) {
912 shader->shininess = 0.0;
914 if ( shader->shininess > 127.0 ) {
915 shader->shininess = 127.0;
921 void PicoSetSurfaceData( picoSurface_t *surface, void *data ){
922 if ( surface == NULL ) {
925 surface->data = data;
930 void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ){
931 if ( surface == NULL ) {
934 surface->type = type;
939 void PicoSetSurfaceName( picoSurface_t *surface, const char *name ){
940 if ( surface == NULL || name == NULL ) {
943 if ( surface->name != NULL ) {
944 _pico_free( surface->name );
947 surface->name = _pico_clone_alloc( name );
952 void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ){
953 if ( surface == NULL ) {
956 surface->shader = shader;
961 void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ){
962 if ( surface == NULL || num < 0 || xyz == NULL ) {
965 if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
968 _pico_copy_vec( xyz, surface->xyz[ num ] );
969 if ( surface->model != NULL ) {
970 _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs );
976 void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ){
977 if ( surface == NULL || num < 0 || normal == NULL ) {
980 if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
983 _pico_copy_vec( normal, surface->normal[ num ] );
988 void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ){
989 if ( surface == NULL || num < 0 || st == NULL ) {
992 if ( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) ) {
995 surface->st[ array ][ num ][ 0 ] = st[ 0 ];
996 surface->st[ array ][ num ][ 1 ] = st[ 1 ];
1001 void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color ){
1002 if ( surface == NULL || num < 0 || color == NULL ) {
1005 if ( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) ) {
1008 surface->color[ array ][ num ][ 0 ] = color[ 0 ];
1009 surface->color[ array ][ num ][ 1 ] = color[ 1 ];
1010 surface->color[ array ][ num ][ 2 ] = color[ 2 ];
1011 surface->color[ array ][ num ][ 3 ] = color[ 3 ];
1016 void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ){
1017 if ( surface == NULL || num < 0 ) {
1020 if ( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) ) {
1023 surface->index[ num ] = index;
1028 void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ){
1029 if ( num < 0 || index == NULL || count < 1 ) {
1032 if ( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) ) {
1035 memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) );
1040 void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ){
1041 if ( surface == NULL || num < 0 || normal == NULL ) {
1044 if ( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) ) {
1047 _pico_copy_vec( normal, surface->faceNormal[ num ] );
1051 void PicoSetSurfaceSmoothingGroup( picoSurface_t *surface, int num, picoIndex_t smoothingGroup ){
1055 if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
1058 surface->smoothingGroup[ num ] = smoothingGroup;
1062 void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ){
1063 if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
1066 surface->special[ num ] = special;
1071 /*----------------------------------------------------------------------------
1072 PicoGet*() Getter Functions
1073 ----------------------------------------------------------------------------*/
1075 char *PicoGetModelName( picoModel_t *model ){
1076 if ( model == NULL ) {
1079 if ( model->name == NULL ) {
1087 char *PicoGetModelFileName( picoModel_t *model ){
1088 if ( model == NULL ) {
1091 if ( model->fileName == NULL ) {
1094 return model->fileName;
1099 int PicoGetModelFrameNum( picoModel_t *model ){
1100 if ( model == NULL ) {
1103 return model->frameNum;
1108 int PicoGetModelNumFrames( picoModel_t *model ){
1109 if ( model == NULL ) {
1112 return model->numFrames;
1117 void *PicoGetModelData( picoModel_t *model ){
1118 if ( model == NULL ) {
1126 int PicoGetModelNumShaders( picoModel_t *model ){
1127 if ( model == NULL ) {
1130 return model->numShaders;
1135 picoShader_t *PicoGetModelShader( picoModel_t *model, int num ){
1136 /* a few sanity checks */
1137 if ( model == NULL ) {
1140 if ( model->shader == NULL ) {
1143 if ( num < 0 || num >= model->numShaders ) {
1147 /* return the shader */
1148 return model->shader[ num ];
1153 int PicoGetModelNumSurfaces( picoModel_t *model ){
1154 if ( model == NULL ) {
1157 return model->numSurfaces;
1162 picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ){
1163 /* a few sanity checks */
1164 if ( model == NULL ) {
1167 if ( model->surface == NULL ) {
1170 if ( num < 0 || num >= model->numSurfaces ) {
1174 /* return the surface */
1175 return model->surface[ num ];
1180 int PicoGetModelTotalVertexes( picoModel_t *model ){
1184 if ( model == NULL ) {
1187 if ( model->surface == NULL ) {
1192 for ( i = 0; i < model->numSurfaces; i++ )
1193 count += PicoGetSurfaceNumVertexes( model->surface[ i ] );
1200 int PicoGetModelTotalIndexes( picoModel_t *model ){
1204 if ( model == NULL ) {
1207 if ( model->surface == NULL ) {
1212 for ( i = 0; i < model->numSurfaces; i++ )
1213 count += PicoGetSurfaceNumIndexes( model->surface[ i ] );
1220 char *PicoGetShaderName( picoShader_t *shader ){
1221 if ( shader == NULL ) {
1224 if ( shader->name == NULL ) {
1227 return shader->name;
1232 char *PicoGetShaderMapName( picoShader_t *shader ){
1233 if ( shader == NULL ) {
1236 if ( shader->mapName == NULL ) {
1239 return shader->mapName;
1244 picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ){
1245 if ( shader == NULL ) {
1248 return shader->ambientColor;
1253 picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ){
1254 if ( shader == NULL ) {
1257 return shader->diffuseColor;
1262 picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ){
1263 if ( shader == NULL ) {
1266 return shader->specularColor;
1271 float PicoGetShaderTransparency( picoShader_t *shader ){
1272 if ( shader == NULL ) {
1275 return shader->transparency;
1280 float PicoGetShaderShininess( picoShader_t *shader ){
1281 if ( shader == NULL ) {
1284 return shader->shininess;
1289 void *PicoGetSurfaceData( picoSurface_t *surface ){
1290 if ( surface == NULL ) {
1293 return surface->data;
1298 picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ){
1299 if ( surface == NULL ) {
1302 return surface->type;
1307 char *PicoGetSurfaceName( picoSurface_t *surface ){
1308 if ( surface == NULL ) {
1311 if ( surface->name == NULL ) {
1314 return surface->name;
1319 picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ){
1320 if ( surface == NULL ) {
1323 return surface->shader;
1328 int PicoGetSurfaceNumVertexes( picoSurface_t *surface ){
1329 if ( surface == NULL ) {
1332 return surface->numVertexes;
1337 picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ){
1338 if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
1341 return surface->xyz[ num ];
1346 picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ){
1347 if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
1350 return surface->normal[ num ];
1355 picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ){
1356 if ( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes ) {
1359 return surface->st[ array ][ num ];
1364 picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ){
1365 if ( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes ) {
1368 return surface->color[ array ][ num ];
1373 int PicoGetSurfaceNumIndexes( picoSurface_t *surface ){
1374 if ( surface == NULL ) {
1377 return surface->numIndexes;
1382 picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ){
1383 if ( surface == NULL || num < 0 || num > surface->numIndexes ) {
1386 return surface->index[ num ];
1391 picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ){
1392 if ( surface == NULL || num < 0 || num > surface->numIndexes ) {
1395 return &surface->index[ num ];
1399 picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ){
1400 if ( surface == NULL || num < 0 || num > surface->numFaceNormals ) {
1403 return surface->faceNormal[ num ];
1406 picoIndex_t PicoGetSurfaceSmoothingGroup( picoSurface_t *surface, int num ){
1407 if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
1410 return surface->smoothingGroup[ num ];
1414 int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ){
1415 if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
1418 return surface->special[ num ];
1423 /* ----------------------------------------------------------------------------
1424 hashtable related functions
1425 ---------------------------------------------------------------------------- */
1427 /* hashtable code for faster vertex lookups */
1428 //#define HASHTABLE_SIZE 32768 // 2048 /* power of 2, use & */
1429 #define HASHTABLE_SIZE 7919 // 32749 // 2039 /* prime, use % */
1431 int PicoGetHashTableSize( void ){
1432 return HASHTABLE_SIZE;
1435 #define HASH_USE_EPSILON
1437 #ifdef HASH_USE_EPSILON
1438 #define HASH_XYZ_EPSILON 0.01f
1439 #define HASH_XYZ_EPSILONSPACE_MULTIPLIER 1.f / HASH_XYZ_EPSILON
1440 #define HASH_ST_EPSILON 0.0001f
1441 #define HASH_NORMAL_EPSILON 0.02f
1444 unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ){
1445 unsigned int hash = 0;
1447 #ifndef HASH_USE_EPSILON
1448 hash += ~( *( (unsigned int*) &xyz[ 0 ] ) << 15 );
1449 hash ^= ( *( (unsigned int*) &xyz[ 0 ] ) >> 10 );
1450 hash += ( *( (unsigned int*) &xyz[ 1 ] ) << 3 );
1451 hash ^= ( *( (unsigned int*) &xyz[ 1 ] ) >> 6 );
1452 hash += ~( *( (unsigned int*) &xyz[ 2 ] ) << 11 );
1453 hash ^= ( *( (unsigned int*) &xyz[ 2 ] ) >> 16 );
1455 picoVec3_t xyz_epsilonspace;
1457 _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace );
1458 xyz_epsilonspace[ 0 ] = (float)floor( xyz_epsilonspace[ 0 ] );
1459 xyz_epsilonspace[ 1 ] = (float)floor( xyz_epsilonspace[ 1 ] );
1460 xyz_epsilonspace[ 2 ] = (float)floor( xyz_epsilonspace[ 2 ] );
1462 hash += ~( *( (unsigned int*) &xyz_epsilonspace[ 0 ] ) << 15 );
1463 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 0 ] ) >> 10 );
1464 hash += ( *( (unsigned int*) &xyz_epsilonspace[ 1 ] ) << 3 );
1465 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 1 ] ) >> 6 );
1466 hash += ~( *( (unsigned int*) &xyz_epsilonspace[ 2 ] ) << 11 );
1467 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 2 ] ) >> 16 );
1470 //hash = hash & (HASHTABLE_SIZE-1);
1471 hash = hash % ( HASHTABLE_SIZE );
1475 picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ){
1476 picoVertexCombinationHash_t **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof( picoVertexCombinationHash_t* ) );
1478 memset( hashTable, 0, HASHTABLE_SIZE * sizeof( picoVertexCombinationHash_t* ) );
1483 void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ){
1485 picoVertexCombinationHash_t *vertexCombinationHash;
1486 picoVertexCombinationHash_t *nextVertexCombinationHash;
1489 if ( hashTable == NULL ) {
1493 for ( i = 0; i < HASHTABLE_SIZE; i++ )
1495 if ( hashTable[ i ] ) {
1496 nextVertexCombinationHash = NULL;
1498 for ( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash )
1500 nextVertexCombinationHash = vertexCombinationHash->next;
1501 if ( vertexCombinationHash->data != NULL ) {
1502 _pico_free( vertexCombinationHash->data );
1504 _pico_free( vertexCombinationHash );
1509 _pico_free( hashTable );
1512 picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ){
1514 picoVertexCombinationHash_t *vertexCombinationHash;
1517 if ( hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) {
1521 hash = PicoVertexCoordGenerateHash( xyz );
1523 for ( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next )
1525 #ifndef HASH_USE_EPSILON
1527 if ( ( vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ] ) ) {
1532 if ( ( vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ] ) ) {
1537 if ( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] ) {
1542 if ( ( fabs( xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ] ) ) > HASH_XYZ_EPSILON ||
1543 ( fabs( xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ] ) ) > HASH_XYZ_EPSILON ||
1544 ( fabs( xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ] ) ) > HASH_XYZ_EPSILON ) {
1549 if ( ( fabs( normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ] ) ) > HASH_NORMAL_EPSILON ||
1550 ( fabs( normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ] ) ) > HASH_NORMAL_EPSILON ||
1551 ( fabs( normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ] ) ) > HASH_NORMAL_EPSILON ) {
1556 if ( ( fabs( st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ] ) ) > HASH_ST_EPSILON ||
1557 ( fabs( st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ] ) ) > HASH_ST_EPSILON ) {
1563 if ( *( (int*) vertexCombinationHash->vcd.color ) != *( (int*) color ) ) {
1568 return vertexCombinationHash;
1574 picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ){
1576 picoVertexCombinationHash_t *vertexCombinationHash;
1579 if ( hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) {
1583 vertexCombinationHash = _pico_alloc( sizeof( picoVertexCombinationHash_t ) );
1585 if ( !vertexCombinationHash ) {
1589 hash = PicoVertexCoordGenerateHash( xyz );
1591 _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz );
1592 _pico_copy_vec( normal, vertexCombinationHash->vcd.normal );
1593 _pico_copy_vec2( st, vertexCombinationHash->vcd.st );
1594 _pico_copy_color( color, vertexCombinationHash->vcd.color );
1595 vertexCombinationHash->index = index;
1596 vertexCombinationHash->data = NULL;
1597 vertexCombinationHash->next = hashTable[ hash ];
1598 hashTable[ hash ] = vertexCombinationHash;
1600 return vertexCombinationHash;
1603 /* ----------------------------------------------------------------------------
1604 specialized routines
1605 ---------------------------------------------------------------------------- */
1608 PicoFindSurfaceVertex()
1609 finds a vertex matching the set parameters
1610 fixme: needs non-naive algorithm
1613 int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color, picoIndex_t smoothingGroup ){
1618 if ( surface == NULL || surface->numVertexes <= 0 ) {
1622 /* walk vertex list */
1623 for ( i = 0; i < surface->numVertexes; i++ )
1626 if ( xyz != NULL && ( surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ] ) ) {
1631 if ( normal != NULL && ( surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ] ) ) {
1636 if ( surface->smoothingGroup[ i ] != smoothingGroup ) {
1641 if ( numSTs > 0 && st != NULL ) {
1642 for ( j = 0; j < numSTs; j++ )
1644 if ( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] ) {
1648 if ( j != numSTs ) {
1654 if ( numColors > 0 && color != NULL ) {
1655 for ( j = 0; j < numSTs; j++ )
1657 if ( *( (int*) surface->color[ j ] ) != *( (int*) color[ j ] ) ) {
1661 if ( j != numColors ) {
1666 /* vertex matches */
1677 typedef struct _IndexArray IndexArray;
1684 void indexarray_push_back( IndexArray* self, picoIndex_t value ){
1685 *self->last++ = value;
1688 size_t indexarray_size( IndexArray* self ){
1689 return self->last - self->data;
1692 void indexarray_reserve( IndexArray* self, size_t size ){
1693 self->data = self->last = _pico_calloc( size, sizeof( picoIndex_t ) );
1696 void indexarray_clear( IndexArray* self ){
1697 _pico_free( self->data );
1700 typedef struct _BinaryTreeNode BinaryTreeNode;
1701 struct _BinaryTreeNode
1707 typedef struct _BinaryTree BinaryTree;
1710 BinaryTreeNode* data;
1711 BinaryTreeNode* last;
1714 void binarytree_extend( BinaryTree* self ){
1715 self->last->left = 0;
1716 self->last->right = 0;
1720 size_t binarytree_size( BinaryTree* self ){
1721 return self->last - self->data;
1724 void binarytree_reserve( BinaryTree* self, size_t size ){
1725 self->data = self->last = _pico_calloc( size, sizeof( BinaryTreeNode ) );
1728 void binarytree_clear( BinaryTree* self ){
1729 _pico_free( self->data );
1732 typedef int ( *LessFunc )( void*, picoIndex_t, picoIndex_t );
1734 typedef struct _UniqueIndices UniqueIndices;
1735 struct _UniqueIndices
1743 size_t UniqueIndices_size( UniqueIndices* self ){
1744 return binarytree_size( &self->tree );
1747 void UniqueIndices_reserve( UniqueIndices* self, size_t size ){
1748 binarytree_reserve( &self->tree, size );
1749 indexarray_reserve( &self->indices, size );
1752 void UniqueIndices_init( UniqueIndices* self, LessFunc lessFunc, void* lessData ){
1753 self->lessFunc = lessFunc;
1754 self->lessData = lessData;
1757 void UniqueIndices_destroy( UniqueIndices* self ){
1758 binarytree_clear( &self->tree );
1759 indexarray_clear( &self->indices );
1763 picoIndex_t UniqueIndices_find_or_insert( UniqueIndices* self, picoIndex_t value ){
1764 picoIndex_t index = 0;
1768 if ( self->lessFunc( self->lessData, value, self->indices.data[index] ) ) {
1769 BinaryTreeNode* node = self->tree.data + index;
1770 if ( node->left != 0 ) {
1776 node->left = (picoIndex_t)binarytree_size( &self->tree );
1777 binarytree_extend( &self->tree );
1778 indexarray_push_back( &self->indices, value );
1782 if ( self->lessFunc( self->lessData, self->indices.data[index], value ) ) {
1783 BinaryTreeNode* node = self->tree.data + index;
1784 if ( node->right != 0 ) {
1785 index = node->right;
1790 node->right = (picoIndex_t)binarytree_size( &self->tree );
1791 binarytree_extend( &self->tree );
1792 indexarray_push_back( &self->indices, value );
1801 picoIndex_t UniqueIndices_insert( UniqueIndices* self, picoIndex_t value ){
1802 if ( self->tree.data == self->tree.last ) {
1803 binarytree_extend( &self->tree );
1804 indexarray_push_back( &self->indices, value );
1809 return UniqueIndices_find_or_insert( self, value );
1813 typedef struct picoSmoothVertices_s picoSmoothVertices_t;
1814 struct picoSmoothVertices_s
1817 picoIndex_t* smoothingGroups;
1820 int lessSmoothVertex( void* data, picoIndex_t first, picoIndex_t second ){
1821 picoSmoothVertices_t* smoothVertices = data;
1823 if ( smoothVertices->xyz[first][0] != smoothVertices->xyz[second][0] ) {
1824 return smoothVertices->xyz[first][0] < smoothVertices->xyz[second][0];
1826 if ( smoothVertices->xyz[first][1] != smoothVertices->xyz[second][1] ) {
1827 return smoothVertices->xyz[first][1] < smoothVertices->xyz[second][1];
1829 if ( smoothVertices->xyz[first][2] != smoothVertices->xyz[second][2] ) {
1830 return smoothVertices->xyz[first][2] < smoothVertices->xyz[second][2];
1832 if ( smoothVertices->smoothingGroups[first] != smoothVertices->smoothingGroups[second] ) {
1833 return smoothVertices->smoothingGroups[first] < smoothVertices->smoothingGroups[second];
1838 void _pico_vertices_combine_shared_normals( picoVec3_t* xyz, picoIndex_t* smoothingGroups, picoVec3_t* normals, picoIndex_t numVertices ){
1839 UniqueIndices vertices;
1841 picoSmoothVertices_t smoothVertices = { xyz, smoothingGroups };
1842 UniqueIndices_init( &vertices, lessSmoothVertex, &smoothVertices );
1843 UniqueIndices_reserve( &vertices, numVertices );
1844 indexarray_reserve( &indices, numVertices );
1849 for (; i < numVertices; ++i )
1851 size_t size = UniqueIndices_size( &vertices );
1852 picoIndex_t index = UniqueIndices_insert( &vertices, i );
1853 if ( (size_t)index != size ) {
1854 float* normal = normals[vertices.indices.data[index]];
1855 _pico_add_vec( normal, normals[i], normal );
1857 indexarray_push_back( &indices, index );
1862 picoIndex_t maxIndex = 0;
1863 picoIndex_t* i = indices.data;
1864 for (; i != indices.last; ++i )
1866 if ( *i <= maxIndex ) {
1867 _pico_copy_vec( normals[vertices.indices.data[*i]], normals[i - indices.data] );
1876 UniqueIndices_destroy( &vertices );
1877 indexarray_clear( &indices );
1880 typedef picoVec3_t* picoNormalIter_t;
1881 typedef picoIndex_t* picoIndexIter_t;
1883 #define THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL 1
1885 void _pico_triangles_generate_weighted_normals( picoIndexIter_t first, picoIndexIter_t end, picoVec3_t* xyz, picoVec3_t* normals ){
1886 for (; first != end; first += 3 )
1888 #if ( THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL )
1889 picoVec3_t weightedNormal;
1891 float* a = xyz[*( first + 0 )];
1892 float* b = xyz[*( first + 1 )];
1893 float* c = xyz[*( first + 2 )];
1895 _pico_subtract_vec( b, a, ba );
1896 _pico_subtract_vec( c, a, ca );
1897 _pico_cross_vec( ca, ba, weightedNormal );
1904 float* normal = normals[*( first + j )];
1905 #if ( !THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL )
1906 picoVec3_t weightedNormal;
1908 float* a = xyz[*( first + ( ( j + 0 ) % 3 ) )];
1909 float* b = xyz[*( first + ( ( j + 1 ) % 3 ) )];
1910 float* c = xyz[*( first + ( ( j + 2 ) % 3 ) )];
1912 _pico_subtract_vec( b, a, ba );
1913 _pico_subtract_vec( c, a, ca );
1914 _pico_cross_vec( ca, ba, weightedNormal );
1917 _pico_add_vec( weightedNormal, normal, normal );
1923 void _pico_normals_zero( picoNormalIter_t first, picoNormalIter_t last ){
1924 for (; first != last; ++first )
1926 _pico_zero_vec( *first );
1930 void _pico_normals_normalize( picoNormalIter_t first, picoNormalIter_t last ){
1931 for (; first != last; ++first )
1933 _pico_normalize_vec( *first );
1937 double _pico_length_vec( picoVec3_t vec ){
1938 return sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] );
1941 #define NORMAL_UNIT_LENGTH_EPSILON 0.01
1942 #define FLOAT_EQUAL_EPSILON( f, other, epsilon ) ( fabs( f - other ) < epsilon )
1944 int _pico_normal_is_unit_length( picoVec3_t normal ){
1945 return FLOAT_EQUAL_EPSILON( _pico_length_vec( normal ), 1.0, NORMAL_UNIT_LENGTH_EPSILON );
1948 int _pico_normal_within_tolerance( picoVec3_t normal, picoVec3_t other ){
1949 return _pico_dot_vec( normal, other ) > 0.0f;
1953 void _pico_normals_assign_generated_normals( picoNormalIter_t first, picoNormalIter_t last, picoNormalIter_t generated ){
1954 for (; first != last; ++first, ++generated )
1956 if ( !_pico_normal_is_unit_length( *first ) || !_pico_normal_within_tolerance( *first, *generated ) ) {
1957 _pico_copy_vec( *generated, *first );
1962 void PicoFixSurfaceNormals( picoSurface_t* surface ){
1963 picoVec3_t* normals = (picoVec3_t*)_pico_calloc( surface->numVertexes, sizeof( picoVec3_t ) );
1965 _pico_normals_zero( normals, normals + surface->numVertexes );
1967 _pico_triangles_generate_weighted_normals( surface->index, surface->index + surface->numIndexes, surface->xyz, normals );
1968 _pico_vertices_combine_shared_normals( surface->xyz, surface->smoothingGroup, normals, surface->numVertexes );
1970 _pico_normals_normalize( normals, normals + surface->numVertexes );
1972 _pico_normals_assign_generated_normals( surface->normal, surface->normal + surface->numVertexes, normals );
1974 _pico_free( normals );
1979 PicoRemapModel() - sea
1980 remaps model material/etc. information using the remappings
1981 contained in the given 'remapFile' (full path to the ascii file to open)
1982 returns 1 on success or 0 on error
1985 #define _prm_error_return \
1987 _pico_free_parser( p ); \
1988 _pico_free_file( remapBuffer ); \
1992 int PicoRemapModel( picoModel_t *model, char *remapFile ){
1994 picoByte_t *remapBuffer;
1999 if ( model == NULL || remapFile == NULL ) {
2003 /* load remap file contents */
2004 _pico_load_file( remapFile,&remapBuffer,&remapBufSize );
2007 if ( remapBufSize == 0 ) {
2008 return 1; /* file is empty: no error */
2010 if ( remapBufSize < 0 ) {
2011 return 0; /* load failed: error */
2014 /* create a new pico parser */
2015 p = _pico_new_parser( remapBuffer, remapBufSize );
2017 /* ram is really cheap nowadays... */
2024 /* get next token in remap file */
2025 if ( !_pico_parse( p,1 ) ) {
2029 /* skip over c++ style comment lines */
2030 if ( !_pico_stricmp( p->token,"//" ) ) {
2031 _pico_parse_skip_rest( p );
2035 /* block for quick material shader name remapping */
2036 /* materials { "m" (=>|->|=) "s" } */
2037 if ( !_pico_stricmp( p->token, "materials" ) ) {
2041 if ( !_pico_parse_check( p,1,"{" ) ) {
2045 /* process assignments */
2048 picoShader_t *shader;
2052 /* get material name */
2053 if ( _pico_parse( p,1 ) == NULL ) {
2056 if ( !strlen( p->token ) ) {
2059 materialName = _pico_clone_alloc( p->token );
2060 if ( materialName == NULL ) {
2065 if ( p->token[0] == '{' ) {
2068 if ( p->token[0] == '}' ) {
2075 /* get next token (assignment token or shader name) */
2076 if ( !_pico_parse( p,0 ) ) {
2077 _pico_free( materialName );
2080 /* skip assignment token (if present) */
2081 if ( !strcmp( p->token,"=>" ) ||
2082 !strcmp( p->token,"->" ) ||
2083 !strcmp( p->token,"=" ) ) {
2084 /* simply grab the next token */
2085 if ( !_pico_parse( p,0 ) ) {
2086 _pico_free( materialName );
2090 /* try to find material by name */
2091 shader = PicoFindShader( model,materialName,0 );
2093 /* we've found a material matching the name */
2094 if ( shader != NULL ) {
2095 PicoSetShaderName( shader,p->token );
2097 /* free memory used by material name */
2098 _pico_free( materialName );
2101 _pico_parse_skip_rest( p );
2104 /* block for detailed single material remappings */
2105 /* materials[ "m" ] { key data... } */
2106 else if ( !_pico_stricmp( p->token,"materials[" ) ) {
2107 picoShader_t *shader;
2108 char *tempMaterialName;
2111 /* get material name */
2112 if ( !_pico_parse( p,0 ) ) {
2116 /* temporary copy of material name */
2117 tempMaterialName = _pico_clone_alloc( p->token );
2118 if ( tempMaterialName == NULL ) {
2122 /* check square closing bracket */
2123 if ( !_pico_parse_check( p,0,"]" ) ) {
2127 /* try to find material by name */
2128 shader = PicoFindShader( model,tempMaterialName,0 );
2130 /* free memory used by temporary material name */
2131 _pico_free( tempMaterialName );
2133 /* we haven't found a material matching the name */
2134 /* so we simply skip the braced section now and */
2135 /* continue parsing with the next main token */
2136 if ( shader == NULL ) {
2137 _pico_parse_skip_braced( p );
2140 /* check opening bracket */
2141 if ( !_pico_parse_check( p,1,"{" ) ) {
2145 /* process material info keys */
2149 if ( _pico_parse( p,1 ) == NULL ) {
2152 if ( !strlen( p->token ) ) {
2157 if ( p->token[0] == '{' ) {
2160 if ( p->token[0] == '}' ) {
2167 /* remap shader name */
2168 if ( !_pico_stricmp( p->token,"shader" ) ) {
2169 if ( !_pico_parse( p,0 ) ) {
2172 PicoSetShaderName( shader,p->token );
2174 /* remap shader map name */
2175 else if ( !_pico_stricmp( p->token,"mapname" ) ) {
2176 if ( !_pico_parse( p,0 ) ) {
2179 PicoSetShaderMapName( shader,p->token );
2181 /* remap shader's ambient color */
2182 else if ( !_pico_stricmp( p->token,"ambient" ) ) {
2186 /* get vector from parser */
2187 if ( !_pico_parse_vec( p,v ) ) {
2191 /* store as color */
2192 color[ 0 ] = (picoByte_t)v[ 0 ];
2193 color[ 1 ] = (picoByte_t)v[ 1 ];
2194 color[ 2 ] = (picoByte_t)v[ 2 ];
2196 /* set new ambient color */
2197 PicoSetShaderAmbientColor( shader,color );
2199 /* remap shader's diffuse color */
2200 else if ( !_pico_stricmp( p->token,"diffuse" ) ) {
2204 /* get vector from parser */
2205 if ( !_pico_parse_vec( p,v ) ) {
2209 /* store as color */
2210 color[ 0 ] = (picoByte_t)v[ 0 ];
2211 color[ 1 ] = (picoByte_t)v[ 1 ];
2212 color[ 2 ] = (picoByte_t)v[ 2 ];
2214 /* set new ambient color */
2215 PicoSetShaderDiffuseColor( shader,color );
2217 /* remap shader's specular color */
2218 else if ( !_pico_stricmp( p->token,"specular" ) ) {
2222 /* get vector from parser */
2223 if ( !_pico_parse_vec( p,v ) ) {
2227 /* store as color */
2228 color[ 0 ] = (picoByte_t)v[ 0 ];
2229 color[ 1 ] = (picoByte_t)v[ 1 ];
2230 color[ 2 ] = (picoByte_t)v[ 2 ];
2232 /* set new ambient color */
2233 PicoSetShaderSpecularColor( shader,color );
2236 _pico_parse_skip_rest( p );
2239 /* end 'materials[' */
2242 /* free both parser and file buffer */
2243 _pico_free_parser( p );
2244 _pico_free_file( remapBuffer );
2246 /* return with success */
2252 PicoAddTriangleToModel() - jhefty
2253 A nice way to add individual triangles to the model.
2254 Chooses an appropriate surface based on the shader, or adds a new surface if necessary
2257 void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals,
2258 int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors,
2259 picoShader_t* shader, const char *name, picoIndex_t* smoothingGroup ){
2262 picoSurface_t* workSurface = NULL;
2264 /* see if a surface already has the shader */
2265 for ( i = 0 ; i < model->numSurfaces ; i++ )
2267 workSurface = model->surface[i];
2268 if ( !name || !strcmp( workSurface->name, name ) ) {
2269 if ( workSurface->shader == shader ) {
2275 /* no surface uses this shader yet, so create a new surface */
2276 if ( !workSurface || i >= model->numSurfaces ) {
2277 /* create a new surface in the model for the unique shader */
2278 workSurface = PicoNewSurface( model );
2279 if ( !workSurface ) {
2280 _pico_printf( PICO_ERROR, "Could not allocate a new surface!\n" );
2284 /* do surface setup */
2285 PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
2286 PicoSetSurfaceName( workSurface, name ? name : shader->name );
2287 PicoSetSurfaceShader( workSurface, shader );
2290 /* add the triangle data to the surface */
2291 for ( i = 0 ; i < 3 ; i++ )
2293 /* get the next free spot in the index array */
2294 int newVertIndex = PicoGetSurfaceNumIndexes( workSurface );
2296 /* get the index of the vertex that we're going to store at newVertIndex */
2297 vertDataIndex = PicoFindSurfaceVertexNum( workSurface, *xyz[i], *normals[i], numSTs, st[i], numColors, colors[i], smoothingGroup[i] );
2299 /* the vertex wasn't found, so create a new vertex in the pool from the data we have */
2300 if ( vertDataIndex == -1 ) {
2301 /* find the next spot for a new vertex */
2302 vertDataIndex = PicoGetSurfaceNumVertexes( workSurface );
2304 /* assign the data to it */
2305 PicoSetSurfaceXYZ( workSurface,vertDataIndex, *xyz[i] );
2306 PicoSetSurfaceNormal( workSurface, vertDataIndex, *normals[i] );
2308 /* make sure to copy over all available ST's and colors for the vertex */
2309 for ( j = 0 ; j < numColors ; j++ )
2311 PicoSetSurfaceColor( workSurface, j, vertDataIndex, colors[i][j] );
2313 for ( j = 0 ; j < numSTs ; j++ )
2315 PicoSetSurfaceST( workSurface, j, vertDataIndex, st[i][j] );
2318 PicoSetSurfaceSmoothingGroup( workSurface, vertDataIndex, smoothingGroup[i] );
2321 /* add this vertex to the triangle */
2322 PicoSetSurfaceIndex( workSurface, newVertIndex, vertDataIndex );