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 );
176 _pico_deduce_shadernames( model );
186 the meat and potatoes function
189 picoModel_t *PicoLoadModel( const char *fileName, int frameNum ){
190 const picoModule_t **modules, *pm;
199 /* make sure we've got a file name */
200 if ( fileName == NULL ) {
201 _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" );
205 /* load file data (buffer is allocated by host app) */
206 _pico_load_file( fileName, &buffer, &bufSize );
208 _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName );
212 /* get ptr to list of supported modules */
213 modules = PicoModuleList( NULL );
215 /* run it through the various loader functions and try */
216 /* to find a loader that fits the given file data */
217 for ( ; *modules != NULL; modules++ )
227 /* module must be able to load */
228 if ( pm->canload == NULL || pm->load == NULL ) {
232 model = PicoModuleLoadModel( pm, fileName, buffer, bufSize, frameNum );
233 if ( model != NULL ) {
234 /* model was loaded, so break out of loop */
239 /* free memory used by file buffer */
241 _pico_free_file( buffer );
248 picoModel_t *PicoModuleLoadModelStream( const picoModule_t* module, void* inputStream, PicoInputStreamReadFunc inputStreamRead, size_t streamLength, int frameNum, const char *fileName ){
257 if ( inputStream == NULL ) {
258 _pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStream == NULL)" );
262 if ( inputStreamRead == NULL ) {
263 _pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStreamRead == NULL)" );
267 buffer = _pico_alloc( streamLength + 1 );
269 bufSize = (int)inputStreamRead( inputStream, buffer, streamLength );
270 buffer[bufSize] = '\0';
272 model = PicoModuleLoadModel( module, fileName, buffer, bufSize, frameNum );
275 _pico_free( buffer );
283 /* ----------------------------------------------------------------------------
285 ---------------------------------------------------------------------------- */
289 creates a new pico model
292 picoModel_t *PicoNewModel( void ){
296 model = _pico_alloc( sizeof( picoModel_t ) );
297 if ( model == NULL ) {
302 memset( model,0,sizeof( picoModel_t ) );
305 _pico_zero_bounds( model->mins,model->maxs );
307 /* set initial frame count to 1 -sea */
308 model->numFrames = 1;
310 /* return ptr to new model */
318 frees a model and all associated data
321 void PicoFreeModel( picoModel_t *model ){
326 if ( model == NULL ) {
332 _pico_free( model->name );
335 if ( model->fileName ) {
336 _pico_free( model->fileName );
340 for ( i = 0; i < model->numShaders; i++ )
341 PicoFreeShader( model->shader[ i ] );
342 free( model->shader );
345 for ( i = 0; i < model->numSurfaces; i++ )
346 PicoFreeSurface( model->surface[ i ] );
347 free( model->surface );
357 adjusts a models's memory allocations to handle the requested sizes.
358 will always grow, never shrink
361 int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ){
363 if ( model == NULL ) {
368 /* sea: null surface/shader fix (1s=>0s) */
369 if ( numShaders < 0 ) {
372 if ( numSurfaces < 0 ) {
376 /* additional shaders? */
377 while ( numShaders > model->maxShaders )
379 model->maxShaders += PICO_GROW_SHADERS;
380 if ( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) ) {
385 /* set shader count to higher */
386 if ( numShaders > model->numShaders ) {
387 model->numShaders = numShaders;
390 /* additional surfaces? */
391 while ( numSurfaces > model->maxSurfaces )
393 model->maxSurfaces += PICO_GROW_SURFACES;
394 if ( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) ) {
399 /* set shader count to higher */
400 if ( numSurfaces > model->numSurfaces ) {
401 model->numSurfaces = numSurfaces;
410 /* ----------------------------------------------------------------------------
412 ---------------------------------------------------------------------------- */
416 creates a new pico shader and returns its index. -sea
419 picoShader_t *PicoNewShader( picoModel_t *model ){
420 picoShader_t *shader;
423 /* allocate and clear */
424 shader = _pico_alloc( sizeof( picoShader_t ) );
425 if ( shader == NULL ) {
428 memset( shader, 0, sizeof( picoShader_t ) );
430 /* attach it to the model */
431 if ( model != NULL ) {
433 if ( !PicoAdjustModel( model, model->numShaders + 1, 0 ) ) {
434 _pico_free( shader );
439 model->shader[ model->numShaders - 1 ] = shader;
440 shader->model = model;
443 /* setup default shader colors */
444 _pico_set_color( shader->ambientColor,0,0,0,0 );
445 _pico_set_color( shader->diffuseColor,255,255,255,1 );
446 _pico_set_color( shader->specularColor,0,0,0,0 );
448 /* no need to do this, but i do it anyway */
449 shader->transparency = 0;
450 shader->shininess = 0;
452 /* return the newly created shader */
460 frees a shader and all associated data -sea
463 void PicoFreeShader( picoShader_t *shader ){
465 if ( shader == NULL ) {
470 if ( shader->name ) {
471 _pico_free( shader->name );
473 if ( shader->mapName ) {
474 _pico_free( shader->mapName );
477 /* free the shader */
478 _pico_free( shader );
485 finds a named shader in a model
488 picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ){
490 if ( model == NULL || name == NULL ) { /* sea: null name fix */
495 for ( int i = 0; i < model->numShaders; i++ )
497 /* skip null shaders or shaders with null names */
498 if ( model->shader[ i ] == NULL ||
499 model->shader[ i ]->name == NULL ) {
503 /* compare the shader name with name we're looking for */
504 if ( caseSensitive ) {
505 if ( !strcmp( name, model->shader[ i ]->name ) ) {
506 return model->shader[ i ];
509 else if ( !_pico_stricmp( name, model->shader[ i ]->name ) ) {
510 return model->shader[ i ];
514 /* named shader not found */
520 /* ----------------------------------------------------------------------------
522 ---------------------------------------------------------------------------- */
526 creates a new pico surface
529 picoSurface_t *PicoNewSurface( picoModel_t *model ){
530 picoSurface_t *surface;
531 char surfaceName[64];
533 /* allocate and clear */
534 surface = _pico_alloc( sizeof( *surface ) );
535 if ( surface == NULL ) {
538 memset( surface, 0, sizeof( *surface ) );
540 /* attach it to the model */
541 if ( model != NULL ) {
543 if ( !PicoAdjustModel( model, 0, model->numSurfaces + 1 ) ) {
544 _pico_free( surface );
549 model->surface[ model->numSurfaces - 1 ] = surface;
550 surface->model = model;
552 /* set default name */
553 sprintf( surfaceName, "Unnamed_%d", model->numSurfaces );
554 PicoSetSurfaceName( surface, surfaceName );
565 frees a surface and all associated data
567 void PicoFreeSurface( picoSurface_t *surface ){
572 if ( surface == NULL ) {
577 _pico_free( surface->xyz );
578 _pico_free( surface->normal );
579 _pico_free( surface->smoothingGroup );
580 _pico_free( surface->index );
581 _pico_free( surface->faceNormal );
583 if ( surface->name ) {
584 _pico_free( surface->name );
588 for ( i = 0; i < surface->numSTArrays; i++ )
589 _pico_free( surface->st[ i ] );
591 for ( i = 0; i < surface->numColorArrays; i++ )
592 _pico_free( surface->color[ i ] );
593 free( surface->color );
595 /* free the surface */
596 _pico_free( surface );
603 adjusts a surface's memory allocations to handle the requested sizes.
604 will always grow, never shrink
607 int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ){
612 if ( surface == NULL ) {
617 if ( numVertexes < 1 ) {
620 if ( numSTArrays < 1 ) {
623 if ( numColorArrays < 1 ) {
626 if ( numIndexes < 1 ) {
630 /* additional vertexes? */
631 while ( numVertexes > surface->maxVertexes ) /* fix */
633 surface->maxVertexes += PICO_GROW_VERTEXES;
634 if ( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) ) {
637 if ( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) ) {
640 if ( !_pico_realloc( (void *) &surface->smoothingGroup, surface->numVertexes * sizeof( *surface->smoothingGroup ), surface->maxVertexes * sizeof( *surface->smoothingGroup ) ) ) {
643 for ( i = 0; i < surface->numSTArrays; i++ )
644 if ( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) ) {
647 for ( i = 0; i < surface->numColorArrays; i++ )
648 if ( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) ) {
653 /* set vertex count to higher */
654 if ( numVertexes > surface->numVertexes ) {
655 surface->numVertexes = numVertexes;
658 /* additional st arrays? */
659 while ( numSTArrays > surface->maxSTArrays ) /* fix */
661 surface->maxSTArrays += PICO_GROW_ARRAYS;
662 if ( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) ) {
665 while ( surface->numSTArrays < numSTArrays )
667 surface->st[ surface->numSTArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
668 memset( surface->st[ surface->numSTArrays ], 0, surface->maxVertexes * sizeof( *surface->st[ 0 ] ) );
669 surface->numSTArrays++;
673 /* additional color arrays? */
674 while ( numColorArrays > surface->maxColorArrays ) /* fix */
676 surface->maxColorArrays += PICO_GROW_ARRAYS;
677 if ( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) ) {
680 while ( surface->numColorArrays < numColorArrays )
682 surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
683 memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
684 surface->numColorArrays++;
688 /* additional indexes? */
689 while ( numIndexes > surface->maxIndexes ) /* fix */
691 surface->maxIndexes += PICO_GROW_INDEXES;
692 if ( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) ) {
697 /* set index count to higher */
698 if ( numIndexes > surface->numIndexes ) {
699 surface->numIndexes = numIndexes;
702 /* additional face normals? */
703 while ( numFaceNormals > surface->maxFaceNormals ) /* fix */
705 surface->maxFaceNormals += PICO_GROW_FACES;
706 if ( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) ) {
711 /* set face normal count to higher */
712 if ( numFaceNormals > surface->numFaceNormals ) {
713 surface->numFaceNormals = numFaceNormals;
722 * Finds first matching named surface in a model.
724 picoSurface_t *PicoFindSurface(
725 picoModel_t *model, char *name, int caseSensitive ){
729 if ( model == NULL || name == NULL ) {
734 for ( i = 0; i < model->numSurfaces; i++ )
736 /* skip null surfaces or surfaces with null names */
737 if ( model->surface[ i ] == NULL ||
738 model->surface[ i ]->name == NULL ) {
742 /* compare the surface name with name we're looking for */
743 if ( caseSensitive ) {
744 if ( !strcmp( name,model->surface[ i ]->name ) ) {
745 return model->surface[ i ];
749 if ( !_pico_stricmp( name,model->surface[ i ]->name ) ) {
750 return model->surface[ i ];
754 /* named surface not found */
760 /*----------------------------------------------------------------------------
761 PicoSet*() Setter Functions
762 ----------------------------------------------------------------------------*/
764 void PicoSetModelName( picoModel_t *model, const char *name ){
765 if ( model == NULL || name == NULL ) {
768 if ( model->name != NULL ) {
769 _pico_free( model->name );
772 model->name = _pico_clone_alloc( name );
777 void PicoSetModelFileName( picoModel_t *model, const char *fileName ){
778 if ( model == NULL || fileName == NULL ) {
781 if ( model->fileName != NULL ) {
782 _pico_free( model->fileName );
785 model->fileName = _pico_clone_alloc( fileName );
790 void PicoSetModelFrameNum( picoModel_t *model, int frameNum ){
791 if ( model == NULL ) {
794 model->frameNum = frameNum;
799 void PicoSetModelNumFrames( picoModel_t *model, int numFrames ){
800 if ( model == NULL ) {
803 model->numFrames = numFrames;
808 void PicoSetModelData( picoModel_t *model, void *data ){
809 if ( model == NULL ) {
817 void PicoSetShaderName( picoShader_t *shader, char *name ){
818 if ( shader == NULL || name == NULL ) {
821 if ( shader->name != NULL ) {
822 _pico_free( shader->name );
825 shader->name = _pico_clone_alloc( name );
830 void PicoSetShaderMapName( picoShader_t *shader, char *mapName ){
831 if ( shader == NULL || mapName == NULL ) {
834 if ( shader->mapName != NULL ) {
835 _pico_free( shader->mapName );
838 shader->mapName = _pico_clone_alloc( mapName );
843 void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ){
844 if ( shader == NULL || color == NULL ) {
847 shader->ambientColor[ 0 ] = color[ 0 ];
848 shader->ambientColor[ 1 ] = color[ 1 ];
849 shader->ambientColor[ 2 ] = color[ 2 ];
850 shader->ambientColor[ 3 ] = color[ 3 ];
855 void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ){
856 if ( shader == NULL || color == NULL ) {
859 shader->diffuseColor[ 0 ] = color[ 0 ];
860 shader->diffuseColor[ 1 ] = color[ 1 ];
861 shader->diffuseColor[ 2 ] = color[ 2 ];
862 shader->diffuseColor[ 3 ] = color[ 3 ];
867 void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ){
868 if ( shader == NULL || color == NULL ) {
871 shader->specularColor[ 0 ] = color[ 0 ];
872 shader->specularColor[ 1 ] = color[ 1 ];
873 shader->specularColor[ 2 ] = color[ 2 ];
874 shader->specularColor[ 3 ] = color[ 3 ];
879 void PicoSetShaderTransparency( picoShader_t *shader, float value ){
880 if ( shader == NULL ) {
883 shader->transparency = value;
885 /* cap to 0..1 range */
886 if ( shader->transparency < 0.0 ) {
887 shader->transparency = 0.0;
889 if ( shader->transparency > 1.0 ) {
890 shader->transparency = 1.0;
896 void PicoSetShaderShininess( picoShader_t *shader, float value ){
897 if ( shader == NULL ) {
900 shader->shininess = value;
902 /* cap to 0..127 range */
903 if ( shader->shininess < 0.0 ) {
904 shader->shininess = 0.0;
906 if ( shader->shininess > 127.0 ) {
907 shader->shininess = 127.0;
913 void PicoSetSurfaceData( picoSurface_t *surface, void *data ){
914 if ( surface == NULL ) {
917 surface->data = data;
922 void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ){
923 if ( surface == NULL ) {
926 surface->type = type;
931 void PicoSetSurfaceName( picoSurface_t *surface, const char *name ){
932 if ( surface == NULL || name == NULL ) {
935 if ( surface->name != NULL ) {
936 _pico_free( surface->name );
939 surface->name = _pico_clone_alloc( name );
944 void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ){
945 if ( surface == NULL ) {
948 surface->shader = shader;
953 void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ){
954 if ( surface == NULL || num < 0 || xyz == NULL ) {
957 if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
960 _pico_copy_vec( xyz, surface->xyz[ num ] );
961 if ( surface->model != NULL ) {
962 _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs );
968 void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ){
969 if ( surface == NULL || num < 0 || normal == NULL ) {
972 if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
975 _pico_copy_vec( normal, surface->normal[ num ] );
980 void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ){
981 if ( surface == NULL || num < 0 || st == NULL ) {
984 if ( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) ) {
987 surface->st[ array ][ num ][ 0 ] = st[ 0 ];
988 surface->st[ array ][ num ][ 1 ] = st[ 1 ];
993 void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, const picoColor_t color ){
994 if ( surface == NULL || num < 0 || color == NULL ) {
997 if ( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) ) {
1000 surface->color[ array ][ num ][ 0 ] = color[ 0 ];
1001 surface->color[ array ][ num ][ 1 ] = color[ 1 ];
1002 surface->color[ array ][ num ][ 2 ] = color[ 2 ];
1003 surface->color[ array ][ num ][ 3 ] = color[ 3 ];
1008 void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ){
1009 if ( surface == NULL || num < 0 ) {
1012 if ( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) ) {
1015 surface->index[ num ] = index;
1020 void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ){
1021 if ( num < 0 || index == NULL || count < 1 ) {
1024 if ( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) ) {
1027 memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) );
1032 void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ){
1033 if ( surface == NULL || num < 0 || normal == NULL ) {
1036 if ( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) ) {
1039 _pico_copy_vec( normal, surface->faceNormal[ num ] );
1043 void PicoSetSurfaceSmoothingGroup( picoSurface_t *surface, int num, picoIndex_t smoothingGroup ){
1047 if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
1050 surface->smoothingGroup[ num ] = smoothingGroup;
1054 void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ){
1055 if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
1058 surface->special[ num ] = special;
1063 /*----------------------------------------------------------------------------
1064 PicoGet*() Getter Functions
1065 ----------------------------------------------------------------------------*/
1067 char *PicoGetModelName( picoModel_t *model ){
1068 if ( model == NULL ) {
1071 if ( model->name == NULL ) {
1079 char *PicoGetModelFileName( picoModel_t *model ){
1080 if ( model == NULL ) {
1083 if ( model->fileName == NULL ) {
1086 return model->fileName;
1091 int PicoGetModelFrameNum( picoModel_t *model ){
1092 if ( model == NULL ) {
1095 return model->frameNum;
1100 int PicoGetModelNumFrames( picoModel_t *model ){
1101 if ( model == NULL ) {
1104 return model->numFrames;
1109 void *PicoGetModelData( picoModel_t *model ){
1110 if ( model == NULL ) {
1118 int PicoGetModelNumShaders( picoModel_t *model ){
1119 if ( model == NULL ) {
1122 return model->numShaders;
1127 picoShader_t *PicoGetModelShader( picoModel_t *model, int num ){
1128 /* a few sanity checks */
1129 if ( model == NULL ) {
1132 if ( model->shader == NULL ) {
1135 if ( num < 0 || num >= model->numShaders ) {
1139 /* return the shader */
1140 return model->shader[ num ];
1145 int PicoGetModelNumSurfaces( picoModel_t *model ){
1146 if ( model == NULL ) {
1149 return model->numSurfaces;
1154 picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ){
1155 /* a few sanity checks */
1156 if ( model == NULL ) {
1159 if ( model->surface == NULL ) {
1162 if ( num < 0 || num >= model->numSurfaces ) {
1166 /* return the surface */
1167 return model->surface[ num ];
1172 int PicoGetModelTotalVertexes( picoModel_t *model ){
1176 if ( model == NULL ) {
1179 if ( model->surface == NULL ) {
1184 for ( i = 0; i < model->numSurfaces; i++ )
1185 count += PicoGetSurfaceNumVertexes( model->surface[ i ] );
1192 int PicoGetModelTotalIndexes( picoModel_t *model ){
1196 if ( model == NULL ) {
1199 if ( model->surface == NULL ) {
1204 for ( i = 0; i < model->numSurfaces; i++ )
1205 count += PicoGetSurfaceNumIndexes( model->surface[ i ] );
1212 char *PicoGetShaderName( picoShader_t *shader ){
1213 if ( shader == NULL ) {
1216 if ( shader->name == NULL ) {
1219 return shader->name;
1224 char *PicoGetShaderMapName( picoShader_t *shader ){
1225 if ( shader == NULL ) {
1228 if ( shader->mapName == NULL ) {
1231 return shader->mapName;
1236 picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ){
1237 if ( shader == NULL ) {
1240 return shader->ambientColor;
1245 picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ){
1246 if ( shader == NULL ) {
1249 return shader->diffuseColor;
1254 picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ){
1255 if ( shader == NULL ) {
1258 return shader->specularColor;
1263 float PicoGetShaderTransparency( picoShader_t *shader ){
1264 if ( shader == NULL ) {
1267 return shader->transparency;
1272 float PicoGetShaderShininess( picoShader_t *shader ){
1273 if ( shader == NULL ) {
1276 return shader->shininess;
1281 void *PicoGetSurfaceData( picoSurface_t *surface ){
1282 if ( surface == NULL ) {
1285 return surface->data;
1290 picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ){
1291 if ( surface == NULL ) {
1294 return surface->type;
1299 char *PicoGetSurfaceName( picoSurface_t *surface ){
1300 if ( surface == NULL ) {
1303 if ( surface->name == NULL ) {
1306 return surface->name;
1311 picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ){
1312 if ( surface == NULL ) {
1315 return surface->shader;
1320 int PicoGetSurfaceNumVertexes( picoSurface_t *surface ){
1321 if ( surface == NULL ) {
1324 return surface->numVertexes;
1329 picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ){
1330 if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
1333 return surface->xyz[ num ];
1338 picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ){
1339 if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
1342 return surface->normal[ num ];
1347 picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ){
1348 if ( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes ) {
1351 return surface->st[ array ][ num ];
1356 picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ){
1357 if ( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes ) {
1360 return surface->color[ array ][ num ];
1365 int PicoGetSurfaceNumIndexes( picoSurface_t *surface ){
1366 if ( surface == NULL ) {
1369 return surface->numIndexes;
1374 picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ){
1375 if ( surface == NULL || num < 0 || num > surface->numIndexes ) {
1378 return surface->index[ num ];
1383 picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ){
1384 if ( surface == NULL || num < 0 || num > surface->numIndexes ) {
1387 return &surface->index[ num ];
1391 picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ){
1392 if ( surface == NULL || num < 0 || num > surface->numFaceNormals ) {
1395 return surface->faceNormal[ num ];
1398 picoIndex_t PicoGetSurfaceSmoothingGroup( picoSurface_t *surface, int num ){
1399 if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
1402 return surface->smoothingGroup[ num ];
1406 int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ){
1407 if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
1410 return surface->special[ num ];
1415 /* ----------------------------------------------------------------------------
1416 hashtable related functions
1417 ---------------------------------------------------------------------------- */
1419 /* hashtable code for faster vertex lookups */
1420 //#define HASHTABLE_SIZE 32768 // 2048 /* power of 2, use & */
1421 const int HASHTABLE_SIZE = 7919; // 32749 // 2039 /* prime, use % */
1423 int PicoGetHashTableSize( void ){
1424 return HASHTABLE_SIZE;
1427 #define HASH_USE_EPSILON
1429 #ifdef HASH_USE_EPSILON
1430 #define HASH_XYZ_EPSILON 0.01f
1431 #define HASH_XYZ_EPSILONSPACE_MULTIPLIER 1.f / HASH_XYZ_EPSILON
1432 #define HASH_ST_EPSILON 0.0001f
1433 #define HASH_NORMAL_EPSILON 0.02f
1436 unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ){
1437 unsigned int hash = 0;
1439 #ifndef HASH_USE_EPSILON
1440 hash += ~( *( (unsigned int*) &xyz[ 0 ] ) << 15 );
1441 hash ^= ( *( (unsigned int*) &xyz[ 0 ] ) >> 10 );
1442 hash += ( *( (unsigned int*) &xyz[ 1 ] ) << 3 );
1443 hash ^= ( *( (unsigned int*) &xyz[ 1 ] ) >> 6 );
1444 hash += ~( *( (unsigned int*) &xyz[ 2 ] ) << 11 );
1445 hash ^= ( *( (unsigned int*) &xyz[ 2 ] ) >> 16 );
1447 picoVec3_t xyz_epsilonspace;
1449 _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace );
1450 xyz_epsilonspace[ 0 ] = (float)floor( xyz_epsilonspace[ 0 ] );
1451 xyz_epsilonspace[ 1 ] = (float)floor( xyz_epsilonspace[ 1 ] );
1452 xyz_epsilonspace[ 2 ] = (float)floor( xyz_epsilonspace[ 2 ] );
1454 hash += ~( *( (unsigned int*) &xyz_epsilonspace[ 0 ] ) << 15 );
1455 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 0 ] ) >> 10 );
1456 hash += ( *( (unsigned int*) &xyz_epsilonspace[ 1 ] ) << 3 );
1457 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 1 ] ) >> 6 );
1458 hash += ~( *( (unsigned int*) &xyz_epsilonspace[ 2 ] ) << 11 );
1459 hash ^= ( *( (unsigned int*) &xyz_epsilonspace[ 2 ] ) >> 16 );
1462 //hash = hash & (HASHTABLE_SIZE-1);
1463 hash = hash % ( HASHTABLE_SIZE );
1467 picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ){
1468 picoVertexCombinationHash_t **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof( picoVertexCombinationHash_t* ) );
1470 memset( hashTable, 0, HASHTABLE_SIZE * sizeof( picoVertexCombinationHash_t* ) );
1475 void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ){
1477 picoVertexCombinationHash_t *vertexCombinationHash;
1478 picoVertexCombinationHash_t *nextVertexCombinationHash;
1481 if ( hashTable == NULL ) {
1485 for ( i = 0; i < HASHTABLE_SIZE; i++ )
1487 if ( hashTable[ i ] ) {
1488 nextVertexCombinationHash = NULL;
1490 for ( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash )
1492 nextVertexCombinationHash = vertexCombinationHash->next;
1493 if ( vertexCombinationHash->data != NULL ) {
1494 _pico_free( vertexCombinationHash->data );
1496 _pico_free( vertexCombinationHash );
1501 _pico_free( hashTable );
1504 picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ){
1506 picoVertexCombinationHash_t *vertexCombinationHash;
1509 if ( hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) {
1513 hash = PicoVertexCoordGenerateHash( xyz );
1515 for ( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next )
1517 #ifndef HASH_USE_EPSILON
1519 if ( ( vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ] ) ) {
1524 if ( ( vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ] ) ) {
1529 if ( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] ) {
1534 if ( ( fabs( xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ] ) ) > HASH_XYZ_EPSILON ||
1535 ( fabs( xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ] ) ) > HASH_XYZ_EPSILON ||
1536 ( fabs( xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ] ) ) > HASH_XYZ_EPSILON ) {
1541 if ( ( fabs( normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ] ) ) > HASH_NORMAL_EPSILON ||
1542 ( fabs( normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ] ) ) > HASH_NORMAL_EPSILON ||
1543 ( fabs( normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ] ) ) > HASH_NORMAL_EPSILON ) {
1548 if ( ( fabs( st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ] ) ) > HASH_ST_EPSILON ||
1549 ( fabs( st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ] ) ) > HASH_ST_EPSILON ) {
1555 if ( *( (int*) vertexCombinationHash->vcd.color ) != *( (int*) color ) ) {
1560 return vertexCombinationHash;
1566 picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ){
1568 picoVertexCombinationHash_t *vertexCombinationHash;
1571 if ( hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) {
1575 vertexCombinationHash = _pico_alloc( sizeof( picoVertexCombinationHash_t ) );
1577 if ( !vertexCombinationHash ) {
1581 hash = PicoVertexCoordGenerateHash( xyz );
1583 _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz );
1584 _pico_copy_vec( normal, vertexCombinationHash->vcd.normal );
1585 _pico_copy_vec2( st, vertexCombinationHash->vcd.st );
1586 _pico_copy_color( color, vertexCombinationHash->vcd.color );
1587 vertexCombinationHash->index = index;
1588 vertexCombinationHash->data = NULL;
1589 vertexCombinationHash->next = hashTable[ hash ];
1590 hashTable[ hash ] = vertexCombinationHash;
1592 return vertexCombinationHash;
1595 /* ----------------------------------------------------------------------------
1596 specialized routines
1597 ---------------------------------------------------------------------------- */
1600 PicoFindSurfaceVertex()
1601 finds a vertex matching the set parameters
1602 fixme: needs non-naive algorithm
1605 int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, const picoColor_t *color, picoIndex_t smoothingGroup ){
1610 if ( surface == NULL || surface->numVertexes <= 0 ) {
1614 /* walk vertex list */
1615 for ( i = 0; i < surface->numVertexes; i++ )
1618 if ( xyz != NULL && ( surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ] ) ) {
1623 if ( normal != NULL && ( surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ] ) ) {
1628 if ( surface->smoothingGroup[ i ] != smoothingGroup ) {
1633 if ( numSTs > 0 && st != NULL ) {
1634 for ( j = 0; j < numSTs; j++ )
1636 if ( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] ) {
1640 if ( j != numSTs ) {
1646 if ( numColors > 0 && color != NULL ) {
1647 for ( j = 0; j < numSTs; j++ )
1649 if ( *( (const int*) surface->color[ j ] ) != *( (const int*) color[ j ] ) ) {
1653 if ( j != numColors ) {
1658 /* vertex matches */
1669 typedef struct _IndexArray IndexArray;
1676 void indexarray_push_back( IndexArray* self, picoIndex_t value ){
1677 *self->last++ = value;
1680 size_t indexarray_size( IndexArray* self ){
1681 return self->last - self->data;
1684 void indexarray_reserve( IndexArray* self, size_t size ){
1685 self->data = self->last = _pico_calloc( size, sizeof( picoIndex_t ) );
1688 void indexarray_clear( IndexArray* self ){
1689 _pico_free( self->data );
1692 typedef struct _BinaryTreeNode BinaryTreeNode;
1693 struct _BinaryTreeNode
1699 typedef struct _BinaryTree BinaryTree;
1702 BinaryTreeNode* data;
1703 BinaryTreeNode* last;
1706 void binarytree_extend( BinaryTree* self ){
1707 self->last->left = 0;
1708 self->last->right = 0;
1712 size_t binarytree_size( BinaryTree* self ){
1713 return self->last - self->data;
1716 void binarytree_reserve( BinaryTree* self, size_t size ){
1717 self->data = self->last = _pico_calloc( size, sizeof( BinaryTreeNode ) );
1720 void binarytree_clear( BinaryTree* self ){
1721 _pico_free( self->data );
1724 typedef int ( *LessFunc )( void*, picoIndex_t, picoIndex_t );
1726 typedef struct _UniqueIndices UniqueIndices;
1727 struct _UniqueIndices
1735 size_t UniqueIndices_size( UniqueIndices* self ){
1736 return binarytree_size( &self->tree );
1739 void UniqueIndices_reserve( UniqueIndices* self, size_t size ){
1740 binarytree_reserve( &self->tree, size );
1741 indexarray_reserve( &self->indices, size );
1744 void UniqueIndices_init( UniqueIndices* self, LessFunc lessFunc, void* lessData ){
1745 self->lessFunc = lessFunc;
1746 self->lessData = lessData;
1749 void UniqueIndices_destroy( UniqueIndices* self ){
1750 binarytree_clear( &self->tree );
1751 indexarray_clear( &self->indices );
1755 picoIndex_t UniqueIndices_find_or_insert( UniqueIndices* self, picoIndex_t value ){
1756 picoIndex_t index = 0;
1760 if ( self->lessFunc( self->lessData, value, self->indices.data[index] ) ) {
1761 BinaryTreeNode* node = self->tree.data + index;
1762 if ( node->left != 0 ) {
1768 node->left = (picoIndex_t)binarytree_size( &self->tree );
1769 binarytree_extend( &self->tree );
1770 indexarray_push_back( &self->indices, value );
1774 if ( self->lessFunc( self->lessData, self->indices.data[index], value ) ) {
1775 BinaryTreeNode* node = self->tree.data + index;
1776 if ( node->right != 0 ) {
1777 index = node->right;
1782 node->right = (picoIndex_t)binarytree_size( &self->tree );
1783 binarytree_extend( &self->tree );
1784 indexarray_push_back( &self->indices, value );
1793 picoIndex_t UniqueIndices_insert( UniqueIndices* self, picoIndex_t value ){
1794 if ( self->tree.data == self->tree.last ) {
1795 binarytree_extend( &self->tree );
1796 indexarray_push_back( &self->indices, value );
1801 return UniqueIndices_find_or_insert( self, value );
1805 typedef struct picoSmoothVertices_s picoSmoothVertices_t;
1806 struct picoSmoothVertices_s
1809 picoIndex_t* smoothingGroups;
1812 int lessSmoothVertex( void* data, picoIndex_t first, picoIndex_t second ){
1813 picoSmoothVertices_t* smoothVertices = data;
1815 if ( smoothVertices->xyz[first][0] != smoothVertices->xyz[second][0] ) {
1816 return smoothVertices->xyz[first][0] < smoothVertices->xyz[second][0];
1818 if ( smoothVertices->xyz[first][1] != smoothVertices->xyz[second][1] ) {
1819 return smoothVertices->xyz[first][1] < smoothVertices->xyz[second][1];
1821 if ( smoothVertices->xyz[first][2] != smoothVertices->xyz[second][2] ) {
1822 return smoothVertices->xyz[first][2] < smoothVertices->xyz[second][2];
1824 if ( smoothVertices->smoothingGroups[first] != smoothVertices->smoothingGroups[second] ) {
1825 return smoothVertices->smoothingGroups[first] < smoothVertices->smoothingGroups[second];
1830 void _pico_vertices_combine_shared_normals( picoVec3_t* xyz, picoIndex_t* smoothingGroups, picoVec3_t* normals, picoIndex_t numVertices ){
1831 UniqueIndices vertices;
1833 picoSmoothVertices_t smoothVertices = { xyz, smoothingGroups };
1834 UniqueIndices_init( &vertices, lessSmoothVertex, &smoothVertices );
1835 UniqueIndices_reserve( &vertices, numVertices );
1836 indexarray_reserve( &indices, numVertices );
1841 for (; i < numVertices; ++i )
1843 size_t size = UniqueIndices_size( &vertices );
1844 picoIndex_t index = UniqueIndices_insert( &vertices, i );
1845 if ( (size_t)index != size ) {
1846 float* normal = normals[vertices.indices.data[index]];
1847 _pico_add_vec( normal, normals[i], normal );
1849 indexarray_push_back( &indices, index );
1854 picoIndex_t maxIndex = 0;
1855 picoIndex_t* i = indices.data;
1856 for (; i != indices.last; ++i )
1858 if ( *i <= maxIndex ) {
1859 _pico_copy_vec( normals[vertices.indices.data[*i]], normals[i - indices.data] );
1868 UniqueIndices_destroy( &vertices );
1869 indexarray_clear( &indices );
1872 typedef picoVec3_t* picoNormalIter_t;
1873 typedef picoIndex_t* picoIndexIter_t;
1875 #define THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL 1
1877 void _pico_triangles_generate_weighted_normals( picoIndexIter_t first, picoIndexIter_t end, picoVec3_t* xyz, picoVec3_t* normals ){
1878 for (; first != end; first += 3 )
1880 #if ( THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL )
1881 picoVec3_t weightedNormal;
1883 float* a = xyz[*( first + 0 )];
1884 float* b = xyz[*( first + 1 )];
1885 float* c = xyz[*( first + 2 )];
1887 _pico_subtract_vec( b, a, ba );
1888 _pico_subtract_vec( c, a, ca );
1889 _pico_cross_vec( ca, ba, weightedNormal );
1896 float* normal = normals[*( first + j )];
1897 #if ( !THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL )
1898 picoVec3_t weightedNormal;
1900 float* a = xyz[*( first + ( ( j + 0 ) % 3 ) )];
1901 float* b = xyz[*( first + ( ( j + 1 ) % 3 ) )];
1902 float* c = xyz[*( first + ( ( j + 2 ) % 3 ) )];
1904 _pico_subtract_vec( b, a, ba );
1905 _pico_subtract_vec( c, a, ca );
1906 _pico_cross_vec( ca, ba, weightedNormal );
1909 _pico_add_vec( weightedNormal, normal, normal );
1915 void _pico_normals_zero( picoNormalIter_t first, picoNormalIter_t last ){
1916 for (; first != last; ++first )
1918 _pico_zero_vec( *first );
1922 void _pico_normals_normalize( picoNormalIter_t first, picoNormalIter_t last ){
1923 for (; first != last; ++first )
1925 _pico_normalize_vec( *first );
1929 double _pico_length_vec( picoVec3_t vec ){
1930 return sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] );
1933 #define NORMAL_UNIT_LENGTH_EPSILON 0.01
1934 #define FLOAT_EQUAL_EPSILON( f, other, epsilon ) ( fabs( f - other ) < epsilon )
1936 int _pico_normal_is_unit_length( picoVec3_t normal ){
1937 return FLOAT_EQUAL_EPSILON( _pico_length_vec( normal ), 1.0, NORMAL_UNIT_LENGTH_EPSILON );
1940 int _pico_normal_within_tolerance( picoVec3_t normal, picoVec3_t other ){
1941 return _pico_dot_vec( normal, other ) > 0.0f;
1945 void _pico_normals_assign_generated_normals( picoNormalIter_t first, picoNormalIter_t last, picoNormalIter_t generated ){
1946 for (; first != last; ++first, ++generated )
1948 if ( !_pico_normal_is_unit_length( *first ) || !_pico_normal_within_tolerance( *first, *generated ) ) {
1949 _pico_copy_vec( *generated, *first );
1954 void PicoFixSurfaceNormals( picoSurface_t* surface ){
1955 picoVec3_t* normals = (picoVec3_t*)_pico_calloc( surface->numVertexes, sizeof( picoVec3_t ) );
1957 _pico_normals_zero( normals, normals + surface->numVertexes );
1959 _pico_triangles_generate_weighted_normals( surface->index, surface->index + surface->numIndexes, surface->xyz, normals );
1960 _pico_vertices_combine_shared_normals( surface->xyz, surface->smoothingGroup, normals, surface->numVertexes );
1962 _pico_normals_normalize( normals, normals + surface->numVertexes );
1964 _pico_normals_assign_generated_normals( surface->normal, surface->normal + surface->numVertexes, normals );
1966 _pico_free( normals );
1971 PicoRemapModel() - sea
1972 remaps model material/etc. information using the remappings
1973 contained in the given 'remapFile' (full path to the ascii file to open)
1974 returns 1 on success or 0 on error
1977 #define _prm_error_return \
1979 _pico_free_parser( p ); \
1980 _pico_free_file( remapBuffer ); \
1984 int PicoRemapModel( picoModel_t *model, char *remapFile ){
1986 picoByte_t *remapBuffer;
1991 if ( model == NULL || remapFile == NULL ) {
1995 /* load remap file contents */
1996 _pico_load_file( remapFile,&remapBuffer,&remapBufSize );
1999 if ( remapBufSize == 0 ) {
2000 return 1; /* file is empty: no error */
2002 if ( remapBufSize < 0 ) {
2003 return 0; /* load failed: error */
2006 /* create a new pico parser */
2007 p = _pico_new_parser( remapBuffer, remapBufSize );
2009 /* ram is really cheap nowadays... */
2016 /* get next token in remap file */
2017 if ( !_pico_parse( p,1 ) ) {
2021 /* skip over c++ style comment lines */
2022 if ( !_pico_stricmp( p->token,"//" ) ) {
2023 _pico_parse_skip_rest( p );
2027 /* block for quick material shader name remapping */
2028 /* materials { "m" (=>|->|=) "s" } */
2029 if ( !_pico_stricmp( p->token, "materials" ) ) {
2033 if ( !_pico_parse_check( p,1,"{" ) ) {
2037 /* process assignments */
2040 picoShader_t *shader;
2044 /* get material name */
2045 if ( _pico_parse( p,1 ) == NULL ) {
2048 if ( !strlen( p->token ) ) {
2051 materialName = _pico_clone_alloc( p->token );
2052 if ( materialName == NULL ) {
2057 if ( p->token[0] == '{' ) {
2060 if ( p->token[0] == '}' ) {
2067 /* get next token (assignment token or shader name) */
2068 if ( !_pico_parse( p,0 ) ) {
2069 _pico_free( materialName );
2072 /* skip assignment token (if present) */
2073 if ( !strcmp( p->token,"=>" ) ||
2074 !strcmp( p->token,"->" ) ||
2075 !strcmp( p->token,"=" ) ) {
2076 /* simply grab the next token */
2077 if ( !_pico_parse( p,0 ) ) {
2078 _pico_free( materialName );
2082 /* try to find material by name */
2083 shader = PicoFindShader( model,materialName,0 );
2085 /* we've found a material matching the name */
2086 if ( shader != NULL ) {
2087 PicoSetShaderName( shader,p->token );
2089 /* free memory used by material name */
2090 _pico_free( materialName );
2093 _pico_parse_skip_rest( p );
2096 /* block for detailed single material remappings */
2097 /* materials[ "m" ] { key data... } */
2098 else if ( !_pico_stricmp( p->token,"materials[" ) ) {
2099 picoShader_t *shader;
2100 char *tempMaterialName;
2103 /* get material name */
2104 if ( !_pico_parse( p,0 ) ) {
2108 /* temporary copy of material name */
2109 tempMaterialName = _pico_clone_alloc( p->token );
2110 if ( tempMaterialName == NULL ) {
2114 /* check square closing bracket */
2115 if ( !_pico_parse_check( p,0,"]" ) ) {
2119 /* try to find material by name */
2120 shader = PicoFindShader( model,tempMaterialName,0 );
2122 /* free memory used by temporary material name */
2123 _pico_free( tempMaterialName );
2125 /* we haven't found a material matching the name */
2126 /* so we simply skip the braced section now and */
2127 /* continue parsing with the next main token */
2128 if ( shader == NULL ) {
2129 _pico_parse_skip_braced( p );
2132 /* check opening bracket */
2133 if ( !_pico_parse_check( p,1,"{" ) ) {
2137 /* process material info keys */
2141 if ( _pico_parse( p,1 ) == NULL ) {
2144 if ( !strlen( p->token ) ) {
2149 if ( p->token[0] == '{' ) {
2152 if ( p->token[0] == '}' ) {
2159 /* remap shader name */
2160 if ( !_pico_stricmp( p->token,"shader" ) ) {
2161 if ( !_pico_parse( p,0 ) ) {
2164 PicoSetShaderName( shader,p->token );
2166 /* remap shader map name */
2167 else if ( !_pico_stricmp( p->token,"mapname" ) ) {
2168 if ( !_pico_parse( p,0 ) ) {
2171 PicoSetShaderMapName( shader,p->token );
2173 /* remap shader's ambient color */
2174 else if ( !_pico_stricmp( p->token,"ambient" ) ) {
2178 /* get vector from parser */
2179 if ( !_pico_parse_vec( p,v ) ) {
2183 /* store as color */
2184 color[ 0 ] = (picoByte_t)v[ 0 ];
2185 color[ 1 ] = (picoByte_t)v[ 1 ];
2186 color[ 2 ] = (picoByte_t)v[ 2 ];
2188 /* set new ambient color */
2189 PicoSetShaderAmbientColor( shader,color );
2191 /* remap shader's diffuse color */
2192 else if ( !_pico_stricmp( p->token,"diffuse" ) ) {
2196 /* get vector from parser */
2197 if ( !_pico_parse_vec( p,v ) ) {
2201 /* store as color */
2202 color[ 0 ] = (picoByte_t)v[ 0 ];
2203 color[ 1 ] = (picoByte_t)v[ 1 ];
2204 color[ 2 ] = (picoByte_t)v[ 2 ];
2206 /* set new ambient color */
2207 PicoSetShaderDiffuseColor( shader,color );
2209 /* remap shader's specular color */
2210 else if ( !_pico_stricmp( p->token,"specular" ) ) {
2214 /* get vector from parser */
2215 if ( !_pico_parse_vec( p,v ) ) {
2219 /* store as color */
2220 color[ 0 ] = (picoByte_t)v[ 0 ];
2221 color[ 1 ] = (picoByte_t)v[ 1 ];
2222 color[ 2 ] = (picoByte_t)v[ 2 ];
2224 /* set new ambient color */
2225 PicoSetShaderSpecularColor( shader,color );
2228 _pico_parse_skip_rest( p );
2231 /* end 'materials[' */
2234 /* free both parser and file buffer */
2235 _pico_free_parser( p );
2236 _pico_free_file( remapBuffer );
2238 /* return with success */
2244 PicoAddTriangleToModel() - jhefty
2245 A nice way to add individual triangles to the model.
2246 Chooses an appropriate surface based on the shader, or adds a new surface if necessary
2249 void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals,
2250 int numSTs, picoVec2_t **st, int numColors, const picoColor_t **colors,
2251 picoShader_t* shader, const char *name, picoIndex_t* smoothingGroup ){
2254 picoSurface_t* workSurface = NULL;
2256 /* see if a surface already has the shader */
2257 for ( i = 0 ; i < model->numSurfaces ; i++ )
2259 workSurface = model->surface[i];
2260 if ( !name || !strcmp( workSurface->name, name ) ) {
2261 if ( workSurface->shader == shader ) {
2267 /* no surface uses this shader yet, so create a new surface */
2268 if ( !workSurface || i >= model->numSurfaces ) {
2269 /* create a new surface in the model for the unique shader */
2270 workSurface = PicoNewSurface( model );
2271 if ( !workSurface ) {
2272 _pico_printf( PICO_ERROR, "Could not allocate a new surface!\n" );
2276 /* do surface setup */
2277 PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
2278 PicoSetSurfaceName( workSurface, name ? name : shader->name );
2279 PicoSetSurfaceShader( workSurface, shader );
2282 /* add the triangle data to the surface */
2283 for ( i = 0 ; i < 3 ; i++ )
2285 /* get the next free spot in the index array */
2286 int newVertIndex = PicoGetSurfaceNumIndexes( workSurface );
2288 /* get the index of the vertex that we're going to store at newVertIndex */
2289 vertDataIndex = PicoFindSurfaceVertexNum( workSurface, *xyz[i], *normals[i], numSTs, st[i], numColors, colors[i], smoothingGroup[i] );
2291 /* the vertex wasn't found, so create a new vertex in the pool from the data we have */
2292 if ( vertDataIndex == -1 ) {
2293 /* find the next spot for a new vertex */
2294 vertDataIndex = PicoGetSurfaceNumVertexes( workSurface );
2296 /* assign the data to it */
2297 PicoSetSurfaceXYZ( workSurface,vertDataIndex, *xyz[i] );
2298 PicoSetSurfaceNormal( workSurface, vertDataIndex, *normals[i] );
2300 /* make sure to copy over all available ST's and colors for the vertex */
2301 for ( j = 0 ; j < numColors ; j++ )
2303 PicoSetSurfaceColor( workSurface, j, vertDataIndex, colors[i][j] );
2305 for ( j = 0 ; j < numSTs ; j++ )
2307 PicoSetSurfaceST( workSurface, j, vertDataIndex, st[i][j] );
2310 PicoSetSurfaceSmoothingGroup( workSurface, vertDataIndex, smoothingGroup[i] );
2313 /* add this vertex to the triangle */
2314 PicoSetSurfaceIndex( workSurface, newVertIndex, vertDataIndex );