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