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