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