1 /* -----------------------------------------------------------------------------
5 Copyright (c) 2002, Randy Reddig & seaw0lf
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
11 Redistributions of source code must retain the above copyright notice, this list
12 of conditions and the following disclaimer.
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.
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.
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.
33 ----------------------------------------------------------------------------- */
35 /* uncomment when debugging this module */
36 //#define DEBUG_PM_ASE
37 //#define DEBUG_PM_ASE_EX
41 #include "picointernal.h"
47 /* jhefty - multi-subobject material support */
49 /* Material/SubMaterial management */
50 /* A material should have 1..n submaterials assigned to it */
52 typedef struct aseSubMaterial_s
54 struct aseSubMaterial_s* next;
60 typedef struct aseMaterial_s
62 struct aseMaterial_s* next;
63 struct aseSubMaterial_s* subMtls;
67 /* Material/SubMaterial management functions */
68 static aseMaterial_t* _ase_get_material( aseMaterial_t* list, int mtlIdParent ){
69 aseMaterial_t* mtl = list;
73 if ( mtlIdParent == mtl->mtlId ) {
81 static aseSubMaterial_t* _ase_get_submaterial( aseMaterial_t* list, int mtlIdParent, int subMtlId ){
82 aseMaterial_t* parent = _ase_get_material( list, mtlIdParent );
83 aseSubMaterial_t* subMtl = NULL;
86 _pico_printf( PICO_ERROR, "No ASE material exists with id %i\n", mtlIdParent );
90 subMtl = parent->subMtls;
93 if ( subMtlId == subMtl->subMtlId ) {
96 subMtl = subMtl->next;
101 aseSubMaterial_t* _ase_get_submaterial_or_default( aseMaterial_t* materials, int mtlIdParent, int subMtlId ){
102 aseSubMaterial_t* subMtl = _ase_get_submaterial( materials, mtlIdParent, subMtlId );
103 if ( subMtl != NULL ) {
107 /* ydnar: trying default submaterial */
108 subMtl = _ase_get_submaterial( materials, mtlIdParent, 0 );
109 if ( subMtl != NULL ) {
113 _pico_printf( PICO_ERROR, "Could not find material/submaterial for id %d/%d\n", mtlIdParent, subMtlId );
120 static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent ){
121 aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) );
122 mtl->mtlId = mtlIdParent;
130 static aseSubMaterial_t* _ase_add_submaterial( aseMaterial_t **list, int mtlIdParent, int subMtlId, picoShader_t* shader ){
131 aseMaterial_t *parent = _ase_get_material( *list, mtlIdParent );
132 aseSubMaterial_t *subMtl = _pico_calloc( 1, sizeof( aseSubMaterial_t ) );
135 parent = _ase_add_material( list, mtlIdParent );
138 subMtl->shader = shader;
139 subMtl->subMtlId = subMtlId;
140 subMtl->next = parent->subMtls;
141 parent->subMtls = subMtl;
146 static void _ase_free_materials( aseMaterial_t **list ){
147 aseMaterial_t* mtl = *list;
148 aseSubMaterial_t* subMtl = NULL;
150 aseMaterial_t* mtlTemp = NULL;
151 aseSubMaterial_t* subMtlTemp = NULL;
155 subMtl = mtl->subMtls;
158 subMtlTemp = subMtl->next;
159 _pico_free( subMtl );
170 static void _ase_print_materials( aseMaterial_t *list ){
171 aseMaterial_t* mtl = list;
172 aseSubMaterial_t* subMtl = NULL;
176 _pico_printf( PICO_NORMAL, "ASE Material %i", mtl->mtlId );
177 subMtl = mtl->subMtls;
180 _pico_printf( PICO_NORMAL, " -- ASE SubMaterial %i - %s\n", subMtl->subMtlId, subMtl->shader->name );
181 subMtl = subMtl->next;
186 #endif //DEBUG_PM_ASE
189 * - apply material specific uv offsets to uv coordinates
193 * validates a 3dsmax ase model file.
195 static int _ase_canload( PM_PARAMS_CANLOAD ){
199 /* quick data length validation */
200 if ( bufSize < 80 ) {
201 return PICO_PMV_ERROR_SIZE;
204 /* create pico parser */
205 p = _pico_new_parser( (const picoByte_t*) buffer, bufSize );
207 return PICO_PMV_ERROR_MEMORY;
210 /* get first token */
211 if ( _pico_parse_first( p ) == NULL ) {
212 return PICO_PMV_ERROR_IDENT;
215 /* check first token */
216 if ( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) ) {
217 _pico_free_parser( p );
218 return PICO_PMV_ERROR_IDENT;
221 /* free the pico parser object */
222 _pico_free_parser( p );
224 /* file seems to be a valid ase file */
228 typedef struct aseVertex_s aseVertex_t;
236 typedef struct aseTexCoord_s aseTexCoord_t;
242 typedef struct aseColor_s aseColor_t;
248 typedef struct aseFace_s aseFace_t;
251 picoIndex_t indices[9];
252 picoIndex_t smoothingGroup;
253 picoIndex_t materialId;
254 picoIndex_t subMaterialId;
256 typedef aseFace_t* aseFacesIter_t;
258 picoSurface_t* PicoModelFindOrAddSurface( picoModel_t *model, picoShader_t* shader ){
259 /* see if a surface already has the shader */
261 for ( ; i < model->numSurfaces ; i++ )
263 picoSurface_t* workSurface = model->surface[i];
264 if ( workSurface->shader == shader ) {
269 /* no surface uses this shader yet, so create a new surface */
272 /* create a new surface in the model for the unique shader */
273 picoSurface_t* workSurface = PicoNewSurface( model );
274 if ( !workSurface ) {
275 _pico_printf( PICO_ERROR, "Could not allocate a new surface!\n" );
279 /* do surface setup */
280 PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
281 PicoSetSurfaceName( workSurface, shader->name );
282 PicoSetSurfaceShader( workSurface, shader );
288 /* _ase_submit_triangles - jhefty
289 use the surface and the current face list to look up material/submaterial IDs
290 and submit them to the model for proper processing
292 The following still holds from ydnar's _ase_make_surface:
293 indexes 0 1 2 = vert indexes
294 indexes 3 4 5 = st indexes
295 indexes 6 7 8 = color indexes (new)
299 typedef picoIndex_t* picoIndexIter_t;
301 typedef struct aseUniqueIndices_s aseUniqueIndices_t;
302 struct aseUniqueIndices_s
310 size_t aseUniqueIndices_size( aseUniqueIndices_t* self ){
311 return self->last - self->data;
314 void aseUniqueIndices_reserve( aseUniqueIndices_t* self, picoIndex_t size ){
315 self->data = self->last = (picoIndex_t*)_pico_calloc( size, sizeof( picoIndex_t ) );
318 void aseUniqueIndices_clear( aseUniqueIndices_t* self ){
319 _pico_free( self->data );
322 void aseUniqueIndices_pushBack( aseUniqueIndices_t* self, picoIndex_t index ){
323 *self->last++ = index;
326 picoIndex_t aseFaces_getVertexIndex( aseFace_t* faces, picoIndex_t index ){
327 return faces[index / 3].indices[index % 3];
330 picoIndex_t aseFaces_getTexCoordIndex( aseFace_t* faces, picoIndex_t index ){
331 return faces[index / 3].indices[( index % 3 ) + 3];
334 picoIndex_t aseFaces_getColorIndex( aseFace_t* faces, picoIndex_t index ){
335 return faces[index / 3].indices[( index % 3 ) + 6];
338 int aseUniqueIndex_equal( aseFace_t* faces, picoIndex_t index, picoIndex_t other ){
339 return aseFaces_getVertexIndex( faces, index ) == aseFaces_getVertexIndex( faces, other )
340 && aseFaces_getTexCoordIndex( faces, index ) == aseFaces_getTexCoordIndex( faces, other )
341 && aseFaces_getColorIndex( faces, index ) == aseFaces_getColorIndex( faces, other );
344 picoIndex_t aseUniqueIndices_insertUniqueVertex( aseUniqueIndices_t* self, picoIndex_t index ){
345 picoIndexIter_t i = self->data;
346 for (; i != self->last; ++i )
348 picoIndex_t other = (picoIndex_t)( i - self->data );
349 if ( aseUniqueIndex_equal( self->faces, index, other ) ) {
354 aseUniqueIndices_pushBack( self, index );
355 return (picoIndex_t)( aseUniqueIndices_size( self ) - 1 );
358 static void _ase_submit_triangles_unshared( picoModel_t* model, aseMaterial_t* materials, aseVertex_t* vertices, aseTexCoord_t* texcoords, aseColor_t* colors, aseFace_t* faces, int numFaces, int meshHasNormals ){
359 aseFacesIter_t i = faces, end = faces + numFaces;
361 aseUniqueIndices_t indices;
362 aseUniqueIndices_t remap;
363 aseUniqueIndices_reserve( &indices, numFaces * 3 );
364 aseUniqueIndices_reserve( &remap, numFaces * 3 );
365 indices.faces = faces;
367 for (; i != end; ++i )
369 /* look up the shader for the material/submaterial pair */
370 aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, ( *i ).materialId, ( *i ).subMaterialId );
371 if ( subMtl == NULL ) {
376 picoSurface_t* surface = PicoModelFindOrAddSurface( model, subMtl->shader );
378 /* we pull the data from the vertex, color and texcoord arrays using the face index data */
379 for ( j = 0 ; j < 3 ; j++ )
381 picoIndex_t index = (picoIndex_t)( ( ( i - faces ) * 3 ) + j );
382 picoIndex_t size = (picoIndex_t)aseUniqueIndices_size( &indices );
383 picoIndex_t unique = aseUniqueIndices_insertUniqueVertex( &indices, index );
385 picoIndex_t numVertexes = PicoGetSurfaceNumVertexes( surface );
386 picoIndex_t numIndexes = PicoGetSurfaceNumIndexes( surface );
388 aseUniqueIndices_pushBack( &remap, numIndexes );
390 PicoSetSurfaceIndex( surface, numIndexes, remap.data[unique] );
392 if ( unique == size ) {
393 PicoSetSurfaceXYZ( surface, numVertexes, vertices[( *i ).indices[j]].xyz );
394 PicoSetSurfaceNormal( surface, numVertexes, vertices[( *i ).indices[j]].normal );
395 PicoSetSurfaceST( surface, 0, numVertexes, texcoords[( *i ).indices[j + 3]].texcoord );
397 if ( ( *i ).indices[j + 6] >= 0 ) {
398 PicoSetSurfaceColor( surface, 0, numVertexes, colors[( *i ).indices[j + 6]].color );
402 PicoSetSurfaceColor( surface, 0, numVertexes, picoColor_white );
405 PicoSetSurfaceSmoothingGroup( surface, numVertexes, ( vertices[( *i ).indices[j]].id * ( 1 << 16 ) ) + ( *i ).smoothingGroup );
411 aseUniqueIndices_clear( &indices );
412 aseUniqueIndices_clear( &remap );
417 static void _ase_submit_triangles( picoModel_t* model, aseMaterial_t* materials, aseVertex_t* vertices, aseTexCoord_t* texcoords, aseColor_t* colors, aseFace_t* faces, int numFaces, const char *name ){
418 aseFacesIter_t i = faces, end = faces + numFaces;
419 for (; i != end; ++i )
421 /* look up the shader for the material/submaterial pair */
422 aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, ( *i ).materialId, ( *i ).subMaterialId );
423 if ( subMtl == NULL ) {
429 picoVec3_t* normal[3];
431 const picoColor_t* color[3];
432 picoIndex_t smooth[3];
434 /* we pull the data from the vertex, color and texcoord arrays using the face index data */
435 for ( j = 0 ; j < 3 ; j++ )
437 xyz[j] = &vertices[( *i ).indices[j]].xyz;
438 normal[j] = &vertices[( *i ).indices[j]].normal;
439 st[j] = &texcoords[( *i ).indices[j + 3]].texcoord;
441 if ( colors != NULL && ( *i ).indices[j + 6] >= 0 ) {
442 color[j] = &colors[( *i ).indices[j + 6]].color;
446 color[j] = &picoColor_white;
449 smooth[j] = ( vertices[( *i ).indices[j]].id * ( 1 << 16 ) ) + ( *i ).smoothingGroup; /* don't merge vertices */
453 /* submit the triangle to the model */
454 PicoAddTriangleToModel( model, xyz, normal, 1, st, 1, color, subMtl->shader, name, smooth );
461 * loads a 3dsmax ase model file.
463 static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
466 char lastNodeName[ 1024 ];
468 aseVertex_t* vertices = NULL;
469 aseTexCoord_t* texcoords = NULL;
470 aseColor_t* colors = NULL;
471 aseFace_t* faces = NULL;
474 int numTextureVertices = 0;
475 int numTextureVertexFaces = 0;
476 int numColorVertices = 0;
477 int numColorVertexFaces = 0;
480 aseMaterial_t* materials = NULL;
483 clock_t start, finish;
489 #define _ase_error_return( m ) \
491 _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine ); \
492 _pico_free_parser( p ); \
493 PicoFreeModel( model ); \
496 /* create a new pico parser */
497 p = _pico_new_parser( (const picoByte_t *)buffer,bufSize );
502 /* create a new pico model */
503 model = PicoNewModel();
504 if ( model == NULL ) {
505 _pico_free_parser( p );
509 PicoSetModelFrameNum( model, frameNum );
510 PicoSetModelName( model, fileName );
511 PicoSetModelFileName( model, fileName );
513 /* initialize some stuff */
514 memset( lastNodeName, 0, sizeof( lastNodeName ) );
516 /* parse ase model file */
519 /* get first token on line */
520 if ( _pico_parse_first( p ) == NULL ) {
524 /* we just skip empty lines */
525 if ( p->token == NULL || !strlen( p->token ) ) {
529 /* we skip invalid ase statements */
530 if ( p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}' ) {
531 _pico_parse_skip_rest( p );
534 /* remember node name */
535 if ( !_pico_stricmp( p->token,"*node_name" ) ) {
537 char *ptr = _pico_parse( p,0 );
539 _ase_error_return( "Node name parse error" );
542 /* remember node name */
543 strncpy( lastNodeName, ptr, sizeof( lastNodeName ) - 1 );
545 /* model mesh (originally contained within geomobject) */
546 else if ( !_pico_stricmp( p->token,"*mesh" ) ) {
547 /* finish existing surface */
548 _ase_submit_triangles( model, materials, vertices, texcoords, colors, faces, numFaces, lastNodeName );
550 _pico_free( vertices );
551 _pico_free( texcoords );
552 _pico_free( colors );
554 else if ( !_pico_stricmp( p->token,"*mesh_numvertex" ) ) {
555 if ( !_pico_parse_int( p, &numVertices ) ) {
556 _ase_error_return( "Missing MESH_NUMVERTEX value" );
559 vertices = _pico_calloc( numVertices, sizeof( aseVertex_t ) );
561 else if ( !_pico_stricmp( p->token,"*mesh_numfaces" ) ) {
562 if ( !_pico_parse_int( p, &numFaces ) ) {
563 _ase_error_return( "Missing MESH_NUMFACES value" );
566 faces = _pico_calloc( numFaces, sizeof( aseFace_t ) );
568 else if ( !_pico_stricmp( p->token,"*mesh_numtvertex" ) ) {
569 if ( !_pico_parse_int( p, &numTextureVertices ) ) {
570 _ase_error_return( "Missing MESH_NUMTVERTEX value" );
573 texcoords = _pico_calloc( numTextureVertices, sizeof( aseTexCoord_t ) );
575 else if ( !_pico_stricmp( p->token,"*mesh_numtvfaces" ) ) {
576 if ( !_pico_parse_int( p, &numTextureVertexFaces ) ) {
577 _ase_error_return( "Missing MESH_NUMTVFACES value" );
580 else if ( !_pico_stricmp( p->token,"*mesh_numcvertex" ) ) {
581 if ( !_pico_parse_int( p, &numColorVertices ) ) {
582 _ase_error_return( "Missing MESH_NUMCVERTEX value" );
585 colors = _pico_calloc( numColorVertices, sizeof( aseColor_t ) );
586 memset( colors, 255, numColorVertices * sizeof( aseColor_t ) ); /* ydnar: force colors to white initially */
588 else if ( !_pico_stricmp( p->token,"*mesh_numcvfaces" ) ) {
589 if ( !_pico_parse_int( p, &numColorVertexFaces ) ) {
590 _ase_error_return( "Missing MESH_NUMCVFACES value" );
593 /* mesh material reference. this usually comes at the end of */
594 /* geomobjects after the mesh blocks. we must assume that the */
595 /* new mesh was already created so all we can do here is assign */
596 /* the material reference id (shader index) now. */
597 else if ( !_pico_stricmp( p->token,"*material_ref" ) ) {
600 /* get the material ref (0..n) */
601 if ( !_pico_parse_int( p,&mtlId ) ) {
602 _ase_error_return( "Missing material reference ID" );
607 /* fix up all of the aseFaceList in the surface to point to the parent material */
608 /* we've already saved off their subMtl */
609 for (; i < numFaces; ++i )
611 faces[i].materialId = mtlId;
615 /* model mesh vertex */
616 else if ( !_pico_stricmp( p->token,"*mesh_vertex" ) ) {
619 if ( numVertices == 0 ) {
620 _ase_error_return( "Vertex parse error" );
623 /* get vertex data (orig: index +y -x +z) */
624 if ( !_pico_parse_int( p,&index ) ) {
625 _ase_error_return( "Vertex parse error" );
627 if ( !_pico_parse_vec( p,vertices[index].xyz ) ) {
628 _ase_error_return( "Vertex parse error" );
631 vertices[index].id = vertexId++;
633 /* model mesh vertex normal */
634 else if ( !_pico_stricmp( p->token,"*mesh_vertexnormal" ) ) {
637 if ( numVertices == 0 ) {
638 _ase_error_return( "Vertex parse error" );
641 /* get vertex data (orig: index +y -x +z) */
642 if ( !_pico_parse_int( p,&index ) ) {
643 _ase_error_return( "Vertex parse error" );
645 if ( !_pico_parse_vec( p,vertices[index].normal ) ) {
646 _ase_error_return( "Vertex parse error" );
649 /* model mesh face */
650 else if ( !_pico_stricmp( p->token,"*mesh_face" ) ) {
651 picoIndex_t indexes[3];
654 if ( numFaces == 0 ) {
655 _ase_error_return( "Face parse error" );
659 if ( !_pico_parse_int( p,&index ) ) {
660 _ase_error_return( "Face parse error" );
663 /* get 1st vertex index */
665 if ( !_pico_parse_int( p,&indexes[0] ) ) {
666 _ase_error_return( "Face parse error" );
669 /* get 2nd vertex index */
671 if ( !_pico_parse_int( p,&indexes[1] ) ) {
672 _ase_error_return( "Face parse error" );
675 /* get 3rd vertex index */
677 if ( !_pico_parse_int( p,&indexes[2] ) ) {
678 _ase_error_return( "Face parse error" );
681 /* parse to the subMaterial ID */
684 if ( !_pico_parse( p,0 ) ) { /* EOL */
687 if ( !_pico_stricmp( p->token,"*MESH_SMOOTHING" ) ) {
688 _pico_parse_int( p, &faces[index].smoothingGroup );
690 if ( !_pico_stricmp( p->token,"*MESH_MTLID" ) ) {
691 _pico_parse_int( p, &faces[index].subMaterialId );
695 faces[index].materialId = 0;
696 faces[index].indices[0] = indexes[2];
697 faces[index].indices[1] = indexes[1];
698 faces[index].indices[2] = indexes[0];
700 /* model texture vertex */
701 else if ( !_pico_stricmp( p->token,"*mesh_tvert" ) ) {
704 if ( numVertices == 0 ) {
705 _ase_error_return( "Texture Vertex parse error" );
708 /* get uv vertex index */
709 if ( !_pico_parse_int( p,&index ) || index >= numTextureVertices ) {
710 _ase_error_return( "Texture vertex parse error" );
713 /* get uv vertex s */
714 if ( !_pico_parse_float( p,&texcoords[index].texcoord[0] ) ) {
715 _ase_error_return( "Texture vertex parse error" );
718 /* get uv vertex t */
719 if ( !_pico_parse_float( p,&texcoords[index].texcoord[1] ) ) {
720 _ase_error_return( "Texture vertex parse error" );
723 /* ydnar: invert t */
724 texcoords[index].texcoord[ 1 ] = 1.0f - texcoords[index].texcoord[ 1 ];
726 /* ydnar: model mesh texture face */
727 else if ( !_pico_stricmp( p->token, "*mesh_tface" ) ) {
728 picoIndex_t indexes[3];
731 if ( numFaces == 0 ) {
732 _ase_error_return( "Texture face parse error" );
736 if ( !_pico_parse_int( p,&index ) ) {
737 _ase_error_return( "Texture face parse error" );
740 /* get 1st vertex index */
741 if ( !_pico_parse_int( p,&indexes[0] ) ) {
742 _ase_error_return( "Texture face parse error" );
745 /* get 2nd vertex index */
746 if ( !_pico_parse_int( p,&indexes[1] ) ) {
747 _ase_error_return( "Texture face parse error" );
750 /* get 3rd vertex index */
751 if ( !_pico_parse_int( p,&indexes[2] ) ) {
752 _ase_error_return( "Texture face parse error" );
755 faces[index].indices[3] = indexes[2];
756 faces[index].indices[4] = indexes[1];
757 faces[index].indices[5] = indexes[0];
759 /* model color vertex */
760 else if ( !_pico_stricmp( p->token,"*mesh_vertcol" ) ) {
764 if ( numVertices == 0 ) {
765 _ase_error_return( "Color Vertex parse error" );
768 /* get color vertex index */
769 if ( !_pico_parse_int( p,&index ) ) {
770 _ase_error_return( "Color vertex parse error" );
773 /* get R component */
774 if ( !_pico_parse_float( p,&colorInput ) ) {
775 _ase_error_return( "Color vertex parse error" );
777 colors[index].color[0] = (picoByte_t)( colorInput * 255 );
779 /* get G component */
780 if ( !_pico_parse_float( p,&colorInput ) ) {
781 _ase_error_return( "Color vertex parse error" );
783 colors[index].color[1] = (picoByte_t)( colorInput * 255 );
785 /* get B component */
786 if ( !_pico_parse_float( p,&colorInput ) ) {
787 _ase_error_return( "Color vertex parse error" );
789 colors[index].color[2] = (picoByte_t)( colorInput * 255 );
791 /* leave alpha alone since we don't get any data from the ASE format */
792 colors[index].color[3] = 255;
794 /* model color face */
795 else if ( !_pico_stricmp( p->token,"*mesh_cface" ) ) {
796 picoIndex_t indexes[3];
799 if ( numFaces == 0 ) {
800 _ase_error_return( "Face parse error" );
804 if ( !_pico_parse_int( p,&index ) ) {
805 _ase_error_return( "Face parse error" );
808 /* get 1st cvertex index */
809 // _pico_parse( p,0 );
810 if ( !_pico_parse_int( p,&indexes[0] ) ) {
811 _ase_error_return( "Face parse error" );
814 /* get 2nd cvertex index */
815 // _pico_parse( p,0 );
816 if ( !_pico_parse_int( p,&indexes[1] ) ) {
817 _ase_error_return( "Face parse error" );
820 /* get 3rd cvertex index */
821 // _pico_parse( p,0 );
822 if ( !_pico_parse_int( p,&indexes[2] ) ) {
823 _ase_error_return( "Face parse error" );
826 faces[index].indices[6] = indexes[2];
827 faces[index].indices[7] = indexes[1];
828 faces[index].indices[8] = indexes[0];
831 else if ( !_pico_stricmp( p->token, "*material" ) ) {
832 aseSubMaterial_t* subMaterial = NULL;
833 picoShader_t *shader = NULL;
834 int level = 1, index;
835 char materialName[ 1024 ];
836 float transValue = 0.0f, shineValue = 1.0f;
837 picoColor_t ambientColor, diffuseColor, specularColor;
838 char *mapname = NULL;
839 int subMtlId, subMaterialLevel = -1;
842 /* get material index */
843 _pico_parse_int( p,&index );
846 if ( !_pico_parse_check( p,1,"{" ) ) {
847 _ase_error_return( "Material missing opening brace" );
850 /* parse material block */
854 if ( _pico_parse( p,1 ) == NULL ) {
857 if ( !strlen( p->token ) ) {
862 if ( p->token[0] == '{' ) {
865 if ( p->token[0] == '}' ) {
872 if ( level == subMaterialLevel ) {
873 /* set material name */
874 _pico_first_token( materialName );
875 _pico_unixify( materialName );
876 PicoSetShaderName( shader, materialName );
878 /* set shader's transparency */
879 PicoSetShaderTransparency( shader,transValue );
881 /* set shader's ambient color */
882 PicoSetShaderAmbientColor( shader,ambientColor );
884 /* set diffuse alpha to transparency */
885 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
887 /* set shader's diffuse color */
888 PicoSetShaderDiffuseColor( shader,diffuseColor );
890 /* set shader's specular color */
891 PicoSetShaderSpecularColor( shader,specularColor );
893 /* set shader's shininess */
894 PicoSetShaderShininess( shader,shineValue );
896 /* set material map name */
897 PicoSetShaderMapName( shader, mapname );
899 subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader );
900 subMaterialLevel = -1;
903 /* parse submaterial index */
904 if ( !_pico_stricmp( p->token,"*submaterial" ) ) {
905 /* allocate new pico shader */
906 _pico_parse_int( p, &subMtlId );
908 shader = PicoNewShader( model );
909 if ( shader == NULL ) {
910 PicoFreeModel( model );
913 subMaterialLevel = level;
915 /* parse material name */
916 else if ( !_pico_stricmp( p->token,"*material_name" ) ) {
917 char* name = _pico_parse( p,0 );
918 if ( name == NULL ) {
919 _ase_error_return( "Missing material name" );
922 strcpy( materialName, name );
923 /* skip rest and continue with next token */
924 _pico_parse_skip_rest( p );
927 /* parse material transparency */
928 else if ( !_pico_stricmp( p->token,"*material_transparency" ) ) {
929 /* get transparency value from ase */
930 if ( !_pico_parse_float( p,&transValue ) ) {
931 _ase_error_return( "Material transparency parse error" );
934 /* skip rest and continue with next token */
935 _pico_parse_skip_rest( p );
938 /* parse material shininess */
939 else if ( !_pico_stricmp( p->token,"*material_shine" ) ) {
941 * - not sure but instead of '*material_shine' i might
942 * need to use '*material_shinestrength' */
944 /* get shine value from ase */
945 if ( !_pico_parse_float( p,&shineValue ) ) {
946 _ase_error_return( "Material shine parse error" );
949 /* scale ase shine range 0..1 to pico range 0..127 */
952 /* skip rest and continue with next token */
953 _pico_parse_skip_rest( p );
956 /* parse ambient material color */
957 else if ( !_pico_stricmp( p->token,"*material_ambient" ) ) {
959 /* get r,g,b float values from ase */
960 if ( !_pico_parse_vec( p,vec ) ) {
961 _ase_error_return( "Material color parse error" );
964 /* setup 0..255 range color values */
965 ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
966 ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
967 ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
968 ambientColor[ 3 ] = (int)( 255 );
970 /* skip rest and continue with next token */
971 _pico_parse_skip_rest( p );
974 /* parse diffuse material color */
975 else if ( !_pico_stricmp( p->token,"*material_diffuse" ) ) {
978 /* get r,g,b float values from ase */
979 if ( !_pico_parse_vec( p,vec ) ) {
980 _ase_error_return( "Material color parse error" );
983 /* setup 0..255 range color */
984 diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
985 diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
986 diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
987 diffuseColor[ 3 ] = (int)( 255 );
989 /* skip rest and continue with next token */
990 _pico_parse_skip_rest( p );
993 /* parse specular material color */
994 else if ( !_pico_stricmp( p->token,"*material_specular" ) ) {
997 /* get r,g,b float values from ase */
998 if ( !_pico_parse_vec( p,vec ) ) {
999 _ase_error_return( "Material color parse error" );
1002 /* setup 0..255 range color */
1003 specularColor[ 0 ] = (int)( vec[ 0 ] * 255 );
1004 specularColor[ 1 ] = (int)( vec[ 1 ] * 255 );
1005 specularColor[ 2 ] = (int)( vec[ 2 ] * 255 );
1006 specularColor[ 3 ] = (int)( 255 );
1008 /* skip rest and continue with next token */
1009 _pico_parse_skip_rest( p );
1012 /* material diffuse map */
1013 else if ( !_pico_stricmp( p->token,"*map_diffuse" ) ) {
1016 /* parse material block */
1019 /* get next token */
1020 if ( _pico_parse( p,1 ) == NULL ) {
1023 if ( !strlen( p->token ) ) {
1028 if ( p->token[0] == '{' ) {
1031 if ( p->token[0] == '}' ) {
1038 /* parse diffuse map bitmap */
1039 if ( !_pico_stricmp( p->token,"*bitmap" ) ) {
1040 char* name = _pico_parse( p,0 );
1041 if ( name == NULL ) {
1042 _ase_error_return( "Missing material map bitmap name" );
1044 else if( !_pico_stricmp( name, "none" ) ){ // standard empty bitmap name
1047 mapname = _pico_alloc( strlen( name ) + 1 );
1048 strcpy( mapname, name );
1049 /* skip rest and continue with next token */
1050 _pico_parse_skip_rest( p );
1055 /* end map_diffuse block */
1057 /* end material block */
1059 if ( subMaterial == NULL ) {
1060 /* allocate new pico shader */
1061 shader = PicoNewShader( model );
1062 if ( shader == NULL ) {
1063 PicoFreeModel( model );
1067 /* set material name */
1068 _pico_unixify( materialName );
1069 PicoSetShaderName( shader,materialName );
1071 /* set shader's transparency */
1072 PicoSetShaderTransparency( shader,transValue );
1074 /* set shader's ambient color */
1075 PicoSetShaderAmbientColor( shader,ambientColor );
1077 /* set diffuse alpha to transparency */
1078 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
1080 /* set shader's diffuse color */
1081 PicoSetShaderDiffuseColor( shader,diffuseColor );
1083 /* set shader's specular color */
1084 PicoSetShaderSpecularColor( shader,specularColor );
1086 /* set shader's shininess */
1087 PicoSetShaderShininess( shader,shineValue );
1089 /* set material map name */
1090 PicoSetShaderMapName( shader, mapname );
1092 /* this is just a material with 1 submaterial */
1093 subMaterial = _ase_add_submaterial( &materials, index, 0, shader );
1096 /* ydnar: free mapname */
1097 if ( mapname != NULL ) {
1098 _pico_free( mapname );
1100 } // !_pico_stricmp ( "*material" )
1102 /* skip unparsed rest of line and continue */
1103 _pico_parse_skip_rest( p );
1106 /* ydnar: finish existing surface */
1107 _ase_submit_triangles( model, materials, vertices, texcoords, colors, faces, numFaces, lastNodeName );
1108 _pico_free( faces );
1109 _pico_free( vertices );
1110 _pico_free( texcoords );
1111 _pico_free( colors );
1114 _ase_print_materials( materials );
1116 elapsed = (double)( finish - start ) / CLOCKS_PER_SEC;
1117 _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed );
1118 #endif //DEBUG_PM_ASE
1120 _ase_free_materials( &materials );
1122 _pico_free_parser( p );
1124 /* return allocated pico model */
1128 /* pico file format module definition */
1129 const picoModule_t picoModuleASE =
1131 "1.0", /* module version string */
1132 "Autodesk 3DSMAX ASCII", /* module display name */
1133 "Jared Hefty, seaw0lf", /* author's name */
1134 "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */
1136 "ase",NULL,NULL,NULL /* default extensions to use */
1138 _ase_canload, /* validation routine */
1139 _ase_load, /* load routine */
1140 NULL, /* save validation routine */
1141 NULL /* save routine */