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