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