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