]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/picointernal.c
* picomodel: do some guessings about shader paths to handle more cases out of the...
[xonotic/netradiant.git] / libs / picomodel / picointernal.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 /* todo:
36  * - fix p->curLine for parser routines. increased twice
37  */
38
39 /* dependencies */
40 #include <string.h>
41 #include "picointernal.h"
42 #include "globaldefs.h"
43
44
45
46 /* function pointers */
47 void *( *_pico_ptr_malloc    )( size_t ) = malloc;
48 void ( *_pico_ptr_free      )( void* ) = free;
49 void ( *_pico_ptr_load_file )( const char*, unsigned char**, int* ) = NULL;
50 void ( *_pico_ptr_free_file )( void* ) = NULL;
51 void ( *_pico_ptr_print     )( int, const char* ) = NULL;
52
53 typedef union
54 {
55         float f;
56         char c[4];
57 }
58 floatSwapUnion;
59
60 /* _pico_alloc:
61  *  kludged memory allocation wrapper
62  */
63 void *_pico_alloc( size_t size ){
64         void *ptr;
65
66         /* some sanity checks */
67         if ( size == 0 ) {
68                 return NULL;
69         }
70         if ( _pico_ptr_malloc == NULL ) {
71                 return NULL;
72         }
73
74         /* allocate memory */
75         ptr = _pico_ptr_malloc( size );
76         if ( ptr == NULL ) {
77                 return NULL;
78         }
79
80         /* zero out allocated memory */
81         memset( ptr,0,size );
82
83         /* return pointer to allocated memory */
84         return ptr;
85 }
86
87 /* _pico_calloc:
88  *  _pico_calloc wrapper
89  */
90 void *_pico_calloc( size_t num, size_t size ){
91         void *ptr;
92
93         /* some sanity checks */
94         if ( num == 0 || size == 0 ) {
95                 return NULL;
96         }
97         if ( _pico_ptr_malloc == NULL ) {
98                 return NULL;
99         }
100
101         /* allocate memory */
102         ptr = _pico_ptr_malloc( num * size );
103         if ( ptr == NULL ) {
104                 return NULL;
105         }
106
107         /* zero out allocated memory */
108         memset( ptr,0,num * size );
109
110         /* return pointer to allocated memory */
111         return ptr;
112 }
113
114 /* _pico_realloc:
115  *  memory reallocation wrapper (note: only grows,
116  *  but never shrinks or frees)
117  */
118 void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ){
119         void *ptr2;
120
121         /* sanity checks */
122         if ( ptr == NULL ) {
123                 return NULL;
124         }
125         if ( newSize < oldSize ) {
126                 return *ptr;
127         }
128         if ( _pico_ptr_malloc == NULL ) {
129                 return NULL;
130         }
131
132         /* allocate new pointer */
133         ptr2 = _pico_alloc( newSize );
134         if ( ptr2 == NULL ) {
135                 return NULL;
136         }
137
138         /* copy */
139         if ( *ptr != NULL ) {
140                 memcpy( ptr2, *ptr, oldSize );
141                 _pico_free( *ptr );
142         }
143
144         /* fix up and return */
145         *ptr = ptr2;
146         return *ptr;
147 }
148
149 /* _pico_clone_alloc:
150  *  handy function for quick string allocation/copy. it clones
151  *  the given string and returns a pointer to the new allocated
152  *  clone (which must be freed by caller of course) or returns
153  *  NULL on memory alloc or param errors. if 'size' is -1 the
154  *  length of the input string is used, otherwise 'size' is used
155  *  as custom clone size (the string is cropped to fit into mem
156  *  if needed). -sea
157  */
158 char *_pico_clone_alloc( const char *str ){
159         char* cloned;
160
161         /* sanity check */
162         if ( str == NULL ) {
163                 return NULL;
164         }
165
166         /* allocate memory */
167         cloned = _pico_alloc( strlen( str ) + 1 );
168         if ( cloned == NULL ) {
169                 return NULL;
170         }
171
172         /* copy input string to cloned string */
173         strcpy( cloned, str );
174
175         /* return ptr to cloned string */
176         return cloned;
177 }
178
179 /* _pico_free:
180  * wrapper around the free function pointer
181  */
182 void _pico_free( void *ptr ){
183         /* sanity checks */
184         if ( ptr == NULL ) {
185                 return;
186         }
187         if ( _pico_ptr_free == NULL ) {
188                 return;
189         }
190
191         /* free the allocated memory */
192         _pico_ptr_free( ptr );
193 }
194
195 /* _pico_load_file:
196  * wrapper around the loadfile function pointer
197  */
198 void _pico_load_file( const char *name, unsigned char **buffer, int *bufSize ){
199         /* sanity checks */
200         if ( name == NULL ) {
201                 *bufSize = -1;
202                 return;
203         }
204         if ( _pico_ptr_load_file == NULL ) {
205                 *bufSize = -1;
206                 return;
207         }
208         /* do the actual call to read in the file; */
209         /* BUFFER IS ALLOCATED BY THE EXTERNAL LOADFILE FUNC */
210         _pico_ptr_load_file( name,buffer,bufSize );
211 }
212
213 /* _pico_free_file:
214  * wrapper around the file free function pointer
215  */
216 void _pico_free_file( void *buffer ){
217         /* sanity checks */
218         if ( buffer == NULL ) {
219                 return;
220         }
221
222         /* use default free */
223         if ( _pico_ptr_free_file == NULL ) {
224                 free( buffer );
225                 return;
226         }
227         /* free the allocated file */
228         _pico_ptr_free_file( buffer );
229 }
230
231 /* _pico_printf:
232  * wrapper around the print function pointer -sea
233  */
234 void _pico_printf( int level, const char *format, ... ){
235         char str[4096];
236         va_list argptr;
237
238         /* sanity checks */
239         if ( format == NULL ) {
240                 return;
241         }
242         if ( _pico_ptr_print == NULL ) {
243                 return;
244         }
245
246         /* format string */
247         va_start( argptr,format );
248         vsprintf( str,format,argptr );
249         va_end( argptr );
250
251         /* remove linefeeds */
252         if ( str[ strlen( str ) - 1 ] == '\n' ) {
253                 str[ strlen( str ) - 1 ] = '\0';
254         }
255
256         /* do the actual call */
257         _pico_ptr_print( level,str );
258 }
259
260 /* _pico_first_token:
261  * trims everything after the first whitespace-delimited token
262  */
263
264 void _pico_first_token( char *str ){
265         if ( !str || !*str ) {
266                 return;
267         }
268         while ( *str && !isspace( *str ) )
269                 str++;
270         *str = '\0';
271 }
272
273 /* _pico_strltrim:
274  * left trims the given string -sea
275  */
276 char *_pico_strltrim( char *str ){
277         char *str1 = str, *str2 = str;
278
279         while ( isspace( *str2 ) ) str2++;
280         if ( str2 != str ) {
281                 while ( *str2 != '\0' ) /* fix: ydnar */
282                         *str1++ = *str2++;
283         }
284         return str;
285 }
286
287 /* _pico_strrtrim:
288  * right trims the given string -sea
289  */
290 char *_pico_strrtrim( char *str ){
291         if ( str && *str ) {
292                 char *str1 = str;
293                 int allspace = 1;
294
295                 while ( *str1 )
296                 {
297                         if ( allspace && !isspace( *str1 ) ) {
298                                 allspace = 0;
299                         }
300                         str1++;
301                 }
302                 if ( allspace ) {
303                         *str = '\0';
304                 }
305                 else {
306                         str1--;
307                         while ( ( isspace( *str1 ) ) && ( str1 >= str ) )
308                                 *str1-- = '\0';
309                 }
310         }
311         return str;
312 }
313
314 /* _pico_strlwr:
315  *  pico internal string-to-lower routine.
316  */
317 char *_pico_strlwr( char *str ){
318         char *cp;
319         for ( cp = str; *cp; ++cp )
320         {
321                 if ( 'A' <= *cp && *cp <= 'Z' ) {
322                         *cp += ( 'a' - 'A' );
323                 }
324         }
325         return str;
326 }
327
328 /* _pico_strchcount:
329  *  counts how often the given char appears in str. -sea
330  */
331 int _pico_strchcount( char *str, int ch ){
332         int count = 0;
333         while ( *str++ ) if ( *str == ch ) {
334                         count++;
335                 }
336         return count;
337 }
338
339 void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ){
340         int i;
341         for ( i = 0; i < 3; i++ )
342         {
343                 mins[i] = +999999;
344                 maxs[i] = -999999;
345         }
346 }
347
348 void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ){
349         int i;
350         for ( i = 0; i < 3; i++ )
351         {
352                 float value = p[i];
353                 if ( value < mins[i] ) {
354                         mins[i] = value;
355                 }
356                 if ( value > maxs[i] ) {
357                         maxs[i] = value;
358                 }
359         }
360 }
361
362 void _pico_zero_vec( picoVec3_t vec ){
363         vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = 0;
364 }
365
366 void _pico_zero_vec2( picoVec2_t vec ){
367         vec[ 0 ] = vec[ 1 ] = 0;
368 }
369
370 void _pico_zero_vec4( picoVec4_t vec ){
371         vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = vec[ 3 ] = 0;
372 }
373
374 void _pico_set_vec( picoVec3_t v, float a, float b, float c ){
375         v[ 0 ] = a;
376         v[ 1 ] = b;
377         v[ 2 ] = c;
378 }
379
380 void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ){
381         v[ 0 ] = a;
382         v[ 1 ] = b;
383         v[ 2 ] = c;
384         v[ 3 ] = d;
385 }
386
387 void _pico_copy_vec( picoVec3_t src, picoVec3_t dest ){
388         dest[ 0 ] = src[ 0 ];
389         dest[ 1 ] = src[ 1 ];
390         dest[ 2 ] = src[ 2 ];
391 }
392
393 void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ){
394         dest[ 0 ] = src[ 0 ];
395         dest[ 1 ] = src[ 1 ];
396 }
397
398 void _pico_copy_vec4( picoVec4_t src, picoVec4_t dest ){
399         dest[ 0 ] = src[ 0 ];
400         dest[ 1 ] = src[ 1 ];
401         dest[ 2 ] = src[ 2 ];
402         dest[ 3 ] = src[ 3 ];
403 }
404
405 /* ydnar */
406 picoVec_t _pico_normalize_vec( picoVec3_t vec ){
407         double len, ilen;
408
409         len = sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] );
410         if ( len == 0.0 ) {
411                 return 0.0;
412         }
413         ilen = 1.0 / len;
414         vec[ 0 ] *= (picoVec_t) ilen;
415         vec[ 1 ] *= (picoVec_t) ilen;
416         vec[ 2 ] *= (picoVec_t) ilen;
417         return (picoVec_t) len;
418 }
419
420 void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ){
421         dest[ 0 ] = a[ 0 ] + b[ 0 ];
422         dest[ 1 ] = a[ 1 ] + b[ 1 ];
423         dest[ 2 ] = a[ 2 ] + b[ 2 ];
424 }
425
426 void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ){
427         dest[ 0 ] = a[ 0 ] - b[ 0 ];
428         dest[ 1 ] = a[ 1 ] - b[ 1 ];
429         dest[ 2 ] = a[ 2 ] - b[ 2 ];
430 }
431
432 void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest ){
433         dest[ 0 ] = v[ 0 ] * scale;
434         dest[ 1 ] = v[ 1 ] * scale;
435         dest[ 2 ] = v[ 2 ] * scale;
436 }
437
438 void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest ){
439         dest[ 0 ] = v[ 0 ] * scale;
440         dest[ 1 ] = v[ 1 ] * scale;
441         dest[ 2 ] = v[ 2 ] * scale;
442         dest[ 3 ] = v[ 3 ] * scale;
443 }
444
445 picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b ){
446         return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ];
447 }
448
449 void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ){
450         dest[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ];
451         dest[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ];
452         dest[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ];
453 }
454
455 picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ){
456         picoVec3_t ba, ca;
457
458         _pico_subtract_vec( b, a, ba );
459         _pico_subtract_vec( c, a, ca );
460         _pico_cross_vec( ca, ba, plane );
461         plane[ 3 ] = _pico_dot_vec( a, plane );
462         return _pico_normalize_vec( plane );
463 }
464
465 const picoColor_t picoColor_white = { 255, 255, 255, 255 };
466
467 /* separate from _pico_set_vec4 */
468 void _pico_set_color( picoColor_t c, int r, int g, int b, int a ){
469         c[ 0 ] = r;
470         c[ 1 ] = g;
471         c[ 2 ] = b;
472         c[ 3 ] = a;
473 }
474
475 void _pico_copy_color( const picoColor_t src, picoColor_t dest ){
476         dest[ 0 ] = src[ 0 ];
477         dest[ 1 ] = src[ 1 ];
478         dest[ 2 ] = src[ 2 ];
479         dest[ 3 ] = src[ 3 ];
480 }
481
482 #if GDEF_ARCH_ENDIAN_BIG
483
484 int   _pico_big_long( int src ) { return src; }
485 short _pico_big_short( short src ) { return src; }
486 float _pico_big_float( float src ) { return src; }
487
488 int _pico_little_long( int src ){
489         return ( ( src & 0xFF000000 ) >> 24 ) |
490                    ( ( src & 0x00FF0000 ) >> 8 ) |
491                    ( ( src & 0x0000FF00 ) << 8 ) |
492                    ( ( src & 0x000000FF ) << 24 );
493 }
494
495 short _pico_little_short( short src ){
496         return ( ( src & 0xFF00 ) >> 8 ) |
497                    ( ( src & 0x00FF ) << 8 );
498 }
499
500 float _pico_little_float( float src ){
501         floatSwapUnion in,out;
502         in.f = src;
503         out.c[ 0 ] = in.c[ 3 ];
504         out.c[ 1 ] = in.c[ 2 ];
505         out.c[ 2 ] = in.c[ 1 ];
506         out.c[ 3 ] = in.c[ 0 ];
507         return out.f;
508 }
509 #else /*__BIG_ENDIAN__*/
510
511 int   _pico_little_long( int src ) { return src; }
512 short _pico_little_short( short src ) { return src; }
513 float _pico_little_float( float src ) { return src; }
514
515 int _pico_big_long( int src ){
516         return ( ( src & 0xFF000000 ) >> 24 ) |
517                    ( ( src & 0x00FF0000 ) >> 8 ) |
518                    ( ( src & 0x0000FF00 ) << 8 ) |
519                    ( ( src & 0x000000FF ) << 24 );
520 }
521
522 short _pico_big_short( short src ){
523         return ( ( src & 0xFF00 ) >> 8 ) |
524                    ( ( src & 0x00FF ) << 8 );
525 }
526
527 float _pico_big_float( float src ){
528         floatSwapUnion in,out;
529         in.f = src;
530         out.c[ 0 ] = in.c[ 3 ];
531         out.c[ 1 ] = in.c[ 2 ];
532         out.c[ 2 ] = in.c[ 1 ];
533         out.c[ 3 ] = in.c[ 0 ];
534         return out.f;
535 }
536 #endif /*__BIG_ENDIAN__*/
537
538 /* _pico_stristr:
539  *  case-insensitive strstr. -sea
540  */
541 const char *_pico_stristr( const char *str, const char *substr ){
542         const size_t sublen = strlen( substr );
543         while ( *str )
544         {
545                 if ( !_pico_strnicmp( str,substr,sublen ) ) {
546                         break;
547                 }
548                 str++;
549         }
550         if ( !( *str ) ) {
551                 str = NULL;
552         }
553         return str;
554 }
555
556 /*
557    _pico_unixify()
558    changes dos \ style path separators to /
559  */
560
561 void _pico_unixify( char *path ){
562         if ( path == NULL ) {
563                 return;
564         }
565         while ( *path )
566         {
567                 if ( *path == '\\' ) {
568                         *path = '/';
569                 }
570                 path++;
571         }
572 }
573
574 /* _pico_nofname:
575  *  removes file name portion from given file path and converts
576  *  the directory separators to un*x style. returns 1 on success
577  *  or 0 when 'destSize' was exceeded. -sea
578  */
579 int _pico_nofname( const char *path, char *dest, int destSize ){
580         int left  = destSize;
581         char *temp  = dest;
582
583         while ( ( *dest = *path ) != '\0' )
584         {
585                 if ( *dest == '/' || *dest == '\\' ) {
586                         temp = ( dest + 1 );
587                         *dest = '/';
588                 }
589                 dest++; path++;
590
591                 if ( --left < 1 ) {
592                         *temp = '\0';
593                         return 0;
594                 }
595         }
596         *temp = '\0';
597         return 1;
598 }
599
600 /* _pico_nopath:
601  *  returns ptr to filename portion in given path or an empty
602  *  string otherwise. given 'path' is not altered. -sea
603  */
604 const char *_pico_nopath( const char *path ){
605         const char *src;
606         src = path + ( strlen( path ) - 1 );
607
608         if ( path == NULL ) {
609                 return "";
610         }
611         if ( !strchr( path,'/' ) && !strchr( path,'\\' ) ) {
612                 return ( path );
613         }
614
615         while ( ( src-- ) != path )
616         {
617                 if ( *src == '/' || *src == '\\' ) {
618                         return ( ++src );
619                 }
620         }
621         return "";
622 }
623
624 /* _pico_setfext:
625  *  sets/changes the file extension for the given filename
626  *  or filepath's filename portion. the given 'path' *is*
627  *  altered. leave 'ext' empty to remove extension. -sea
628  */
629 char *_pico_setfext( char *path, const char *ext ){
630         char *src;
631         int remfext = 0;
632
633         src = path + ( strlen( path ) - 1 );
634
635         if ( ext == NULL ) {
636                 ext = "";
637         }
638         if ( strlen( ext ) < 1 ) {
639                 remfext = 1;
640         }
641         if ( strlen( path ) < 1 ) {
642                 return path;
643         }
644
645         while ( ( src-- ) != path )
646         {
647                 if ( *src == '/' || *src == '\\' ) {
648                         return path;
649                 }
650
651                 if ( *src == '.' ) {
652                         if ( remfext ) {
653                                 *src = '\0';
654                                 return path;
655                         }
656                         *( ++src ) = '\0';
657                         break;
658                 }
659         }
660         strcat( path,ext );
661         return path;
662 }
663
664 /* _pico_getline:
665  *  extracts one line from the given buffer and stores it in dest.
666  *  returns -1 on error or the length of the line on success. i've
667  *  removed string trimming here. this can be done manually by the
668  *  calling func.
669  */
670 int _pico_getline( char *buf, int bufsize, char *dest, int destsize ){
671         int pos;
672
673         /* check output */
674         if ( dest == NULL || destsize < 1 ) {
675                 return -1;
676         }
677         memset( dest,0,destsize );
678
679         /* check input */
680         if ( buf == NULL || bufsize < 1 ) {
681                 return -1;
682         }
683
684         /* get next line */
685         for ( pos = 0; pos < bufsize && pos < destsize; pos++ )
686         {
687                 if ( buf[pos] == '\n' ) {
688                         pos++; break;
689                 }
690                 dest[pos] = buf[pos];
691         }
692         /* terminate dest and return */
693         dest[pos] = '\0';
694         return pos;
695 }
696
697 /* expecting fileName to be relative vfs model path */
698 void _pico_deduce_shadername( const char* fileName, const char* srcName, picoShader_t* shader ){
699         if( srcName == NULL || fileName == NULL )
700                 return;
701         char name[strlen( srcName ) + 1];
702         strcpy( name, srcName );
703         _pico_unixify( name );
704         _pico_setfext( name, NULL );
705
706         char path[strlen( fileName ) + strlen( name ) + 1];
707         _pico_nofname( fileName, path, strlen( fileName ) + strlen( name ) + 1 );
708         _pico_unixify( path );
709
710         if( !strchr( name , '/' ) ){ /* texture is likely in the folder, where model is */
711                 strcat( path, name );
712         }
713         else if( name[0] == '/' || ( name[0] != '\0' && name[1] == ':' ) || strstr( name, ".." ) ){ /* absolute path or with .. */
714                 const char* p = name;
715                 for (; *p != '\0'; ++p )
716                         if ( _pico_strnicmp( p, "/models/", 8 ) == 0 || _pico_strnicmp( p, "/textures/", 10 ) == 0 )
717                                 break;
718                 if( *p != '\0' ){
719                         strcpy( path, p + 1 );
720                 }
721                 else{
722                         p = _pico_nopath( name );
723                         strcat( path, p );
724                 }
725         }
726         else{
727                 PicoSetShaderName( shader, name );
728                 return;
729         }
730
731         _pico_printf( PICO_NORMAL, "PICO: substituting shader name: %s -> %s", srcName, path );
732         PicoSetShaderName( shader, path );
733 }
734
735 /* deduce shadernames from bitmap or shadername paths */
736 void _pico_deduce_shadernames( picoModel_t *model ){
737         for ( int i = 0; i < model->numShaders; ++i ){
738                 /* skip null shaders */
739                 if ( model->shader[i] == NULL )
740                         continue;
741
742                 const char* mapname = model->shader[i]->mapName;
743                 const char* shadername = model->shader[i]->name;
744                 if( mapname && *mapname )
745                         _pico_deduce_shadername( model->fileName, mapname, model->shader[i] );
746                 else if( shadername && *shadername )
747                         _pico_deduce_shadername( model->fileName, shadername, model->shader[i] );
748         }
749 }
750
751 /* _pico_parse_skip_white:
752  *  skips white spaces in current pico parser, sets *hasLFs
753  *  to 1 if linefeeds were skipped, and either returns the
754  *  parser's cursor pointer or NULL on error. -sea
755  */
756 void _pico_parse_skip_white( picoParser_t *p, int *hasLFs ){
757         /* sanity checks */
758         if ( p == NULL || p->cursor == NULL ) {
759                 return;
760         }
761
762         /* skin white spaces */
763         while ( 1 )
764         {
765                 /* sanity checks */
766                 if ( p->cursor <  p->buffer ||
767                          p->cursor >= p->max ) {
768                         return;
769                 }
770                 /* break for chars other than white spaces */
771                 if ( *p->cursor >  0x20 ) {
772                         break;
773                 }
774                 if ( *p->cursor == 0x00 ) {
775                         return;
776                 }
777
778                 /* a bit of linefeed handling */
779                 if ( *p->cursor == '\n' ) {
780                         *hasLFs = 1;
781                         p->curLine++;
782                 }
783                 /* go to next character */
784                 p->cursor++;
785         }
786 }
787
788 /* _pico_new_parser:
789  *  allocates a new ascii parser object.
790  */
791 picoParser_t *_pico_new_parser( const picoByte_t *buffer, int bufSize ){
792         picoParser_t *p;
793
794         /* sanity check */
795         if ( buffer == NULL || bufSize <= 0 ) {
796                 return NULL;
797         }
798
799         /* allocate reader */
800         p = _pico_alloc( sizeof( picoParser_t ) );
801         if ( p == NULL ) {
802                 return NULL;
803         }
804         memset( p,0,sizeof( picoParser_t ) );
805
806         /* allocate token space */
807         p->tokenSize = 0;
808         p->tokenMax = 1024;
809         p->token = _pico_alloc( p->tokenMax );
810         if ( p->token == NULL ) {
811                 _pico_free( p );
812                 return NULL;
813         }
814         /* setup */
815         p->buffer   = (const char *) buffer;
816         p->cursor   = p->buffer;
817         p->bufSize  = bufSize;
818         p->max      = p->buffer + bufSize;
819         p->curLine = 1; /* sea: new */
820
821         /* return ptr to parser */
822         return p;
823 }
824
825 /* _pico_free_parser:
826  *  frees an existing pico parser object.
827  */
828 void _pico_free_parser( picoParser_t *p ){
829         /* sanity check */
830         if ( p == NULL ) {
831                 return;
832         }
833
834         /* free the parser */
835         if ( p->token != NULL ) {
836                 _pico_free( p->token );
837         }
838         _pico_free( p );
839 }
840
841 /* _pico_parse_ex:
842  *  reads the next token from given pico parser object. if param
843  * 'allowLFs' is 1 it will read beyond linefeeds and return 0 when
844  *  the EOF is reached. if 'allowLFs' is 0 it will return 0 when
845  *  the EOL is reached. if 'handleQuoted' is 1 the parser function
846  *  will handle "quoted" strings and return the data between the
847  *  quotes as token. returns 0 on end/error or 1 on success. -sea
848  */
849 int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ){
850         int hasLFs = 0;
851         const char *old;
852
853         /* sanity checks */
854         if ( p == NULL || p->buffer == NULL ||
855                  p->cursor <  p->buffer ||
856                  p->cursor >= p->max ) {
857                 return 0;
858         }
859         /* clear parser token */
860         p->tokenSize = 0;
861         p->token[ 0 ] = '\0';
862         old = p->cursor;
863
864         /* skip whitespaces */
865         while ( p->cursor < p->max && *p->cursor <= 32 )
866         {
867                 if ( *p->cursor == '\n' ) {
868                         p->curLine++;
869                         hasLFs++;
870                 }
871                 p->cursor++;
872         }
873         /* return if we're not allowed to go beyond lfs */
874         if ( ( hasLFs > 0 ) && !allowLFs ) {
875                 p->cursor = old;
876                 return 0;
877         }
878         /* get next quoted string */
879         if ( *p->cursor == '\"' && handleQuoted ) {
880                 p->cursor++;
881                 while ( p->cursor < p->max && *p->cursor )
882                 {
883                         if ( *p->cursor == '\\' ) {
884                                 if ( *( p->cursor + 1 ) == '"' ) {
885                                         p->cursor++;
886                                 }
887                                 p->token[ p->tokenSize++ ] = *p->cursor++;
888                                 continue;
889                         }
890                         else if ( *p->cursor == '\"' ) {
891                                 p->cursor++;
892                                 break;
893                         }
894                         else if ( *p->cursor == '\n' ) {
895                                 p->curLine++;
896                         }
897                         p->token[ p->tokenSize++ ] = *p->cursor++;
898                 }
899                 /* terminate token */
900                 p->token[ p->tokenSize ] = '\0';
901                 return 1;
902         }
903         /* otherwise get next word */
904         while ( p->cursor < p->max && *p->cursor > 32 )
905         {
906                 if ( *p->cursor == '\n' ) {
907                         p->curLine++;
908                 }
909                 p->token[ p->tokenSize++ ] = *p->cursor++;
910         }
911         /* terminate token */
912         p->token[ p->tokenSize ] = '\0';
913         return 1;
914 }
915
916 /* _pico_parse_first:
917  *  reads the first token from the next line and returns
918  *  a pointer to it. returns NULL on EOL or EOF. -sea
919  */
920 char *_pico_parse_first( picoParser_t *p ){
921         /* sanity check */
922         if ( p == NULL ) {
923                 return NULL;
924         }
925
926         /* try to read next token (with lfs & quots) */
927         if ( !_pico_parse_ex( p,1,1 ) ) {
928                 return NULL;
929         }
930
931         /* return ptr to the token string */
932         return p->token;
933 }
934
935 /* _pico_parse:
936  *  reads the next token from the parser and returns a pointer
937  *  to it. quoted strings are handled as usual. returns NULL
938  *  on EOL or EOF. -sea
939  */
940 char *_pico_parse( picoParser_t *p, int allowLFs ){
941         /* sanity check */
942         if ( p == NULL ) {
943                 return NULL;
944         }
945
946         /* try to read next token (with quots) */
947         if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
948                 return NULL;
949         }
950
951         /* return ptr to the token string */
952         return p->token;
953 }
954
955 /* _pico_parse_skip_rest:
956  *  skips the rest of the current line in parser.
957  */
958 void _pico_parse_skip_rest( picoParser_t *p ){
959         while ( _pico_parse_ex( p,0,0 ) ) ;
960 }
961
962 /* _pico_parse_skip_braced:
963  *  parses/skips over a braced section. returns 1 on success
964  *  or 0 on error (when there was no closing bracket and the
965  *  end of buffer was reached or when the opening bracket was
966  *  missing).
967  */
968 int _pico_parse_skip_braced( picoParser_t *p ){
969         int firstToken = 1;
970         int level;
971
972         /* sanity check */
973         if ( p == NULL ) {
974                 return 0;
975         }
976
977         /* set the initial level for parsing */
978         level = 0;
979
980         /* skip braced section */
981         while ( 1 )
982         {
983                 /* read next token (lfs allowed) */
984                 if ( !_pico_parse_ex( p,1,1 ) ) {
985                         /* end of parser buffer reached */
986                         return 0;
987                 }
988                 /* first token must be an opening bracket */
989                 if ( firstToken && p->token[0] != '{' ) {
990                         /* opening bracket missing */
991                         return 0;
992                 }
993                 /* we only check this once */
994                 firstToken = 0;
995
996                 /* update level */
997                 if ( p->token[1] == '\0' ) {
998                         if ( p->token[0] == '{' ) {
999                                 level++;
1000                         }
1001                         if ( p->token[0] == '}' ) {
1002                                 level--;
1003                         }
1004                 }
1005                 /* break if we're back at our starting level */
1006                 if ( level == 0 ) {
1007                         break;
1008                 }
1009         }
1010         /* successfully skipped braced section */
1011         return 1;
1012 }
1013
1014 int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ){
1015         if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
1016                 return 0;
1017         }
1018         if ( !strcmp( p->token,str ) ) {
1019                 return 1;
1020         }
1021         return 0;
1022 }
1023
1024 int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ){
1025         if ( !_pico_parse_ex( p,allowLFs,1 ) ) {
1026                 return 0;
1027         }
1028         if ( !_pico_stricmp( p->token,str ) ) {
1029                 return 1;
1030         }
1031         return 0;
1032 }
1033
1034 int _pico_parse_int( picoParser_t *p, int *out ){
1035         char *token;
1036
1037         /* sanity checks */
1038         if ( p == NULL || out == NULL ) {
1039                 return 0;
1040         }
1041
1042         /* get token and turn it into an integer */
1043         *out = 0;
1044         token = _pico_parse( p,0 );
1045         if ( token == NULL ) {
1046                 return 0;
1047         }
1048         *out = atoi( token );
1049
1050         /* success */
1051         return 1;
1052 }
1053
1054 int _pico_parse_int_def( picoParser_t *p, int *out, int def ){
1055         char *token;
1056
1057         /* sanity checks */
1058         if ( p == NULL || out == NULL ) {
1059                 return 0;
1060         }
1061
1062         /* get token and turn it into an integer */
1063         *out = def;
1064         token = _pico_parse( p,0 );
1065         if ( token == NULL ) {
1066                 return 0;
1067         }
1068         *out = atoi( token );
1069
1070         /* success */
1071         return 1;
1072 }
1073
1074 int _pico_parse_float( picoParser_t *p, float *out ){
1075         char *token;
1076
1077         /* sanity checks */
1078         if ( p == NULL || out == NULL ) {
1079                 return 0;
1080         }
1081
1082         /* get token and turn it into a float */
1083         *out = 0.0f;
1084         token = _pico_parse( p,0 );
1085         if ( token == NULL ) {
1086                 return 0;
1087         }
1088         *out = (float) atof( token );
1089
1090         /* success */
1091         return 1;
1092 }
1093
1094 int _pico_parse_float_def( picoParser_t *p, float *out, float def ){
1095         char *token;
1096
1097         /* sanity checks */
1098         if ( p == NULL || out == NULL ) {
1099                 return 0;
1100         }
1101
1102         /* get token and turn it into a float */
1103         *out = def;
1104         token = _pico_parse( p,0 );
1105         if ( token == NULL ) {
1106                 return 0;
1107         }
1108         *out = (float) atof( token );
1109
1110         /* success */
1111         return 1;
1112 }
1113
1114 int _pico_parse_vec( picoParser_t *p, picoVec3_t out ){
1115         char *token;
1116         int i;
1117
1118         /* sanity checks */
1119         if ( p == NULL || out == NULL ) {
1120                 return 0;
1121         }
1122
1123         /* zero out outination vector */
1124         _pico_zero_vec( out );
1125
1126         /* parse three vector components */
1127         for ( i = 0; i < 3; i++ )
1128         {
1129                 token = _pico_parse( p,0 );
1130                 if ( token == NULL ) {
1131                         _pico_zero_vec( out );
1132                         return 0;
1133                 }
1134                 out[ i ] = (float) atof( token );
1135         }
1136         /* success */
1137         return 1;
1138 }
1139
1140 int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def ){
1141         char *token;
1142         int i;
1143
1144         /* sanity checks */
1145         if ( p == NULL || out == NULL ) {
1146                 return 0;
1147         }
1148
1149         /* assign default vector value */
1150         _pico_copy_vec( def,out );
1151
1152         /* parse three vector components */
1153         for ( i = 0; i < 3; i++ )
1154         {
1155                 token = _pico_parse( p,0 );
1156                 if ( token == NULL ) {
1157                         _pico_copy_vec( def,out );
1158                         return 0;
1159                 }
1160                 out[ i ] = (float) atof( token );
1161         }
1162         /* success */
1163         return 1;
1164 }
1165
1166 int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ){
1167         char *token;
1168         int i;
1169
1170         /* sanity checks */
1171         if ( p == NULL || out == NULL ) {
1172                 return 0;
1173         }
1174
1175         /* zero out outination vector */
1176         _pico_zero_vec2( out );
1177
1178         /* parse two vector components */
1179         for ( i = 0; i < 2; i++ )
1180         {
1181                 token = _pico_parse( p,0 );
1182                 if ( token == NULL ) {
1183                         _pico_zero_vec2( out );
1184                         return 0;
1185                 }
1186                 out[ i ] = (float) atof( token );
1187         }
1188         /* success */
1189         return 1;
1190 }
1191
1192 int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ){
1193         char *token;
1194         int i;
1195
1196         /* sanity checks */
1197         if ( p == NULL || out == NULL ) {
1198                 return 0;
1199         }
1200
1201         /* assign default vector value */
1202         _pico_copy_vec2( def,out );
1203
1204         /* parse two vector components */
1205         for ( i = 0; i < 2; i++ )
1206         {
1207                 token = _pico_parse( p,0 );
1208                 if ( token == NULL ) {
1209                         _pico_copy_vec2( def,out );
1210                         return 0;
1211                 }
1212                 out[ i ] = (float) atof( token );
1213         }
1214         /* success */
1215         return 1;
1216 }
1217
1218 int _pico_parse_vec4( picoParser_t *p, picoVec4_t out ){
1219         char *token;
1220         int i;
1221
1222         /* sanity checks */
1223         if ( p == NULL || out == NULL ) {
1224                 return 0;
1225         }
1226
1227         /* zero out outination vector */
1228         _pico_zero_vec4( out );
1229
1230         /* parse four vector components */
1231         for ( i = 0; i < 4; i++ )
1232         {
1233                 token = _pico_parse( p,0 );
1234                 if ( token == NULL ) {
1235                         _pico_zero_vec4( out );
1236                         return 0;
1237                 }
1238                 out[ i ] = (float) atof( token );
1239         }
1240         /* success */
1241         return 1;
1242 }
1243
1244 int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def ){
1245         char *token;
1246         int i;
1247
1248         /* sanity checks */
1249         if ( p == NULL || out == NULL ) {
1250                 return 0;
1251         }
1252
1253         /* assign default vector value */
1254         _pico_copy_vec4( def,out );
1255
1256         /* parse four vector components */
1257         for ( i = 0; i < 4; i++ )
1258         {
1259                 token = _pico_parse( p,0 );
1260                 if ( token == NULL ) {
1261                         _pico_copy_vec4( def,out );
1262                         return 0;
1263                 }
1264                 out[ i ] = (float) atof( token );
1265         }
1266         /* success */
1267         return 1;
1268 }
1269
1270 /* _pico_new_memstream:
1271  *  allocates a new memorystream object.
1272  */
1273 picoMemStream_t *_pico_new_memstream( const picoByte_t *buffer, int bufSize ){
1274         picoMemStream_t *s;
1275
1276         /* sanity check */
1277         if ( buffer == NULL || bufSize <= 0 ) {
1278                 return NULL;
1279         }
1280
1281         /* allocate stream */
1282         s = _pico_alloc( sizeof( picoMemStream_t ) );
1283         if ( s == NULL ) {
1284                 return NULL;
1285         }
1286         memset( s,0,sizeof( picoMemStream_t ) );
1287
1288         /* setup */
1289         s->buffer   = buffer;
1290         s->curPos   = buffer;
1291         s->bufSize  = bufSize;
1292         s->flag     = 0;
1293
1294         /* return ptr to stream */
1295         return s;
1296 }
1297
1298 /* _pico_free_memstream:
1299  *  frees an existing pico memorystream object.
1300  */
1301 void _pico_free_memstream( picoMemStream_t *s ){
1302         /* sanity check */
1303         if ( s == NULL ) {
1304                 return;
1305         }
1306
1307         /* free the stream */
1308         _pico_free( s );
1309 }
1310
1311 /* _pico_memstream_read:
1312  *  reads data from a pico memorystream into a buffer.
1313  */
1314 int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ){
1315         int ret = 1;
1316
1317         /* sanity checks */
1318         if ( s == NULL || buffer == NULL ) {
1319                 return 0;
1320         }
1321
1322         if ( s->curPos + len > s->buffer + s->bufSize ) {
1323                 s->flag |= PICO_IOEOF;
1324                 len = s->buffer + s->bufSize - s->curPos;
1325                 ret = 0;
1326         }
1327
1328         /* read the data */
1329         memcpy( buffer, s->curPos, len );
1330         s->curPos += len;
1331         return ret;
1332 }
1333
1334 /* _pico_memstream_read:
1335  *  reads a character from a pico memorystream
1336  */
1337 int _pico_memstream_getc( picoMemStream_t *s ){
1338         int c = 0;
1339
1340         /* sanity check */
1341         if ( s == NULL ) {
1342                 return -1;
1343         }
1344
1345         /* read the character */
1346         if ( _pico_memstream_read( s, &c, 1 ) == 0 ) {
1347                 return -1;
1348         }
1349
1350         return c;
1351 }
1352
1353 /* _pico_memstream_seek:
1354  *  sets the current read position to a different location
1355  */
1356 int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ){
1357         int overflow;
1358
1359         /* sanity check */
1360         if ( s == NULL ) {
1361                 return -1;
1362         }
1363
1364         if ( origin == PICO_SEEK_SET ) {
1365                 s->curPos = s->buffer + offset;
1366                 overflow = s->curPos - ( s->buffer + s->bufSize );
1367                 if ( overflow > 0 ) {
1368                         s->curPos = s->buffer + s->bufSize;
1369                         return offset - overflow;
1370                 }
1371                 return 0;
1372         }
1373         else if ( origin == PICO_SEEK_CUR ) {
1374                 s->curPos += offset;
1375                 overflow = s->curPos - ( s->buffer + s->bufSize );
1376                 if ( overflow > 0 ) {
1377                         s->curPos = s->buffer + s->bufSize;
1378                         return offset - overflow;
1379                 }
1380                 return 0;
1381         }
1382         else if ( origin == PICO_SEEK_END ) {
1383                 s->curPos = ( s->buffer + s->bufSize ) - offset;
1384                 overflow = s->buffer - s->curPos;
1385                 if ( overflow > 0 ) {
1386                         s->curPos = s->buffer;
1387                         return offset - overflow;
1388                 }
1389                 return 0;
1390         }
1391
1392         return -1;
1393 }
1394
1395 /* _pico_memstream_tell:
1396  *  returns the current read position in the pico memorystream
1397  */
1398 long _pico_memstream_tell( picoMemStream_t *s ){
1399         /* sanity check */
1400         if ( s == NULL ) {
1401                 return -1;
1402         }
1403
1404         return s->curPos - s->buffer;
1405 }