root/GtkRadiant/trunk/libs/picomodel/pm_ase.c

Revision 277, 25.7 kB (checked in by mattn, 3 months ago)

* fixed warning

  • Property svn:eol-style set to native
Line 
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 aseMaterialList 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 /* marker */
37 #define PM_ASE_C
38
39 /* uncomment when debugging this module */
40 //#define DEBUG_PM_ASE
41 //#define DEBUG_PM_ASE_EX
42
43
44 /* dependencies */
45 #include "picointernal.h"
46
47 #ifdef DEBUG_PM_ASE
48 #include "time.h"
49 #endif
50
51 /* plain white */
52 static picoColor_t white = { 255, 255, 255, 255 };
53
54 /* jhefty - multi-subobject material support */
55
56 /* Material/SubMaterial management */
57 /* A material should have 1..n submaterials assigned to it */
58
59 typedef struct aseSubMaterial_s
60 {
61         struct aseSubMaterial_s* next;
62         int subMtlId;
63         picoShader_t* shader;
64
65 } aseSubMaterial_t;
66
67 typedef struct aseMaterial_s
68 {
69         struct aseMaterial_s* next;
70         struct aseSubMaterial_s* subMtls;
71         int mtlId;
72 } aseMaterial_t;
73
74 /* Material/SubMaterial management functions */
75 static aseMaterial_t* _ase_get_material ( aseMaterial_t* list , int mtlIdParent )
76 {
77         aseMaterial_t* mtl = list;
78
79         while ( mtl )
80         {
81                 if ( mtlIdParent == mtl->mtlId )
82                 {
83                         break;
84                 }
85                 mtl = mtl->next;
86         }
87         return mtl;
88 }
89
90 static aseSubMaterial_t* _ase_get_submaterial ( aseMaterial_t* list, int  mtlIdParent , int subMtlId )
91 {
92         aseMaterial_t* parent = _ase_get_material ( list , mtlIdParent );
93         aseSubMaterial_t* subMtl = NULL;
94
95         if ( !parent )
96         {
97                 _pico_printf ( PICO_ERROR , "No ASE material exists with id %i\n" , mtlIdParent );
98                 return NULL;
99         }
100
101         subMtl = parent->subMtls;
102         while ( subMtl )
103         {
104                 if ( subMtlId == subMtl->subMtlId )
105                 {
106                         break;
107                 }
108                 subMtl = subMtl->next;
109         }
110         return subMtl;
111 }
112
113 static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent )
114 {
115         aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) );
116         mtl->mtlId = mtlIdParent;
117         mtl->subMtls = NULL;
118         mtl->next = *list;
119         *list = mtl;
120
121         return mtl;
122 }
123
124 static aseSubMaterial_t* _ase_add_submaterial( aseMaterial_t **list, int mtlIdParent, int subMtlId, picoShader_t* shader )
125 {
126         aseMaterial_t *parent = _ase_get_material( *list,  mtlIdParent );
127         aseSubMaterial_t *subMtl = _pico_calloc( 1, sizeof ( aseSubMaterial_t ) );
128
129         if ( !parent )
130         {
131                 parent = _ase_add_material ( list , mtlIdParent );
132         }
133
134         subMtl->shader = shader;
135         subMtl->subMtlId = subMtlId;
136         subMtl->next = parent->subMtls;
137         parent->subMtls = subMtl;
138
139         return subMtl;
140 }
141
142 static void _ase_free_materials( aseMaterial_t **list )
143 {
144         aseMaterial_t* mtl = *list;
145         aseSubMaterial_t* subMtl = NULL;
146
147         aseMaterial_t* mtlTemp = NULL;
148         aseSubMaterial_t* subMtlTemp = NULL;
149
150         while ( mtl )
151         {
152                 subMtl = mtl->subMtls;
153                 while ( subMtl )
154                 {
155                         subMtlTemp = subMtl->next;
156                         _pico_free ( subMtl );
157                         subMtl = subMtlTemp;
158                 }
159                 mtlTemp = mtl->next;
160                 _pico_free ( mtl );
161                 mtl = mtlTemp;
162         }
163         (*list) = NULL;
164 }
165
166 #ifdef DEBUG_PM_ASE
167 static void _ase_print_materials( aseMaterial_t *list )
168 {
169         aseMaterial_t* mtl = list;
170         aseSubMaterial_t* subMtl = NULL;
171
172         while ( mtl )
173         {
174                 _pico_printf ( PICO_NORMAL ,  "ASE Material %i" , mtl->mtlId );
175                 subMtl = mtl->subMtls;
176                 while ( subMtl )
177                 {
178                         _pico_printf ( PICO_NORMAL ,  " -- ASE SubMaterial %i - %s\n" , subMtl->subMtlId , subMtl->shader->name );
179                         subMtl = subMtl->next;
180                 }
181                 mtl = mtl->next;
182         }
183 }
184 #endif //DEBUG_PM_ASE
185
186 /* ASE Face management */
187 /* These are used to keep an association between a submaterial and a face definition */
188 /* They are kept in parallel with the current picoSurface, */
189 /* and are used by _ase_submit_triangles to lookup the proper material/submaterial IDs */
190 typedef struct aseFace_s
191 {
192         struct aseFace_s* next;
193         int mtlId;
194         int subMtlId;
195         int index[9];
196 } aseFace_t;
197
198 /* ASE Face management functions */
199 void _ase_add_face( aseFace_t **list, aseFace_t **tail, aseFace_t *newFace )
200 {
201         /* insert as head of list */
202         if ( !(*list) )
203         {
204                 *list = newFace;
205         }
206         else
207         {
208                 (*tail)->next = newFace;
209         }
210
211         *tail = newFace;
212         newFace->next = NULL;
213
214         //tag the color indices so we can detect them and apply the default color to them
215         newFace->index[6] = -1;
216         newFace->index[7] = -1;
217         newFace->index[8] = -1;
218 }
219
220 aseFace_t* _ase_get_face_for_index( aseFace_t *list, int index )
221 {
222         int counter = 0;
223         aseFace_t* face = list;
224
225         while ( counter < index )
226         {
227                 face = face->next;
228                 counter++;
229         }
230         return face;
231 }
232 static void _ase_free_faces (aseFace_t** list, aseFace_t** tail )
233 {
234         aseFace_t* face = *list;
235         aseFace_t* tempFace = NULL;
236
237         while ( face )
238         {
239                 tempFace = face->next;
240                 _pico_free ( face );
241                 face = tempFace;
242         }
243
244         (*list) = NULL;
245         (*tail) = NULL;
246 }
247
248 /* todo:
249  * - apply material specific uv offsets to uv coordinates
250  */
251
252 /* _ase_canload:
253  *  validates a 3dsmax ase model file.
254  */
255 static int _ase_canload( PM_PARAMS_CANLOAD )
256 {
257         picoParser_t *p;
258
259
260         /* quick data length validation */
261         if( bufSize < 80 )
262                 return PICO_PMV_ERROR_SIZE;
263
264         /* keep the friggin compiler happy */
265         *fileName = *fileName;
266
267         /* create pico parser */
268         p = _pico_new_parser( (picoByte_t*) buffer, bufSize );
269         if( p == NULL )
270                 return PICO_PMV_ERROR_MEMORY;
271
272         /* get first token */
273         if( _pico_parse_first( p ) == NULL)
274         {
275                 return PICO_PMV_ERROR_IDENT;
276         }
277
278         /* check first token */
279         if( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) )
280         {
281                 _pico_free_parser( p );
282                 return PICO_PMV_ERROR_IDENT;
283         }
284
285         /* free the pico parser object */
286         _pico_free_parser( p );
287
288         /* file seems to be a valid ase file */
289         return PICO_PMV_OK;
290 }
291
292
293
294 /* _ase_submit_triangles - jhefty
295  use the surface and the current face list to look up material/submaterial IDs
296  and submit them to the model for proper processing
297
298 The following still holds from ydnar's _ase_make_surface:
299  indexes 0 1 2 = vert indexes
300  indexes 3 4 5 = st indexes
301  indexes 6 7 8 = color indexes (new)
302 */
303
304 static void _ase_submit_triangles ( picoSurface_t* surface , picoModel_t* model , aseMaterial_t* materials , aseFace_t* faces )
305 {
306         aseFace_t* face;
307         aseSubMaterial_t* subMtl;
308         picoVec3_t* xyz[3];
309         picoVec3_t* normal[3];
310         picoVec2_t* st[3];
311         picoColor_t* color[3];
312         int i;
313
314         face = faces;
315         while ( face != NULL )
316         {
317                 /* look up the shader for the material/submaterial pair */
318                 subMtl = _ase_get_submaterial( materials, face->mtlId, face->subMtlId );
319                 if( subMtl == NULL )
320                 {
321                         /* ydnar: trying default submaterial */
322                         subMtl = _ase_get_submaterial( materials, face->mtlId, 0 );
323                         if( subMtl == NULL )
324                         {
325                                 _pico_printf( PICO_ERROR, "Could not find material/submaterial for id %d/%d\n", face->mtlId, face->subMtlId );
326                                 return;
327                         }
328                 }
329
330                 /* we pull the data from the surface using the facelist data */
331                 for ( i = 0 ; i < 3 ; i ++ )
332                 {
333                         xyz[i]    = (picoVec3_t*) PicoGetSurfaceXYZ   ( surface, face->index[ i ] );
334                         normal[i] = (picoVec3_t*) PicoGetSurfaceNormal( surface, face->index[ i ] );
335                         st[i]     = (picoVec2_t*) PicoGetSurfaceST    ( surface, 0, face->index[ i + 3 ] );
336
337                         if ( face->index [ i + 6] >= 0 )
338                         {
339                                 color[i]  = (picoColor_t*)PicoGetSurfaceColor ( surface, 0, face->index[ i + 6 ] );
340                         }
341                         else
342                         {
343                                 color[i] = &white;
344                         }
345
346                 }
347
348                 /* submit the triangle to the model */
349                 PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader );
350
351                 /* advance to the next face */
352                 face = face->next;
353         }
354 }
355
356 /* _ase_load:
357  *  loads a 3dsmax ase model file.
358 */
359 static picoModel_t *_ase_load( PM_PARAMS_LOAD )
360 {
361         picoModel_t    *model;
362         picoSurface_t  *surface = NULL;
363         picoParser_t   *p;
364         char                    lastNodeName[ 1024 ];
365
366         aseFace_t* faces = NULL;
367         aseFace_t* facesTail = NULL;
368         aseMaterial_t* materials = NULL;
369
370 #ifdef DEBUG_PM_ASE
371         clock_t start, finish;
372         double elapsed;
373         start = clock();
374 #endif
375
376         /* helper */
377         #define _ase_error_return(m) \
378         { \
379                 _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine); \
380                 _pico_free_parser( p ); \
381                 PicoFreeModel( model ); \
382                 return NULL; \
383         }
384         /* create a new pico parser */
385         p = _pico_new_parser( (picoByte_t *)buffer,bufSize );
386         if (p == NULL) return NULL;
387
388         /* create a new pico model */
389         model = PicoNewModel();
390         if (model == NULL)
391         {
392                 _pico_free_parser( p );
393                 return NULL;
394         }
395         /* do model setup */
396         PicoSetModelFrameNum( model, frameNum );
397         PicoSetModelName( model, fileName );
398         PicoSetModelFileName( model, fileName );
399
400         /* initialize some stuff */
401         memset( lastNodeName,0,sizeof(lastNodeName) );
402
403         /* parse ase model file */
404         while( 1 )
405         {
406                 /* get first token on line */
407                 if (_pico_parse_first( p ) == NULL)
408                         break;
409
410                 /* we just skip empty lines */
411                 if (p->token == NULL || !strlen( p->token ))
412                         continue;
413
414                 /* we skip invalid ase statements */
415                 if (p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}')
416                 {
417                         _pico_parse_skip_rest( p );
418                         continue;
419                 }
420                 /* remember node name */
421                 if (!_pico_stricmp(p->token,"*node_name"))
422                 {
423                         /* read node name */
424                         char *ptr = _pico_parse( p,0 );
425                         if (ptr == NULL)
426                                 _ase_error_return("Node name parse error");
427
428                         /* remember node name */
429                         strncpy( lastNodeName,ptr,sizeof(lastNodeName) );
430                 }
431                 /* model mesh (originally contained within geomobject) */
432                 else if (!_pico_stricmp(p->token,"*mesh"))
433                 {
434                         /* finish existing surface */
435                         //_ase_make_surface( model, &surface );
436                         _ase_submit_triangles (surface, model ,materials,faces);
437                         _ase_free_faces (&faces,&facesTail);
438
439                         /* allocate new pico surface */
440                         surface = PicoNewSurface( NULL );
441                         if (surface == NULL)
442                         {
443                                 PicoFreeModel( model );
444                                 return NULL;
445                         }
446                 }
447                 /* mesh material reference. this usually comes at the end of */
448                 /* geomobjects after the mesh blocks. we must assume that the */
449                 /* new mesh was already created so all we can do here is assign */
450                 /* the material reference id (shader index) now. */
451                 else if (!_pico_stricmp(p->token,"*material_ref"))
452                 {
453                         int mtlId;
454                         aseFace_t* face;
455
456                         /* we must have a valid surface */
457                         if( surface == NULL )
458                                 _ase_error_return("Missing mesh for material reference");
459
460                         /* get the material ref (0..n) */
461                         if (!_pico_parse_int( p,&mtlId) )
462                                 _ase_error_return("Missing material reference ID");
463
464                         /* fix up all of the aseFaceList in the surface to point to the parent material */
465                         /* we've already saved off their subMtl */
466                         face = faces;
467                         while ( face != NULL )
468                         {
469                                 face->mtlId = mtlId;
470                                 face = face->next;
471                         }
472                 }
473                 /* model mesh vertex */
474                 else if (!_pico_stricmp(p->token,"*mesh_vertex"))
475                 {
476                         picoVec3_t      v;
477                         int                     index;
478
479                         /* we must have a valid surface */
480                         if( surface == NULL )
481                                 continue;
482
483                         /* get vertex data (orig: index +y -x +z) */
484                         if (!_pico_parse_int( p,&index ))
485                                 _ase_error_return("Vertex parse error");
486                         if (!_pico_parse_vec( p,v ))
487                                 _ase_error_return("Vertex parse error");
488
489                         /* set vertex */
490                         PicoSetSurfaceXYZ( surface,index,v );
491                 }
492                 /* model mesh vertex normal */
493                 else if (!_pico_stricmp(p->token,"*mesh_vertexnormal"))
494                 {
495                         picoVec3_t      v;
496                         int                     index;
497
498                         /* we must have a valid surface */
499                         if( surface == NULL )
500                                 continue;
501
502                         /* get vertex data (orig: index +y -x +z) */
503                         if (!_pico_parse_int( p,&index ))
504                                 _ase_error_return("Vertex parse error");
505                         if (!_pico_parse_vec( p,v ))
506                                 _ase_error_return("Vertex parse error");
507
508                         /* set vertex */
509                         PicoSetSurfaceNormal( surface,index,v );
510                 }
511                 /* model mesh face */
512                 else if (!_pico_stricmp(p->token,"*mesh_face"))
513                 {
514                         picoIndex_t indexes[3];
515                         int                     index;
516
517                         /* we must have a valid surface */
518                         if( surface == NULL )
519                                 continue;
520
521                         /* get face index */
522                         if (!_pico_parse_int( p,&index ))
523                                 _ase_error_return("Face parse error");
524
525                         /* get 1st vertex index */
526                         _pico_parse( p,0 );
527                         if (!_pico_parse_int( p,&indexes[0] ))
528                                 _ase_error_return("Face parse error");
529
530                         /* get 2nd vertex index */
531                         _pico_parse( p,0 );
532                         if (!_pico_parse_int( p,&indexes[1] ))
533                                 _ase_error_return("Face parse error");
534
535                         /* get 3rd vertex index */
536                         _pico_parse( p,0 );
537                         if (!_pico_parse_int( p,&indexes[2] ))
538                                 _ase_error_return("Face parse error");
539
540                         /* set face indexes (note interleaved offset!) */
541                         PicoSetSurfaceIndex( surface, (index * 9 + 0), indexes[2] );
542                         PicoSetSurfaceIndex( surface, (index * 9 + 1), indexes[1] );
543                         PicoSetSurfaceIndex( surface, (index * 9 + 2), indexes[0] );
544
545                         /* parse to the subMaterial ID */
546                         while ( 1 )
547                         {
548                                 _pico_parse (p,0);
549                                 if (!_pico_stricmp (p->token,"*MESH_MTLID" ))
550                                 {
551                                         aseFace_t* newFace;
552                                         int subMtlId;
553
554                                         _pico_parse_int ( p , &subMtlId );
555                                         newFace = _pico_calloc ( 1 , sizeof ( aseFace_t ));
556
557                                         /* we fix up the mtlId later when we parse the material_ref */
558                                         newFace->mtlId = 0;
559                                         newFace->subMtlId = subMtlId;
560                                         newFace->index[0] = indexes[2];
561                                         newFace->index[1] = indexes[1];
562                                         newFace->index[2] = indexes[0];
563
564                                         _ase_add_face ( &faces,&facesTail,newFace );
565                                         break;
566                                 }
567                         }
568
569                 }
570                 /* model texture vertex */
571                 else if (!_pico_stricmp(p->token,"*mesh_tvert"))
572                 {
573                         picoVec2_t      uv;
574                         int                     index;
575
576                         /* we must have a valid surface */
577                         if( surface == NULL )
578                                 continue;
579
580                         /* get uv vertex index */
581                         if (!_pico_parse_int( p,&index ))
582                                 _ase_error_return("UV vertex parse error");
583
584                         /* get uv vertex s */
585                         if (!_pico_parse_float( p,&uv[0] ))
586                                 _ase_error_return("UV vertex parse error");
587
588                         /* get uv vertex t */
589                         if (!_pico_parse_float( p,&uv[1] ))
590                                 _ase_error_return("UV vertex parse error");
591
592                         /* ydnar: invert t */
593                         uv[ 1 ] = 1.0f - uv[ 1 ];
594
595                         /* set texture vertex */
596                         PicoSetSurfaceST( surface,0,index,uv );
597                 }
598                 /* ydnar: model mesh texture face */
599                 else if( !_pico_stricmp( p->token, "*mesh_tface" ) )
600                 {
601                         picoIndex_t indexes[3];
602                         int                     index;
603                         aseFace_t* face;
604
605                         /* we must have a valid surface */
606                         if( surface == NULL )
607                                 continue;
608
609                         /* get face index */
610                         if (!_pico_parse_int( p,&index ))
611                                 _ase_error_return("Texture face parse error");
612
613                         /* get 1st vertex index */
614                         if (!_pico_parse_int( p,&indexes[0] ))
615                                 _ase_error_return("Texture face parse error");
616
617                         /* get 2nd vertex index */
618                         if (!_pico_parse_int( p,&indexes[1] ))
619                                 _ase_error_return("Texture face parse error");
620
621                         /* get 3rd vertex index */
622                         if (!_pico_parse_int( p,&indexes[2] ))
623                                 _ase_error_return("Texture face parse error");
624
625                         /* set face indexes (note interleaved offset!) */
626                         PicoSetSurfaceIndex( surface, (index * 9 + 3), indexes[2] );
627                         PicoSetSurfaceIndex( surface, (index * 9 + 4), indexes[1] );
628                         PicoSetSurfaceIndex( surface, (index * 9 + 5), indexes[0] );
629
630                         face = _ase_get_face_for_index(faces,index);
631                         face->index[3] = indexes[2];
632                         face->index[4] = indexes[1];
633                         face->index[5] = indexes[0];
634                 }
635                 /* model color vertex */
636                 else if (!_pico_stricmp(p->token,"*mesh_vertcol"))
637                 {
638                         picoColor_t     color;
639                         int                     index;
640                         float           colorInput;
641
642                         /* we must have a valid surface */
643                         if( surface == NULL )
644                                 continue;
645
646                         /* get color vertex index */
647                         if (!_pico_parse_int( p,&index ))
648                                 _ase_error_return("UV vertex parse error");
649
650                         /* get R component */
651                         if (!_pico_parse_float( p,&colorInput ))
652                                 _ase_error_return("color vertex parse error");
653                         color[0] = (picoByte_t)(colorInput * 255);
654
655                         /* get G component */
656                         if (!_pico_parse_float( p,&colorInput ))
657                                 _ase_error_return("color vertex parse error");
658                         color[1] = (picoByte_t)(colorInput * 255);
659
660                         /* get B component */
661                         if (!_pico_parse_float( p,&colorInput ))
662                                 _ase_error_return("color vertex parse error");
663                         color[2] = (picoByte_t)(colorInput * 255);
664
665                         /* leave alpha alone since we don't get any data from the ASE format */
666                         color[3] = 255;
667
668                         /* set texture vertex */
669                         PicoSetSurfaceColor( surface,0,index,color );
670                 }
671                 /* model color face */
672                 else if (!_pico_stricmp(p->token,"*mesh_cface"))
673                 {
674                         picoIndex_t indexes[3];
675                         int                     index;
676                         aseFace_t*  face;
677
678                         /* we must have a valid surface */
679                         if( surface == NULL )
680                                 continue;
681
682                         /* get face index */
683                         if (!_pico_parse_int( p,&index ))
684                                 _ase_error_return("Face parse error");
685
686                         /* get 1st cvertex index */
687                         //                      _pico_parse( p,0 );
688                         if (!_pico_parse_int( p,&indexes[0] ))
689                                 _ase_error_return("Face parse error");
690
691                         /* get 2nd cvertex index */
692                         //                      _pico_parse( p,0 );
693                         if (!_pico_parse_int( p,&indexes[1] ))
694                                 _ase_error_return("Face parse error");
695
696                         /* get 3rd cvertex index */
697                         //                      _pico_parse( p,0 );
698                         if (!_pico_parse_int( p,&indexes[2] ))
699                                 _ase_error_return("Face parse error");
700
701                         /* set face indexes (note interleaved offset!) */
702                         PicoSetSurfaceIndex( surface, (index * 9 + 6), indexes[2] );
703                         PicoSetSurfaceIndex( surface, (index * 9 + 7), indexes[1] );
704                         PicoSetSurfaceIndex( surface, (index * 9 + 8), indexes[0] );
705
706                         face = _ase_get_face_for_index(faces,index);
707                         face->index[6] = indexes[2];
708                         face->index[7] = indexes[1];
709                         face->index[8] = indexes[0];
710                 }
711                 /* model material */
712                 else if( !_pico_stricmp( p->token, "*material" ) )
713                 {
714                         aseSubMaterial_t*       subMaterial = NULL;
715                         picoShader_t            *shader = NULL;
716                         int                                     level = 1, index;
717                         char                            materialName[ 1024 ];
718                         float                           transValue = 0.0f, shineValue = 1.0f;
719                         picoColor_t                     ambientColor, diffuseColor, specularColor;
720                         char                            *mapname = NULL;
721                         int                                     subMtlId, subMaterialLevel = -1;
722
723
724                         /* get material index */
725                         _pico_parse_int( p,&index );
726
727                         /* check brace */
728                         if (!_pico_parse_check(p,1,"{"))
729                                 _ase_error_return("Material missing opening brace");
730
731                         /* parse material block */
732                         while( 1 )
733                         {
734                                 /* get next token */
735                                 if (_pico_parse(p,1) == NULL) break;
736                                 if (!strlen(p->token)) continue;
737
738                                 /* handle levels */
739                                 if (p->token[0] == '{') level++;
740                                 if (p->token[0] == '}') level--;
741                                 if (!level) break;
742
743                                 if( level == subMaterialLevel )
744                                 {
745                                         /* set material name */
746                                         PicoSetShaderName( shader, materialName);
747
748                                         /* set shader's transparency */
749                                         PicoSetShaderTransparency( shader,transValue );
750
751                                         /* set shader's ambient color */
752                                         PicoSetShaderAmbientColor( shader,ambientColor );
753
754                                         /* set diffuse alpha to transparency */
755                                         diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
756
757                                         /* set shader's diffuse color */
758                                         PicoSetShaderDiffuseColor( shader,diffuseColor );
759
760                                         /* set shader's specular color */
761                                         PicoSetShaderSpecularColor( shader,specularColor );
762
763                                         /* set shader's shininess */
764                                         PicoSetShaderShininess( shader,shineValue );
765
766                                         /* set material map name */
767                                         PicoSetShaderMapName( shader, mapname );
768
769                                         subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader );
770                                         subMaterialLevel = -1;
771                                 }
772
773                                 /* parse submaterial index */
774                                 if (!_pico_stricmp(p->token,"*submaterial"))
775                                 {
776                                         /* allocate new pico shader */
777                                         _pico_parse_int( p , &subMtlId );
778
779                                         shader = PicoNewShader( model );
780                                         if (shader == NULL)
781                                         {
782                                                 PicoFreeModel( model );
783                                                 return NULL;
784                                         }
785                                         subMaterialLevel = level;
786                                 }
787                                 /* parse material name */
788                                 else if (!_pico_stricmp(p->token,"*material_name"))
789                                 {
790