]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/picomodel.c
240d729b3f2f8a419e6bb8c22bd8c15e07ed0cbd
[xonotic/netradiant.git] / libs / picomodel / picomodel.c
1 /* -----------------------------------------------------------------------------
2
3 PicoModel Library
4
5 Copyright (c) 2002, Randy Reddig & seaw0lf
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
10
11 Redistributions of source code must retain the above copyright notice, this list
12 of conditions and the following disclaimer.
13
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.
17
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.
21
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.
32
33 ----------------------------------------------------------------------------- */
34
35
36
37 /* marker */
38 #define PICOMODEL_C
39
40
41
42 /* dependencies */
43 #include "picointernal.h"
44
45
46
47 /*
48 PicoInit()
49 initializes the picomodel library
50 */
51
52 int PicoInit( void )
53 {
54         /* successfully initialized -sea */
55         return 1;
56 }
57
58
59
60 /*
61 PicoShutdown()
62 shuts the pico model library down
63 */
64
65 void PicoShutdown( void )
66 {
67         /* do something interesting here in the future */
68         return;
69 }
70
71
72
73 /*
74 PicoError()
75 returns last picomodel error code (see PME_* defines)
76 */
77
78 int PicoError( void )
79 {
80         /* todo: do something here */
81         return 0;
82 }
83
84
85
86 /*
87 PicoSetMallocFunc()
88 sets the ptr to the malloc function
89 */
90
91 void PicoSetMallocFunc( void *(*func)( size_t ) )
92 {
93         if( func != NULL )
94                 _pico_ptr_malloc = func;
95 }
96
97
98
99 /*
100 PicoSetFreeFunc()
101 sets the ptr to the free function
102 */
103
104 void PicoSetFreeFunc( void (*func)( void* ) )
105 {
106         if( func != NULL )
107                 _pico_ptr_free = func;
108 }
109
110
111
112 /*
113 PicoSetLoadFileFunc()
114 sets the ptr to the file load function
115 */
116
117 void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) )
118 {
119         if( func != NULL )
120                 _pico_ptr_load_file = func;
121 }
122
123
124
125 /*
126 PicoSetFreeFileFunc()
127 sets the ptr to the free function
128 */
129
130 void PicoSetFreeFileFunc( void (*func)( void* ) )
131 {
132         if( func != NULL )
133                 _pico_ptr_free_file = func;
134 }
135
136
137
138 /*
139 PicoSetPrintFunc()
140 sets the ptr to the print function
141 */
142
143 void PicoSetPrintFunc( void (*func)( int, const char* ) )
144 {
145         if( func != NULL )
146                 _pico_ptr_print = func;
147 }
148
149
150
151 picoModel_t     *PicoModuleLoadModel( const picoModule_t* pm, char* fileName, picoByte_t* buffer, int bufSize, int frameNum )
152 {
153         char                            *modelFileName, *remapFileName;
154
155         /* see whether this module can load the model file or not */
156         if( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK )
157         {
158                 /* use loader provided by module to read the model data */
159                 picoModel_t* model = pm->load( fileName, frameNum, buffer, bufSize );
160                 if( model == NULL )
161                 {
162                         _pico_free_file( buffer );
163                         return NULL;
164                 }
165                 
166                 /* assign pointer to file format module */
167                 model->module = pm;
168                 
169                 /* get model file name */
170                 modelFileName = PicoGetModelFileName( model );
171                 
172                 /* apply model remappings from <model>.remap */
173                 if( strlen( modelFileName ) )
174                 {
175                         /* alloc copy of model file name */
176                         remapFileName = _pico_alloc( strlen( modelFileName ) + 20 );
177                         if( remapFileName != NULL )
178                         {
179                                 /* copy model file name and change extension */
180                                 strcpy( remapFileName, modelFileName );
181                                 _pico_setfext( remapFileName, "remap" );
182
183                                 /* try to remap model; we don't handle the result */
184                                 PicoRemapModel( model, remapFileName );
185
186                                 /* free the remap file name string */
187                                 _pico_free( remapFileName );
188                         }
189                 }
190
191                 return model;
192         }
193
194         return NULL;
195 }
196
197 /*
198 PicoLoadModel()
199 the meat and potatoes function
200 */
201
202 picoModel_t     *PicoLoadModel( char *fileName, int frameNum )
203 {
204         const picoModule_t      **modules, *pm;
205         picoModel_t                     *model;
206         picoByte_t                      *buffer;
207         int                                     bufSize;
208
209         
210         /* init */
211         model = NULL;
212         
213         /* make sure we've got a file name */
214         if( fileName == NULL )
215         {
216                 _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" );
217                 return NULL;
218         }
219         
220         /* load file data (buffer is allocated by host app) */
221         _pico_load_file( fileName, &buffer, &bufSize );
222         if( bufSize < 0 )
223         {
224                 _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName );
225                 return NULL;
226         }
227
228         /* get ptr to list of supported modules */
229         modules = PicoModuleList( NULL );
230         
231         /* run it through the various loader functions and try */
232         /* to find a loader that fits the given file data */
233         for( ; *modules != NULL; modules++ )
234         {
235                 /* get module */
236                 pm = *modules;
237                 
238                 /* sanity check */
239                 if( pm == NULL)
240                         break;
241
242                 /* module must be able to load */
243                 if( pm->canload == NULL || pm->load == NULL )
244                         continue;
245         
246                 model = PicoModuleLoadModel(pm, fileName, buffer, bufSize, frameNum);
247                 if(model != NULL)
248                 {
249                         /* model was loaded, so break out of loop */
250                         break;
251                 }
252         }
253         
254         /* free memory used by file buffer */
255         if( buffer)
256                 _pico_free_file( buffer );
257
258         /* return */
259         return model;
260 }
261
262 picoModel_t     *PicoModuleLoadModelStream( const picoModule_t* module, void* inputStream, PicoInputStreamReadFunc inputStreamRead, size_t streamLength, int frameNum )
263 {
264         picoModel_t                     *model;
265         picoByte_t                      *buffer;
266         int                                     bufSize;
267
268         
269         /* init */
270         model = NULL;
271         
272         if( inputStream == NULL )
273         {
274                 _pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStream == NULL)" );
275                 return NULL;
276         }
277         
278         if( inputStreamRead == NULL )
279         {
280                 _pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStreamRead == NULL)" );
281                 return NULL;
282         }
283         
284         buffer = _pico_alloc(streamLength + 1);
285
286         bufSize = (int)inputStreamRead(inputStream, buffer, streamLength);
287         buffer[bufSize] = '\0';
288
289         {
290                 // dummy filename
291                 char fileName[128];
292                 fileName[0] = '.';
293                 strncpy(fileName + 1, module->defaultExts[0], 126);
294                 fileName[127] = '\0';
295                 model = PicoModuleLoadModel(module, fileName, buffer, bufSize, frameNum);
296         }
297         
298   if(model != 0)
299   {
300           _pico_free(buffer);
301   }
302
303         /* return */
304         return model;
305 }
306
307
308 /* ----------------------------------------------------------------------------
309 models
310 ---------------------------------------------------------------------------- */
311
312 /*
313 PicoNewModel()
314 creates a new pico model
315 */
316
317 picoModel_t *PicoNewModel( void )
318 {
319         picoModel_t     *model;
320         
321         /* allocate */
322         model = _pico_alloc( sizeof(picoModel_t) );
323         if( model == NULL )
324                 return NULL;
325
326         /* clear */
327         memset( model,0,sizeof(picoModel_t) );
328         
329         /* model set up */
330         _pico_zero_bounds( model->mins,model->maxs );
331
332         /* set initial frame count to 1 -sea */
333         model->numFrames = 1;
334
335         /* return ptr to new model */
336         return model;
337 }
338
339
340
341 /*
342 PicoFreeModel()
343 frees a model and all associated data
344 */
345
346 void PicoFreeModel( picoModel_t *model )
347 {
348         int                             i;
349         
350
351         /* sanity check */
352         if( model == NULL )
353                 return;
354         
355         /* free bits */
356         if( model->name )
357                 _pico_free( model->name );
358         
359         if( model->fileName )
360                 _pico_free( model->fileName );
361         
362         /* free shaders */
363         for( i = 0; i < model->numShaders; i++ )
364                 PicoFreeShader( model->shader[ i ] );
365         free( model->shader );
366         
367         /* free surfaces */
368         for( i = 0; i < model->numSurfaces; i++ )
369                 PicoFreeSurface( model->surface[ i ] );
370         free( model->surface );
371         
372         /* free the model */
373         _pico_free( model );
374 }
375
376
377
378 /*
379 PicoAdjustModel()
380 adjusts a models's memory allocations to handle the requested sizes.
381 will always grow, never shrink
382 */
383
384 int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces )
385 {
386         /* dummy check */
387         if( model == NULL )
388                 return 0;
389         
390         /* bare minimums */
391         /* sea: null surface/shader fix (1s=>0s) */
392         if( numShaders < 0 )
393                 numShaders = 0;
394         if( numSurfaces < 0 )
395                 numSurfaces = 0;
396
397         /* additional shaders? */
398         while( numShaders > model->maxShaders )
399         {
400                 model->maxShaders += PICO_GROW_SHADERS;
401                 if( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) )
402                         return 0;
403         }
404         
405         /* set shader count to higher */
406         if( numShaders > model->numShaders )
407                 model->numShaders = numShaders;
408         
409         /* additional surfaces? */
410         while( numSurfaces > model->maxSurfaces )
411         {
412                 model->maxSurfaces += PICO_GROW_SURFACES;
413                 if( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) )
414                         return 0;
415         }
416         
417         /* set shader count to higher */
418         if( numSurfaces > model->numSurfaces )
419                 model->numSurfaces = numSurfaces;
420         
421         /* return ok */
422         return 1;
423 }
424
425
426
427 /* ----------------------------------------------------------------------------
428 shaders
429 ---------------------------------------------------------------------------- */
430
431 /*
432 PicoNewShader()
433 creates a new pico shader and returns its index. -sea
434 */
435
436 picoShader_t *PicoNewShader( picoModel_t *model )
437 {
438         picoShader_t    *shader;
439         
440         
441         /* allocate and clear */
442         shader = _pico_alloc( sizeof(picoShader_t) );
443         if( shader == NULL )
444                 return NULL;
445         memset( shader, 0, sizeof(picoShader_t) );
446         
447         /* attach it to the model */
448         if( model != NULL )
449         {
450                 /* adjust model */
451                 if( !PicoAdjustModel( model, model->numShaders + 1, 0 ) )
452                 {
453                         _pico_free( shader );
454                         return NULL;
455                 }
456                 
457                 /* attach */
458                 model->shader[ model->numShaders - 1 ] = shader;
459                 shader->model = model;
460         }
461         
462         /* setup default shader colors */
463         _pico_set_color( shader->ambientColor,0,0,0,0 );
464         _pico_set_color( shader->diffuseColor,255,255,255,1 );
465         _pico_set_color( shader->specularColor,0,0,0,0 );
466         
467         /* no need to do this, but i do it anyway */
468         shader->transparency = 0;
469         shader->shininess = 0;
470         
471         /* return the newly created shader */
472         return shader;
473 }
474
475
476
477 /*
478 PicoFreeShader()
479 frees a shader and all associated data -sea
480 */
481
482 void PicoFreeShader( picoShader_t *shader )
483 {
484         /* dummy check */
485         if( shader == NULL )
486                 return;
487         
488         /* free bits */
489         if( shader->name )
490                 _pico_free( shader->name );
491         if( shader->mapName )
492                 _pico_free( shader->mapName );
493         
494         /* free the shader */
495         _pico_free( shader );
496 }
497
498
499
500 /*
501 PicoFindShader()
502 finds a named shader in a model
503 */
504
505 picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive )
506 {
507         int             i;
508         
509         
510         /* sanity checks */
511         if( model == NULL || name == NULL )     /* sea: null name fix */
512                 return NULL;
513         
514         /* walk list */
515         for( i = 0; i < model->numShaders; i++ )
516         {
517                 /* skip null shaders or shaders with null names */
518                 if( model->shader[ i ] == NULL ||
519                         model->shader[ i ]->name == NULL )
520                         continue;
521
522                 /* compare the shader name with name we're looking for */
523                 if( caseSensitive )
524                 {
525                         if( !strcmp( name, model->shader[ i ]->name ) )
526                                 return model->shader[ i ];
527                 }
528                 else if( !_pico_stricmp( name, model->shader[ i ]->name ) )
529                                 return model->shader[ i ];
530         }
531         
532         /* named shader not found */
533         return NULL;
534 }
535
536
537
538 /* ----------------------------------------------------------------------------
539 surfaces
540 ---------------------------------------------------------------------------- */
541
542 /*
543 PicoNewSurface()
544 creates a new pico surface
545 */
546
547 picoSurface_t *PicoNewSurface( picoModel_t *model )
548 {
549         picoSurface_t   *surface;
550         char surfaceName[64];
551         
552         /* allocate and clear */
553         surface = _pico_alloc( sizeof( *surface ) );
554         if( surface == NULL )
555                 return NULL;
556         memset( surface, 0, sizeof( *surface ) );
557         
558         /* attach it to the model */
559         if( model != NULL )
560         {
561                 /* adjust model */
562                 if( !PicoAdjustModel( model, 0, model->numSurfaces + 1 ) )
563                 {
564                         _pico_free( surface );
565                         return NULL;
566                 }
567                 
568                 /* attach */
569                 model->surface[ model->numSurfaces - 1 ] = surface;
570                 surface->model = model;
571                 
572                 /* set default name */
573                 sprintf( surfaceName, "Unnamed_%d", model->numSurfaces );
574                 PicoSetSurfaceName( surface, surfaceName );
575         }
576         
577         /* return */
578         return surface;
579 }
580
581
582
583 /*
584 PicoFreeSurface()
585 frees a surface and all associated data
586 */
587 void PicoFreeSurface( picoSurface_t *surface )
588 {
589         int             i;
590         
591         
592         /* dummy check */
593         if( surface == NULL )
594                 return;
595         
596         /* free bits */
597         _pico_free( surface->xyz );
598         _pico_free( surface->normal );
599         _pico_free( surface->smoothingGroup );
600         _pico_free( surface->index );
601         _pico_free( surface->faceNormal );
602
603   if( surface->name )
604     _pico_free( surface->name );
605         
606         /* free arrays */
607         for( i = 0; i < surface->numSTArrays; i++ )
608                 _pico_free( surface->st[ i ] );
609         free( surface->st );
610         for( i = 0; i < surface->numColorArrays; i++ )
611                 _pico_free( surface->color[ i ] );
612         free( surface->color );
613         
614         /* free the surface */
615         _pico_free( surface );
616 }
617
618
619
620 /*
621 PicoAdjustSurface()
622 adjusts a surface's memory allocations to handle the requested sizes.
623 will always grow, never shrink
624 */
625
626 int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals )
627 {
628         int             i;
629         
630         
631         /* dummy check */
632         if( surface == NULL )
633                 return 0;
634         
635         /* bare minimums */
636         if( numVertexes < 1 )
637                 numVertexes = 1;
638         if( numSTArrays < 1 )
639                 numSTArrays = 1;
640         if( numColorArrays < 1 )
641                 numColorArrays = 1;
642         if( numIndexes < 1 )
643                 numIndexes = 1;
644         
645         /* additional vertexes? */
646         while( numVertexes > surface->maxVertexes ) /* fix */
647         {
648                 surface->maxVertexes += PICO_GROW_VERTEXES;
649                 if( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) )
650                         return 0;
651                 if( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) )
652                         return 0;
653                 if( !_pico_realloc( (void *) &surface->smoothingGroup, surface->numVertexes * sizeof( *surface->smoothingGroup ), surface->maxVertexes * sizeof( *surface->smoothingGroup ) ) )
654                         return 0;
655                 for( i = 0; i < surface->numSTArrays; i++ )
656                         if( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) )
657                         return 0;
658                 for( i = 0; i < surface->numColorArrays; i++ )
659                         if( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) )
660                         return 0;
661         }
662         
663         /* set vertex count to higher */
664         if( numVertexes > surface->numVertexes )
665                 surface->numVertexes = numVertexes;
666         
667         /* additional st arrays? */
668         while( numSTArrays > surface->maxSTArrays ) /* fix */
669         {
670                 surface->maxSTArrays += PICO_GROW_ARRAYS;
671                 if( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) )
672                         return 0;
673                 while( surface->numSTArrays < numSTArrays )
674                 {
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++;
678                 }
679         }
680         
681         /* additional color arrays? */
682         while( numColorArrays > surface->maxColorArrays ) /* fix */
683         {
684                 surface->maxColorArrays += PICO_GROW_ARRAYS;
685                 if( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) )
686                         return 0;
687                 while( surface->numColorArrays < numColorArrays )
688                 {
689                         surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
690                         memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) );
691                         surface->numColorArrays++;
692                 }
693         }
694         
695         /* additional indexes? */
696         while( numIndexes > surface->maxIndexes ) /* fix */
697         {
698                 surface->maxIndexes += PICO_GROW_INDEXES;
699                 if( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) )
700                         return 0;
701         }
702         
703         /* set index count to higher */
704         if( numIndexes > surface->numIndexes )
705                 surface->numIndexes = numIndexes;
706
707         /* additional face normals? */
708         while( numFaceNormals > surface->maxFaceNormals ) /* fix */
709         {
710                 surface->maxFaceNormals += PICO_GROW_FACES;
711                 if( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) )
712                         return 0;
713         }
714
715         /* set face normal count to higher */
716         if( numFaceNormals > surface->numFaceNormals )
717                 surface->numFaceNormals = numFaceNormals;
718
719         /* return ok */
720         return 1;
721 }
722
723
724 /* PicoFindSurface:
725  *   Finds first matching named surface in a model.
726  */
727 picoSurface_t *PicoFindSurface(
728         picoModel_t *model, char *name, int caseSensitive )
729 {
730         int             i;
731
732         /* sanity check */
733         if( model == NULL || name == NULL )
734                 return NULL;
735         
736         /* walk list */
737         for( i = 0; i < model->numSurfaces; i++ )
738         {
739                 /* skip null surfaces or surfaces with null names */
740                 if( model->surface[ i ] == NULL ||
741                         model->surface[ i ]->name == NULL )
742                         continue;
743
744                 /* compare the surface name with name we're looking for */
745                 if (caseSensitive) {
746                         if( !strcmp(name,model->surface[ i ]->name) )
747                                 return model->surface[ i ];
748                 } else {
749                         if( !_pico_stricmp(name,model->surface[ i ]->name) )
750                                 return model->surface[ i ];
751                 }
752         }
753         /* named surface not found */
754         return NULL;
755 }
756
757
758
759 /*----------------------------------------------------------------------------
760   PicoSet*() Setter Functions
761 ----------------------------------------------------------------------------*/
762
763 void PicoSetModelName( picoModel_t *model, char *name )
764 {
765         if( model == NULL || name == NULL )
766                 return;
767         if( model->name != NULL )
768                 _pico_free( model->name );
769
770         model->name = _pico_clone_alloc( name );
771 }
772
773
774
775 void PicoSetModelFileName( picoModel_t *model, char *fileName )
776 {
777         if( model == NULL || fileName == NULL )
778                 return;
779         if( model->fileName != NULL )
780                 _pico_free( model->fileName );
781
782         model->fileName = _pico_clone_alloc( fileName );
783 }
784
785
786
787 void PicoSetModelFrameNum( picoModel_t *model, int frameNum )
788 {
789         if( model == NULL )
790                 return;
791         model->frameNum = frameNum;
792 }
793
794
795
796 void PicoSetModelNumFrames( picoModel_t *model, int numFrames )
797 {
798         if( model == NULL )
799                 return;
800         model->numFrames = numFrames;
801 }
802
803
804
805 void PicoSetModelData( picoModel_t *model, void *data )
806 {
807         if( model == NULL )
808                 return;
809         model->data = data;
810 }
811
812
813
814 void PicoSetShaderName( picoShader_t *shader, char *name )
815 {
816         if( shader == NULL || name == NULL )
817                 return;
818         if( shader->name != NULL )
819                 _pico_free( shader->name );
820
821         shader->name = _pico_clone_alloc( name );
822 }
823
824
825
826 void PicoSetShaderMapName( picoShader_t *shader, char *mapName )
827 {
828         if( shader == NULL || mapName == NULL )
829                 return;
830         if( shader->mapName != NULL )
831                 _pico_free( shader->mapName );
832
833         shader->mapName = _pico_clone_alloc( mapName );
834 }
835
836
837
838 void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color )
839 {
840         if( shader == NULL || color == NULL )
841                 return;
842         shader->ambientColor[ 0 ] = color[ 0 ];
843         shader->ambientColor[ 1 ] = color[ 1 ];
844         shader->ambientColor[ 2 ] = color[ 2 ];
845         shader->ambientColor[ 3 ] = color[ 3 ];
846 }
847
848
849
850 void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color )
851 {
852         if( shader == NULL || color == NULL )
853                 return;
854         shader->diffuseColor[ 0 ] = color[ 0 ];
855         shader->diffuseColor[ 1 ] = color[ 1 ];
856         shader->diffuseColor[ 2 ] = color[ 2 ];
857         shader->diffuseColor[ 3 ] = color[ 3 ];
858 }
859
860
861
862 void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color )
863 {
864         if( shader == NULL || color == NULL )
865                 return;
866         shader->specularColor[ 0 ] = color[ 0 ];
867         shader->specularColor[ 1 ] = color[ 1 ];
868         shader->specularColor[ 2 ] = color[ 2 ];
869         shader->specularColor[ 3 ] = color[ 3 ];
870 }
871
872
873
874 void PicoSetShaderTransparency( picoShader_t *shader, float value )
875 {
876         if( shader == NULL )
877                 return;
878         shader->transparency = value;
879
880         /* cap to 0..1 range */
881         if (shader->transparency < 0.0)
882                 shader->transparency = 0.0;
883         if (shader->transparency > 1.0)
884                 shader->transparency = 1.0;
885 }
886
887
888
889 void PicoSetShaderShininess( picoShader_t *shader, float value )
890 {
891         if( shader == NULL )
892                 return;
893         shader->shininess = value;
894
895         /* cap to 0..127 range */
896         if (shader->shininess < 0.0)
897                 shader->shininess = 0.0;
898         if (shader->shininess > 127.0)
899                 shader->shininess = 127.0;
900 }
901
902
903
904 void PicoSetSurfaceData( picoSurface_t *surface, void *data )
905 {
906         if( surface == NULL )
907                 return;
908         surface->data = data;
909 }
910
911
912
913 void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type )
914 {
915         if( surface == NULL )
916                 return;
917         surface->type = type;
918 }
919
920
921
922 void PicoSetSurfaceName( picoSurface_t *surface, char *name )
923 {
924         if( surface == NULL || name == NULL )
925                 return;
926         if( surface->name != NULL )
927                 _pico_free( surface->name );
928
929         surface->name = _pico_clone_alloc( name );
930 }
931
932
933
934 void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader )
935 {
936         if( surface == NULL )
937                 return;
938         surface->shader = shader;
939 }
940
941
942
943 void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz )
944 {
945         if( surface == NULL || num < 0 || xyz == NULL )
946                 return;
947         if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) )
948                 return;
949         _pico_copy_vec( xyz, surface->xyz[ num ] );
950         if( surface->model != NULL )
951                 _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs );
952 }
953
954
955
956 void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal )
957 {
958         if( surface == NULL || num < 0 || normal == NULL )
959                 return;
960         if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) )
961                 return;
962         _pico_copy_vec( normal, surface->normal[ num ] );
963 }
964
965
966
967 void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st )
968 {
969         if( surface == NULL || num < 0 || st == NULL )
970                 return;
971         if( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) )
972                 return;
973         surface->st[ array ][ num ][ 0 ] = st[ 0 ];
974         surface->st[ array ][ num ][ 1 ] = st[ 1 ];
975 }
976
977
978
979 void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color )
980 {
981         if( surface == NULL || num < 0 || color == NULL )
982                 return;
983         if( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) )
984                 return;
985         surface->color[ array ][ num ][ 0 ] = color[ 0 ];
986         surface->color[ array ][ num ][ 1 ] = color[ 1 ];
987         surface->color[ array ][ num ][ 2 ] = color[ 2 ];
988         surface->color[ array ][ num ][ 3 ] = color[ 3 ];
989 }
990
991
992
993 void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index )
994 {
995         if( surface == NULL || num < 0 )
996                 return;
997         if( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) )
998                 return;
999         surface->index[ num ] = index;
1000 }
1001
1002
1003
1004 void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count )
1005 {
1006         if( num < 0 || index == NULL || count < 1 )
1007                 return;
1008         if( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) )
1009                 return;
1010         memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) );
1011 }
1012
1013
1014
1015 void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal )
1016 {
1017         if( surface == NULL || num < 0 || normal == NULL )
1018                 return;
1019         if( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) )
1020                 return;
1021         _pico_copy_vec( normal, surface->faceNormal[ num ] );
1022 }
1023
1024
1025 void PicoSetSurfaceSmoothingGroup( picoSurface_t *surface, int num, picoIndex_t smoothingGroup )
1026 {
1027         if( num < 0 )
1028                 return;
1029         if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) )
1030                 return;
1031         surface->smoothingGroup[ num ] = smoothingGroup;
1032 }
1033
1034
1035 void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special )
1036 {
1037         if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL )
1038                 return;
1039         surface->special[ num ] = special;
1040 }
1041
1042
1043
1044 /*----------------------------------------------------------------------------
1045   PicoGet*() Getter Functions
1046 ----------------------------------------------------------------------------*/
1047
1048 char *PicoGetModelName( picoModel_t *model )
1049 {
1050         if( model == NULL )
1051                 return NULL;
1052         if( model->name == NULL)
1053                 return (char*) "";
1054         return model->name;
1055 }
1056
1057
1058
1059 char *PicoGetModelFileName( picoModel_t *model )
1060 {
1061         if( model == NULL )
1062                 return NULL;
1063         if( model->fileName == NULL)
1064                 return (char*) "";
1065         return model->fileName;
1066 }
1067
1068
1069
1070 int PicoGetModelFrameNum( picoModel_t *model )
1071 {
1072         if( model == NULL )
1073                 return 0;
1074         return model->frameNum;
1075 }
1076
1077
1078
1079 int PicoGetModelNumFrames( picoModel_t *model )
1080 {
1081         if( model == NULL )
1082                 return 0;
1083         return model->numFrames;
1084 }
1085
1086
1087
1088 void *PicoGetModelData( picoModel_t *model )
1089 {
1090         if( model == NULL )
1091                 return NULL;
1092         return model->data;
1093 }
1094
1095
1096
1097 int PicoGetModelNumShaders( picoModel_t *model )
1098 {
1099         if( model == NULL )
1100                 return 0;
1101         return model->numShaders;
1102 }
1103
1104
1105
1106 picoShader_t *PicoGetModelShader( picoModel_t *model, int num )
1107 {
1108         /* a few sanity checks */
1109         if( model == NULL )
1110                 return NULL;
1111         if( model->shader == NULL)
1112                 return NULL;
1113         if( num < 0 || num >= model->numShaders )
1114                 return NULL;
1115         
1116         /* return the shader */
1117         return model->shader[ num ];
1118 }
1119
1120
1121
1122 int PicoGetModelNumSurfaces( picoModel_t *model )
1123 {
1124         if( model == NULL )
1125                 return 0;
1126         return model->numSurfaces;
1127 }
1128
1129
1130
1131 picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num )
1132 {
1133         /* a few sanity checks */
1134         if( model == NULL )
1135                 return NULL;
1136         if( model->surface == NULL)
1137                 return NULL;
1138         if( num < 0 || num >= model->numSurfaces )
1139                 return NULL;
1140         
1141         /* return the surface */
1142         return model->surface[ num ];
1143 }
1144
1145
1146
1147 int PicoGetModelTotalVertexes( picoModel_t *model )
1148 {
1149         int             i, count;
1150         
1151         
1152         if( model == NULL )
1153                 return 0;
1154         if( model->surface == NULL )
1155                 return 0;
1156         
1157         count = 0;
1158         for( i = 0; i < model->numSurfaces; i++ )
1159                  count += PicoGetSurfaceNumVertexes( model->surface[ i ] );
1160         
1161         return count;
1162 }
1163
1164
1165
1166 int PicoGetModelTotalIndexes( picoModel_t *model )
1167 {
1168         int             i, count;
1169         
1170         
1171         if( model == NULL )
1172                 return 0;
1173         if( model->surface == NULL )
1174                 return 0;
1175         
1176         count = 0;
1177         for( i = 0; i < model->numSurfaces; i++ )
1178                  count += PicoGetSurfaceNumIndexes( model->surface[ i ] );
1179         
1180         return count;
1181 }
1182
1183
1184
1185 char *PicoGetShaderName( picoShader_t *shader )
1186 {
1187         if( shader == NULL )
1188                 return NULL;
1189         if( shader->name == NULL)
1190                 return (char*) "";
1191         return shader->name;
1192 }
1193
1194
1195
1196 char *PicoGetShaderMapName( picoShader_t *shader )
1197 {
1198         if( shader == NULL )
1199                 return NULL;
1200         if( shader->mapName == NULL)
1201                 return (char*) "";
1202         return shader->mapName;
1203 }
1204
1205
1206
1207 picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader )
1208 {
1209         if( shader == NULL )
1210                 return NULL;
1211         return shader->ambientColor;
1212 }
1213
1214
1215
1216 picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader )
1217 {
1218         if( shader == NULL )
1219                 return NULL;
1220         return shader->diffuseColor;
1221 }
1222
1223
1224
1225 picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader )
1226 {
1227         if( shader == NULL )
1228                 return NULL;
1229         return shader->specularColor;
1230 }
1231
1232
1233
1234 float PicoGetShaderTransparency( picoShader_t *shader )
1235 {
1236         if( shader == NULL )
1237                 return 0.0f;
1238         return shader->transparency;
1239 }
1240
1241
1242
1243 float PicoGetShaderShininess( picoShader_t *shader )
1244 {
1245         if( shader == NULL )
1246                 return 0.0f;
1247         return shader->shininess;
1248 }
1249
1250
1251
1252 void *PicoGetSurfaceData( picoSurface_t *surface )
1253 {
1254         if( surface == NULL )
1255                 return NULL;
1256         return surface->data;
1257 }
1258
1259
1260
1261 picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface )
1262 {
1263         if( surface == NULL )
1264                 return PICO_BAD;
1265         return surface->type;
1266 }
1267
1268
1269
1270 char *PicoGetSurfaceName( picoSurface_t *surface )
1271 {
1272         if( surface == NULL )
1273                 return NULL;
1274         if( surface->name == NULL )
1275                 return (char*) "";
1276         return surface->name;
1277 }
1278
1279
1280
1281 picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface )
1282 {
1283         if( surface == NULL )
1284                 return NULL;
1285         return surface->shader;
1286 }
1287
1288
1289
1290 int PicoGetSurfaceNumVertexes( picoSurface_t *surface )
1291 {
1292         if( surface == NULL )
1293                 return 0;
1294         return surface->numVertexes;
1295 }
1296
1297
1298
1299 picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num )
1300 {
1301         if( surface == NULL || num < 0 || num > surface->numVertexes )
1302                 return NULL;
1303         return surface->xyz[ num ];
1304 }
1305
1306
1307
1308 picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num )
1309 {
1310         if( surface == NULL || num < 0 || num > surface->numVertexes )
1311                 return NULL;
1312         return surface->normal[ num ];
1313 }
1314
1315
1316
1317 picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num  )
1318 {
1319         if( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes )
1320                 return NULL;
1321         return surface->st[ array ][ num ];
1322 }
1323
1324
1325
1326 picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num )
1327 {
1328         if( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes )
1329                 return NULL;
1330         return surface->color[ array ][ num ];
1331 }
1332
1333
1334
1335 int PicoGetSurfaceNumIndexes( picoSurface_t *surface )
1336 {
1337         if( surface == NULL )
1338                 return 0;
1339         return surface->numIndexes;
1340 }
1341
1342
1343
1344 picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num )
1345 {
1346         if( surface == NULL || num < 0 || num > surface->numIndexes )
1347                 return 0;
1348         return surface->index[ num ];
1349 }
1350
1351
1352
1353 picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num )
1354 {
1355         if( surface == NULL || num < 0 || num > surface->numIndexes )
1356                 return NULL;
1357         return &surface->index[ num ];
1358 }
1359
1360
1361 picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num )
1362 {
1363         if( surface == NULL || num < 0 || num > surface->numFaceNormals )
1364                 return NULL;
1365         return surface->faceNormal[ num ];
1366 }
1367
1368 picoIndex_t PicoGetSurfaceSmoothingGroup( picoSurface_t *surface, int num )
1369 {
1370         if( surface == NULL || num < 0 || num > surface->numVertexes )
1371                 return -1;
1372         return surface->smoothingGroup[ num ];
1373 }
1374
1375
1376 int PicoGetSurfaceSpecial( picoSurface_t *surface, int num )
1377 {
1378         if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL )
1379                 return 0;
1380         return surface->special[ num ];
1381 }
1382
1383
1384
1385 /* ----------------------------------------------------------------------------
1386 hashtable related functions
1387 ---------------------------------------------------------------------------- */
1388
1389 /* hashtable code for faster vertex lookups */
1390 //#define HASHTABLE_SIZE 32768 // 2048                  /* power of 2, use & */
1391 #define HASHTABLE_SIZE 7919 // 32749 // 2039    /* prime, use % */
1392
1393 int PicoGetHashTableSize( void )
1394 {
1395         return HASHTABLE_SIZE;
1396 }
1397
1398 #define HASH_USE_EPSILON
1399
1400 #ifdef HASH_USE_EPSILON
1401 #define HASH_XYZ_EPSILON                                        0.01f
1402 #define HASH_XYZ_EPSILONSPACE_MULTIPLIER        1.f / HASH_XYZ_EPSILON
1403 #define HASH_ST_EPSILON                                         0.0001f
1404 #define HASH_NORMAL_EPSILON                                     0.02f
1405 #endif
1406
1407 unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz )
1408 {
1409         unsigned int hash = 0;
1410
1411 #ifndef HASH_USE_EPSILON
1412         hash += ~(*((unsigned int*) &xyz[ 0 ]) << 15);
1413         hash ^= (*((unsigned int*) &xyz[ 0 ]) >> 10);
1414         hash += (*((unsigned int*) &xyz[ 1 ]) << 3);
1415         hash ^= (*((unsigned int*) &xyz[ 1 ]) >> 6);
1416         hash += ~(*((unsigned int*) &xyz[ 2 ]) << 11);
1417         hash ^= (*((unsigned int*) &xyz[ 2 ]) >> 16);
1418 #else
1419         picoVec3_t xyz_epsilonspace;
1420
1421         _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace );
1422         xyz_epsilonspace[ 0 ] = (float)floor(xyz_epsilonspace[ 0 ]);
1423         xyz_epsilonspace[ 1 ] = (float)floor(xyz_epsilonspace[ 1 ]);
1424         xyz_epsilonspace[ 2 ] = (float)floor(xyz_epsilonspace[ 2 ]);
1425
1426         hash += ~(*((unsigned int*) &xyz_epsilonspace[ 0 ]) << 15);
1427         hash ^= (*((unsigned int*) &xyz_epsilonspace[ 0 ]) >> 10);
1428         hash += (*((unsigned int*) &xyz_epsilonspace[ 1 ]) << 3);
1429         hash ^= (*((unsigned int*) &xyz_epsilonspace[ 1 ]) >> 6);
1430         hash += ~(*((unsigned int*) &xyz_epsilonspace[ 2 ]) << 11);
1431         hash ^= (*((unsigned int*) &xyz_epsilonspace[ 2 ]) >> 16);
1432 #endif
1433
1434         //hash = hash & (HASHTABLE_SIZE-1);
1435         hash = hash % (HASHTABLE_SIZE);
1436         return hash;
1437 }
1438
1439 picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void )
1440 {
1441         picoVertexCombinationHash_t     **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) );
1442
1443         memset( hashTable, 0, HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) );
1444
1445         return hashTable;
1446 }
1447
1448 void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable )
1449 {
1450         int                                                     i;
1451         picoVertexCombinationHash_t     *vertexCombinationHash;
1452         picoVertexCombinationHash_t *nextVertexCombinationHash;
1453
1454         /* dummy check */
1455         if (hashTable == NULL)
1456                 return;
1457
1458         for( i = 0; i < HASHTABLE_SIZE; i++ )
1459         {
1460                 if (hashTable[ i ])
1461                 {
1462                         nextVertexCombinationHash = NULL;
1463
1464                         for( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash )
1465                         {
1466                                 nextVertexCombinationHash = vertexCombinationHash->next;
1467                                 if (vertexCombinationHash->data != NULL)
1468                                 {
1469                                         _pico_free( vertexCombinationHash->data );
1470                                 }
1471                                 _pico_free( vertexCombinationHash );
1472                         }
1473                 }
1474         }
1475
1476         _pico_free( hashTable );
1477 }
1478
1479 picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color )
1480 {
1481         unsigned int                            hash;
1482         picoVertexCombinationHash_t     *vertexCombinationHash;
1483
1484         /* dumy check */
1485         if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL )
1486                 return NULL;
1487
1488         hash = PicoVertexCoordGenerateHash( xyz );
1489
1490         for( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next )
1491         {
1492 #ifndef HASH_USE_EPSILON
1493                 /* check xyz */
1494                 if( (vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ]) )
1495                         continue;
1496
1497                 /* check normal */
1498                 if( (vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ]) )
1499                         continue;
1500                 
1501                 /* check st */
1502                 if( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] )
1503                         continue;
1504 #else
1505                 /* check xyz */
1506                 if( ( fabs(xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ]) ) > HASH_XYZ_EPSILON ||
1507                         ( fabs(xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ]) ) > HASH_XYZ_EPSILON ||
1508                         ( fabs(xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ]) ) > HASH_XYZ_EPSILON )
1509                         continue;
1510
1511                 /* check normal */
1512                 if( ( fabs(normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ]) ) > HASH_NORMAL_EPSILON ||
1513                         ( fabs(normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ]) ) > HASH_NORMAL_EPSILON ||
1514                         ( fabs(normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ]) ) > HASH_NORMAL_EPSILON )
1515                         continue;
1516                 
1517                 /* check st */
1518                 if( ( fabs(st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ]) ) > HASH_ST_EPSILON ||
1519                         ( fabs(st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ]) ) > HASH_ST_EPSILON )
1520                         continue;
1521 #endif
1522
1523                 /* check color */
1524                 if( *((int*) vertexCombinationHash->vcd.color) != *((int*) color) )
1525                         continue;
1526
1527                 /* gotcha */
1528                 return vertexCombinationHash;
1529         }
1530
1531         return NULL;
1532 }
1533
1534 picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index )
1535 {
1536         unsigned int                            hash;
1537         picoVertexCombinationHash_t     *vertexCombinationHash;
1538
1539         /* dumy check */
1540         if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL )
1541                 return NULL;
1542
1543         vertexCombinationHash = _pico_alloc( sizeof(picoVertexCombinationHash_t) );
1544
1545         if (!vertexCombinationHash)
1546                 return NULL;
1547
1548         hash = PicoVertexCoordGenerateHash( xyz );
1549
1550         _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz );
1551         _pico_copy_vec( normal, vertexCombinationHash->vcd.normal );
1552         _pico_copy_vec2( st, vertexCombinationHash->vcd.st );
1553         _pico_copy_color( color, vertexCombinationHash->vcd.color );
1554         vertexCombinationHash->index = index;
1555         vertexCombinationHash->data = NULL;
1556         vertexCombinationHash->next = hashTable[ hash ];
1557         hashTable[ hash ] = vertexCombinationHash;
1558
1559         return vertexCombinationHash;
1560 }
1561
1562 /* ----------------------------------------------------------------------------
1563 specialized routines
1564 ---------------------------------------------------------------------------- */
1565
1566 /*
1567 PicoFindSurfaceVertex()
1568 finds a vertex matching the set parameters
1569 fixme: needs non-naive algorithm
1570 */
1571
1572 int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color, picoIndex_t smoothingGroup)
1573 {
1574         int             i, j;
1575         
1576         
1577         /* dummy check */
1578         if( surface == NULL || surface->numVertexes <= 0 )
1579                 return -1;
1580         
1581         /* walk vertex list */
1582         for( i = 0; i < surface->numVertexes; i++ )
1583         {
1584                 /* check xyz */
1585                 if( xyz != NULL && (surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ]) )
1586                         continue;
1587                 
1588                 /* check normal */
1589                 if( normal != NULL && (surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ]) )
1590                         continue;
1591                 
1592                 /* check normal */
1593                 if( surface->smoothingGroup[ i ] != smoothingGroup )
1594                         continue;
1595
1596     /* check st */
1597                 if( numSTs > 0 && st != NULL )
1598                 {
1599                         for( j = 0; j < numSTs; j++ )
1600                         {
1601                                 if( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] )
1602                                         break;
1603                         }
1604                         if( j != numSTs )
1605                                 continue;
1606                 }
1607                 
1608                 /* check color */
1609                 if( numColors > 0 && color != NULL )
1610                 {
1611                         for( j = 0; j < numSTs; j++ )
1612                         {
1613                                 if( *((int*) surface->color[ j ]) != *((int*) color[ j ]) )
1614                                         break;
1615                         }
1616                         if( j != numColors )
1617                                 continue;
1618                 }
1619                 
1620                 /* vertex matches */
1621                 return i;
1622         }
1623         
1624         /* nada */
1625         return -1;
1626 }
1627
1628
1629
1630
1631 typedef struct _IndexArray IndexArray;
1632 struct _IndexArray
1633 {
1634         picoIndex_t* data;
1635         picoIndex_t* last;
1636 };
1637
1638 void indexarray_push_back(IndexArray* self, picoIndex_t value)
1639 {
1640         *self->last++ = value;
1641 }
1642
1643 size_t indexarray_size(IndexArray* self)
1644 {
1645         return self->last - self->data;
1646 }
1647
1648 void indexarray_reserve(IndexArray* self, size_t size)
1649 {
1650         self->data = self->last = _pico_calloc(size, sizeof(picoIndex_t));
1651 }
1652
1653 void indexarray_clear(IndexArray* self)
1654 {
1655         _pico_free(self->data);
1656 }
1657
1658 typedef struct _BinaryTreeNode BinaryTreeNode;
1659 struct _BinaryTreeNode
1660 {
1661         picoIndex_t left;
1662         picoIndex_t right;
1663 };
1664
1665 typedef struct _BinaryTree BinaryTree;
1666 struct _BinaryTree
1667 {
1668         BinaryTreeNode* data;
1669         BinaryTreeNode* last;
1670 };
1671
1672 void binarytree_extend(BinaryTree* self)
1673 {
1674         self->last->left = 0;
1675         self->last->right = 0;
1676         ++self->last;
1677 }
1678
1679 size_t binarytree_size(BinaryTree* self)
1680 {
1681         return self->last - self->data;
1682 }
1683
1684 void binarytree_reserve(BinaryTree* self, size_t size)
1685 {
1686         self->data = self->last = _pico_calloc(size, sizeof(BinaryTreeNode));
1687 }
1688
1689 void binarytree_clear(BinaryTree* self)
1690 {
1691         _pico_free(self->data);
1692 }
1693
1694 typedef int (*LessFunc)(void*, picoIndex_t, picoIndex_t);
1695
1696 typedef struct _UniqueIndices UniqueIndices;
1697 struct _UniqueIndices
1698 {
1699         BinaryTree tree;
1700         IndexArray indices;
1701         LessFunc lessFunc;
1702         void* lessData;
1703 };
1704
1705 size_t UniqueIndices_size(UniqueIndices* self)
1706 {
1707   return binarytree_size(&self->tree);
1708 }
1709
1710 void UniqueIndices_reserve(UniqueIndices* self, size_t size)
1711 {
1712         binarytree_reserve(&self->tree, size);
1713         indexarray_reserve(&self->indices, size);
1714 }
1715
1716 void UniqueIndices_init(UniqueIndices* self, LessFunc lessFunc, void* lessData)
1717 {
1718         self->lessFunc = lessFunc;
1719         self->lessData = lessData;
1720 }
1721
1722 void UniqueIndices_destroy(UniqueIndices* self)
1723 {
1724         binarytree_clear(&self->tree);
1725         indexarray_clear(&self->indices);
1726 }
1727
1728
1729 picoIndex_t UniqueIndices_find_or_insert(UniqueIndices* self, picoIndex_t value)
1730 {
1731         picoIndex_t index = 0;
1732
1733         for(;;)
1734         {
1735                 if(self->lessFunc(self->lessData, value, self->indices.data[index]))
1736                 {
1737                         BinaryTreeNode* node = self->tree.data + index;
1738                         if(node->left != 0)
1739                         {
1740                                 index = node->left;
1741                                 continue;
1742                         }
1743                         else
1744                         {
1745                                 node->left = (picoIndex_t)binarytree_size(&self->tree);
1746                                 binarytree_extend(&self->tree);
1747                                 indexarray_push_back(&self->indices, value);
1748                                 return node->left;
1749                         }
1750                 }
1751                 if(self->lessFunc(self->lessData, self->indices.data[index], value))
1752                 {
1753                         BinaryTreeNode* node = self->tree.data + index;
1754                         if(node->right != 0)
1755                         {
1756                                 index = node->right;
1757                                 continue;
1758                         }
1759                         else
1760                         {
1761                                 node->right = (picoIndex_t)binarytree_size(&self->tree);
1762                                 binarytree_extend(&self->tree);
1763                                 indexarray_push_back(&self->indices, value);
1764                                 return node->right;
1765                         }
1766                 }
1767
1768                 return index;
1769         }
1770 }
1771
1772 picoIndex_t UniqueIndices_insert(UniqueIndices* self, picoIndex_t value)
1773 {
1774         if(self->tree.data == self->tree.last)
1775         {
1776                 binarytree_extend(&self->tree);
1777                 indexarray_push_back(&self->indices, value);
1778                 return 0;
1779     }
1780         else
1781         {
1782                 return UniqueIndices_find_or_insert(self, value);
1783         }
1784 }
1785
1786 typedef struct picoSmoothVertices_s picoSmoothVertices_t;
1787 struct picoSmoothVertices_s
1788 {
1789         picoVec3_t* xyz;
1790         picoIndex_t* smoothingGroups;
1791 };
1792
1793 int lessSmoothVertex(void* data, picoIndex_t first, picoIndex_t second)
1794 {
1795         picoSmoothVertices_t* smoothVertices = data;
1796         
1797         if(smoothVertices->xyz[first][0] != smoothVertices->xyz[second][0])
1798         {
1799                 return smoothVertices->xyz[first][0] < smoothVertices->xyz[second][0];
1800         }
1801         if(smoothVertices->xyz[first][1] != smoothVertices->xyz[second][1])
1802         {
1803                 return smoothVertices->xyz[first][1] < smoothVertices->xyz[second][1];
1804         }
1805         if(smoothVertices->xyz[first][2] != smoothVertices->xyz[second][2])
1806         {
1807                 return smoothVertices->xyz[first][2] < smoothVertices->xyz[second][2];
1808         }
1809         if(smoothVertices->smoothingGroups[first] != smoothVertices->smoothingGroups[second])
1810         {
1811                 return smoothVertices->smoothingGroups[first] < smoothVertices->smoothingGroups[second];
1812         }
1813         return 0;
1814 }
1815
1816 void _pico_vertices_combine_shared_normals(picoVec3_t* xyz, picoIndex_t* smoothingGroups, picoVec3_t* normals, picoIndex_t numVertices)
1817 {
1818         UniqueIndices vertices;
1819         IndexArray indices;
1820         picoSmoothVertices_t smoothVertices = { xyz, smoothingGroups };
1821         UniqueIndices_init(&vertices, lessSmoothVertex, &smoothVertices);
1822         UniqueIndices_reserve(&vertices, numVertices);
1823         indexarray_reserve(&indices, numVertices);
1824
1825
1826         {
1827                 picoIndex_t i = 0;
1828                 for(; i < numVertices; ++i)
1829                 {
1830                         size_t size = UniqueIndices_size(&vertices);
1831                         picoIndex_t index = UniqueIndices_insert(&vertices, i);
1832                         if((size_t)index != size)
1833                         {
1834                                 float* normal = normals[vertices.indices.data[index]];
1835                                 _pico_add_vec(normal, normals[i], normal);
1836                         }
1837                         indexarray_push_back(&indices, index);
1838                 }
1839         }
1840
1841         {
1842                 picoIndex_t maxIndex = 0;
1843                 picoIndex_t* i = indices.data;
1844                 for(; i != indices.last; ++i)
1845                 {
1846                         if(*i <= maxIndex)
1847                         {
1848                                 _pico_copy_vec(normals[vertices.indices.data[*i]], normals[i - indices.data]);
1849                         }
1850                         else
1851                         {
1852                                 maxIndex = *i;
1853                         }
1854                 }
1855         }
1856
1857         UniqueIndices_destroy(&vertices);
1858   indexarray_clear(&indices);
1859 }
1860
1861 typedef picoVec3_t* picoNormalIter_t;
1862 typedef picoIndex_t* picoIndexIter_t;
1863
1864 #define THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL 1
1865
1866 void _pico_triangles_generate_weighted_normals(picoIndexIter_t first, picoIndexIter_t end, picoVec3_t* xyz, picoVec3_t* normals)
1867 {
1868         for(; first != end; first += 3)
1869         {
1870 #if (THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL)
1871                 picoVec3_t weightedNormal;
1872                 {
1873                         float* a = xyz[*(first + 0)];
1874                         float* b = xyz[*(first + 1)];
1875                         float* c = xyz[*(first + 2)];
1876                         picoVec3_t ba, ca;
1877                         _pico_subtract_vec( b, a, ba );
1878                         _pico_subtract_vec( c, a, ca );
1879                         _pico_cross_vec( ca, ba, weightedNormal );
1880                 }
1881 #endif
1882                 {
1883                         int j = 0;
1884                         for(; j < 3; ++j)
1885                         {
1886                                 float* normal = normals[*(first + j)];
1887 #if (!THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL)
1888                                 picoVec3_t weightedNormal;
1889                                 {
1890                                         float* a = xyz[*(first + ((j + 0) % 3))];
1891                                         float* b = xyz[*(first + ((j + 1) % 3))];
1892                                         float* c = xyz[*(first + ((j + 2) % 3))];
1893                                         picoVec3_t ba, ca;
1894                                         _pico_subtract_vec( b, a, ba );
1895                                         _pico_subtract_vec( c, a, ca );
1896                                         _pico_cross_vec( ca, ba, weightedNormal );
1897                                 }
1898 #endif
1899                                 _pico_add_vec(weightedNormal, normal, normal);
1900                         }
1901                 }
1902         }
1903 }
1904
1905 void _pico_normals_zero(picoNormalIter_t first, picoNormalIter_t last)
1906 {
1907         for(; first != last; ++first)
1908         {
1909                 _pico_zero_vec(*first);
1910         }
1911 }
1912
1913 void _pico_normals_normalize(picoNormalIter_t first, picoNormalIter_t last)
1914 {
1915         for(; first != last; ++first)
1916         {
1917                 _pico_normalize_vec(*first);
1918         }
1919 }
1920
1921 double _pico_length_vec( picoVec3_t vec )
1922 {
1923         return sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] );
1924 }
1925
1926 #define NORMAL_UNIT_LENGTH_EPSILON 0.01
1927 #define FLOAT_EQUAL_EPSILON(f, other, epsilon) (fabs(f - other) < epsilon)
1928
1929 int _pico_normal_is_unit_length(picoVec3_t normal)
1930 {
1931         return FLOAT_EQUAL_EPSILON(_pico_length_vec(normal), 1.0, NORMAL_UNIT_LENGTH_EPSILON);
1932 }
1933
1934 int _pico_normal_within_tolerance(picoVec3_t normal, picoVec3_t other)
1935 {
1936         return _pico_dot_vec(normal, other) > 0.0f;
1937 }
1938
1939
1940 void _pico_normals_assign_generated_normals(picoNormalIter_t first, picoNormalIter_t last, picoNormalIter_t generated)
1941 {
1942         for(; first != last; ++first, ++generated)
1943         {
1944                 if(!_pico_normal_is_unit_length(*first) || !_pico_normal_within_tolerance(*first, *generated))
1945                 {
1946                         _pico_copy_vec(*generated, *first);
1947                 }
1948         }
1949 }
1950
1951 void PicoFixSurfaceNormals(picoSurface_t* surface)
1952 {
1953         picoVec3_t* normals = (picoVec3_t*)_pico_calloc(surface->numVertexes, sizeof(picoVec3_t));
1954
1955         _pico_normals_zero(normals, normals + surface->numVertexes);
1956
1957         _pico_triangles_generate_weighted_normals(surface->index, surface->index + surface->numIndexes, surface->xyz, normals);
1958         _pico_vertices_combine_shared_normals(surface->xyz, surface->smoothingGroup, normals, surface->numVertexes);
1959
1960         _pico_normals_normalize(normals, normals + surface->numVertexes);
1961
1962         _pico_normals_assign_generated_normals(surface->normal, surface->normal + surface->numVertexes, normals);
1963
1964         _pico_free(normals);
1965 }
1966
1967
1968 /*
1969 PicoRemapModel() - sea
1970 remaps model material/etc. information using the remappings
1971 contained in the given 'remapFile' (full path to the ascii file to open)
1972 returns 1 on success or 0 on error
1973 */
1974
1975 #define _prm_error_return \
1976 { \
1977         _pico_free_parser( p ); \
1978         _pico_free_file( remapBuffer ); \
1979         return 0; \
1980 }
1981
1982 int PicoRemapModel( picoModel_t *model, char *remapFile )
1983 {
1984         picoParser_t    *p;
1985         picoByte_t              *remapBuffer;
1986         int                             remapBufSize;
1987         
1988         
1989         /* sanity checks */
1990         if( model == NULL || remapFile == NULL )
1991                 return 0;
1992         
1993         /* load remap file contents */
1994         _pico_load_file( remapFile,&remapBuffer,&remapBufSize );
1995         
1996         /* check result */
1997         if( remapBufSize == 0 )
1998                 return 1;       /* file is empty: no error */
1999         if( remapBufSize < 0 )
2000                 return 0;       /* load failed: error */
2001         
2002         /* create a new pico parser */
2003         p = _pico_new_parser( remapBuffer, remapBufSize );
2004         if (p == NULL)
2005         {
2006                 /* ram is really cheap nowadays... */
2007                 _prm_error_return;
2008         }
2009         
2010         /* doo teh parse */
2011         while( 1 )
2012         {
2013                 /* get next token in remap file */
2014                 if (!_pico_parse( p,1 ))
2015                         break;
2016
2017                 /* skip over c++ style comment lines */
2018                 if (!_pico_stricmp(p->token,"//"))
2019                 {
2020                         _pico_parse_skip_rest( p );
2021                         continue;
2022                 }
2023                 
2024                 /* block for quick material shader name remapping */
2025                 /* materials { "m" (=>|->|=) "s" } */
2026                 if( !_pico_stricmp(p->token, "materials" ) )
2027                 {
2028                         int level = 1;
2029
2030                         /* check bracket */
2031                         if (!_pico_parse_check( p,1,"{" ))
2032                                 _prm_error_return;
2033
2034                         /* process assignments */
2035                         while( 1 )
2036                         {
2037                                 picoShader_t    *shader;
2038                                 char                    *materialName;
2039                                 
2040                                 
2041                                 /* get material name */
2042                                 if (_pico_parse( p,1 ) == NULL) break;
2043                                 if (!strlen(p->token)) continue;
2044                                 materialName = _pico_clone_alloc( p->token );
2045                                 if (materialName == NULL)
2046                                         _prm_error_return;
2047
2048                                 /* handle levels */
2049                                 if (p->token[0] == '{') level++;
2050                                 if (p->token[0] == '}') level--;
2051                                 if (!level) break;
2052
2053                                 /* get next token (assignment token or shader name) */
2054                                 if (!_pico_parse( p,0 ))
2055                                 {
2056                                         _pico_free( materialName );
2057                                         _prm_error_return;
2058                                 }
2059                                 /* skip assignment token (if present) */
2060                                 if (!strcmp(p->token,"=>") ||
2061                                         !strcmp(p->token,"->") ||
2062                                         !strcmp(p->token,"="))
2063                                 {
2064                                         /* simply grab the next token */
2065                                         if (!_pico_parse( p,0 ))
2066                                         {
2067                                                 _pico_free( materialName );
2068                                                 _prm_error_return;
2069                                         }
2070                                 }
2071                                 /* try to find material by name */
2072                                 shader = PicoFindShader( model,materialName,0 );
2073
2074                                 /* we've found a material matching the name */
2075                                 if (shader != NULL)
2076                                 {
2077                                         PicoSetShaderName( shader,p->token );
2078                                 }
2079                                 /* free memory used by material name */
2080                                 _pico_free( materialName );
2081
2082                                 /* skip rest */
2083                                 _pico_parse_skip_rest( p );
2084                         }
2085                 }
2086                 /* block for detailed single material remappings */
2087                 /* materials[ "m" ] { key data... } */
2088                 else if (!_pico_stricmp(p->token,"materials["))
2089                 {
2090                         picoShader_t *shader;
2091                         char *tempMaterialName;
2092                         int level = 1;
2093
2094                         /* get material name */
2095                         if (!_pico_parse( p,0 ))
2096                                 _prm_error_return;
2097
2098                         /* temporary copy of material name */
2099                         tempMaterialName = _pico_clone_alloc( p->token );
2100                         if (tempMaterialName == NULL)
2101                                 _prm_error_return;
2102
2103                         /* check square closing bracket */
2104                         if (!_pico_parse_check( p,0,"]" ))
2105                                 _prm_error_return;                      
2106
2107                         /* try to find material by name */
2108                         shader = PicoFindShader( model,tempMaterialName,0 );
2109
2110                         /* free memory used by temporary material name */
2111                         _pico_free( tempMaterialName );
2112
2113                         /* we haven't found a material matching the name */
2114                         /* so we simply skip the braced section now and */
2115                         /* continue parsing with the next main token */
2116                         if (shader == NULL)
2117                         {
2118                                 _pico_parse_skip_braced( p );
2119                                 continue;
2120                         }
2121                         /* check opening bracket */
2122                         if (!_pico_parse_check( p,1,"{" ))
2123                                 _prm_error_return;
2124
2125                         /* process material info keys */
2126                         while( 1 )
2127                         {
2128                                 /* get key name */
2129                                 if (_pico_parse( p,1 ) == NULL) break;
2130                                 if (!strlen(p->token)) continue;
2131
2132                                 /* handle levels */
2133                                 if (p->token[0] == '{') level++;
2134                                 if (p->token[0] == '}') level--;
2135                                 if (!level) break;
2136
2137                                 /* remap shader name */
2138                                 if (!_pico_stricmp(p->token,"shader"))
2139                                 {
2140                                         if (!_pico_parse( p,0 )) _prm_error_return;
2141                                         PicoSetShaderName( shader,p->token );
2142                                 }
2143                                 /* remap shader map name */
2144                                 else if (!_pico_stricmp(p->token,"mapname"))
2145                                 {
2146                                         if (!_pico_parse( p,0 )) _prm_error_return;
2147                                         PicoSetShaderMapName( shader,p->token );
2148                                 }
2149                                 /* remap shader's ambient color */
2150                                 else if (!_pico_stricmp(p->token,"ambient"))
2151                                 {
2152                                         picoColor_t color;
2153                                         picoVec3_t  v;
2154
2155                                         /* get vector from parser */
2156                                         if (!_pico_parse_vec( p,v )) _prm_error_return;
2157
2158                                         /* store as color */
2159                                         color[ 0 ] = (picoByte_t)v[ 0 ];
2160                                         color[ 1 ] = (picoByte_t)v[ 1 ];
2161                                         color[ 2 ] = (picoByte_t)v[ 2 ];
2162
2163                                         /* set new ambient color */
2164                                         PicoSetShaderAmbientColor( shader,color );
2165                                 }
2166                                 /* remap shader's diffuse color */
2167                                 else if (!_pico_stricmp(p->token,"diffuse"))
2168                                 {
2169                                         picoColor_t color;
2170                                         picoVec3_t  v;
2171
2172                                         /* get vector from parser */
2173                                         if (!_pico_parse_vec( p,v )) _prm_error_return;
2174
2175                                         /* store as color */
2176                                         color[ 0 ] = (picoByte_t)v[ 0 ];
2177                                         color[ 1 ] = (picoByte_t)v[ 1 ];
2178                                         color[ 2 ] = (picoByte_t)v[ 2 ];
2179
2180                                         /* set new ambient color */
2181                                         PicoSetShaderDiffuseColor( shader,color );
2182                                 }
2183                                 /* remap shader's specular color */
2184                                 else if (!_pico_stricmp(p->token,"specular"))
2185                                 {
2186                                         picoColor_t color;
2187                                         picoVec3_t  v;
2188
2189                                         /* get vector from parser */
2190                                         if (!_pico_parse_vec( p,v )) _prm_error_return;
2191
2192                                         /* store as color */
2193                                         color[ 0 ] = (picoByte_t)v[ 0 ];
2194                                         color[ 1 ] = (picoByte_t)v[ 1 ];
2195                                         color[ 2 ] = (picoByte_t)v[ 2 ];
2196
2197                                         /* set new ambient color */
2198                                         PicoSetShaderSpecularColor( shader,color );
2199                                 }
2200                                 /* skip rest */
2201                                 _pico_parse_skip_rest( p );
2202                         }
2203                 }
2204                 /* end 'materials[' */
2205         }
2206         
2207         /* free both parser and file buffer */
2208         _pico_free_parser( p );
2209         _pico_free_file( remapBuffer );
2210
2211         /* return with success */
2212         return 1;
2213 }
2214
2215
2216 /*
2217 PicoAddTriangleToModel() - jhefty
2218 A nice way to add individual triangles to the model.
2219 Chooses an appropriate surface based on the shader, or adds a new surface if necessary
2220 */
2221
2222 void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, 
2223                                                         int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors,
2224                                                         picoShader_t* shader, picoIndex_t* smoothingGroup )
2225 {
2226         int i,j;
2227         int vertDataIndex;
2228         picoSurface_t* workSurface = NULL;
2229
2230         /* see if a surface already has the shader */
2231         for ( i = 0 ; i < model->numSurfaces ; i++ )
2232         {
2233                 workSurface = model->surface[i];
2234                 if ( workSurface->shader == shader )
2235                 {                       
2236                         break;
2237                 }
2238         }
2239
2240         /* no surface uses this shader yet, so create a new surface */
2241         if ( !workSurface || i >=model->numSurfaces )
2242         {
2243                 /* create a new surface in the model for the unique shader */
2244                 workSurface = PicoNewSurface(model);
2245                 if ( !workSurface )
2246                 {
2247                         _pico_printf ( PICO_ERROR , "Could not allocate a new surface!\n" );
2248                         return;
2249                 }
2250
2251                 /* do surface setup */
2252                 PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
2253                 PicoSetSurfaceName( workSurface, shader->name );
2254                 PicoSetSurfaceShader( workSurface, shader );
2255         }
2256
2257         /* add the triangle data to the surface */
2258         for ( i = 0 ; i < 3 ; i++ )     
2259         {
2260                 /* get the next free spot in the index array */
2261                 int newVertIndex = PicoGetSurfaceNumIndexes ( workSurface );
2262
2263                 /* get the index of the vertex that we're going to store at newVertIndex */
2264                 vertDataIndex = PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i], smoothingGroup[i]);
2265
2266                 /* the vertex wasn't found, so create a new vertex in the pool from the data we have */
2267                 if ( vertDataIndex == -1 )
2268                 {                       
2269                         /* find the next spot for a new vertex */
2270                         vertDataIndex = PicoGetSurfaceNumVertexes ( workSurface );                      
2271
2272                         /* assign the data to it */
2273                         PicoSetSurfaceXYZ ( workSurface ,vertDataIndex , *xyz[i] );
2274                         PicoSetSurfaceNormal ( workSurface , vertDataIndex , *normals[i] );                     
2275
2276                         /* make sure to copy over all available ST's and colors for the vertex */
2277                         for ( j = 0 ; j < numColors ; j++ )
2278                         {
2279                                 PicoSetSurfaceColor( workSurface , j , vertDataIndex , colors[i][j] );
2280                         }
2281                         for ( j = 0 ; j < numSTs ; j++ )
2282                         {
2283                                 PicoSetSurfaceST ( workSurface , j , vertDataIndex , st[i][j] );
2284                         }
2285
2286                         PicoSetSurfaceSmoothingGroup ( workSurface , vertDataIndex , smoothingGroup[i] );                       
2287                 }
2288
2289                 /* add this vertex to the triangle */           
2290                 PicoSetSurfaceIndex ( workSurface , newVertIndex , vertDataIndex );
2291         }
2292 }