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