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 );
459 static void shadername_convert( char* shaderName ){
460 /* unix-style path separators */
461 char* s = shaderName;
462 for (; *s != '\0'; ++s )
472 * loads a 3dsmax ase model file.
474 static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
477 char lastNodeName[ 1024 ];
479 aseVertex_t* vertices = NULL;
480 aseTexCoord_t* texcoords = NULL;
481 aseColor_t* colors = NULL;
482 aseFace_t* faces = NULL;
485 int numTextureVertices = 0;
486 int numTextureVertexFaces = 0;
487 int numColorVertices = 0;
488 int numColorVertexFaces = 0;
491 aseMaterial_t* materials = NULL;
494 clock_t start, finish;
500 #define _ase_error_return( m ) \
502 _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine ); \
503 _pico_free_parser( p ); \
504 PicoFreeModel( model ); \
507 /* create a new pico parser */
508 p = _pico_new_parser( (const picoByte_t *)buffer,bufSize );
513 /* create a new pico model */
514 model = PicoNewModel();
515 if ( model == NULL ) {
516 _pico_free_parser( p );
520 PicoSetModelFrameNum( model, frameNum );
521 PicoSetModelName( model, fileName );
522 PicoSetModelFileName( model, fileName );
524 /* initialize some stuff */
525 memset( lastNodeName,0,sizeof( lastNodeName ) );
527 /* parse ase model file */
530 /* get first token on line */
531 if ( _pico_parse_first( p ) == NULL ) {
535 /* we just skip empty lines */
536 if ( p->token == NULL || !strlen( p->token ) ) {
540 /* we skip invalid ase statements */
541 if ( p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}' ) {
542 _pico_parse_skip_rest( p );
545 /* remember node name */
546 if ( !_pico_stricmp( p->token,"*node_name" ) ) {
548 char *ptr = _pico_parse( p,0 );
550 _ase_error_return( "Node name parse error" );
553 /* remember node name */
554 strncpy( lastNodeName,ptr,sizeof( lastNodeName ) );
556 /* model mesh (originally contained within geomobject) */
557 else if ( !_pico_stricmp( p->token,"*mesh" ) ) {
558 /* finish existing surface */
559 _ase_submit_triangles( model, materials, vertices, texcoords, colors, faces, numFaces, lastNodeName );
561 _pico_free( vertices );
562 _pico_free( texcoords );
563 _pico_free( colors );
565 else if ( !_pico_stricmp( p->token,"*mesh_numvertex" ) ) {
566 if ( !_pico_parse_int( p, &numVertices ) ) {
567 _ase_error_return( "Missing MESH_NUMVERTEX value" );
570 vertices = _pico_calloc( numVertices, sizeof( aseVertex_t ) );
572 else if ( !_pico_stricmp( p->token,"*mesh_numfaces" ) ) {
573 if ( !_pico_parse_int( p, &numFaces ) ) {
574 _ase_error_return( "Missing MESH_NUMFACES value" );
577 faces = _pico_calloc( numFaces, sizeof( aseFace_t ) );
579 else if ( !_pico_stricmp( p->token,"*mesh_numtvertex" ) ) {
580 if ( !_pico_parse_int( p, &numTextureVertices ) ) {
581 _ase_error_return( "Missing MESH_NUMTVERTEX value" );
584 texcoords = _pico_calloc( numTextureVertices, sizeof( aseTexCoord_t ) );
586 else if ( !_pico_stricmp( p->token,"*mesh_numtvfaces" ) ) {
587 if ( !_pico_parse_int( p, &numTextureVertexFaces ) ) {
588 _ase_error_return( "Missing MESH_NUMTVFACES value" );
591 else if ( !_pico_stricmp( p->token,"*mesh_numcvertex" ) ) {
592 if ( !_pico_parse_int( p, &numColorVertices ) ) {
593 _ase_error_return( "Missing MESH_NUMCVERTEX value" );
596 colors = _pico_calloc( numColorVertices, sizeof( aseColor_t ) );
597 memset( colors, 255, numColorVertices * sizeof( aseColor_t ) ); /* ydnar: force colors to white initially */
599 else if ( !_pico_stricmp( p->token,"*mesh_numcvfaces" ) ) {
600 if ( !_pico_parse_int( p, &numColorVertexFaces ) ) {
601 _ase_error_return( "Missing MESH_NUMCVFACES value" );
604 /* mesh material reference. this usually comes at the end of */
605 /* geomobjects after the mesh blocks. we must assume that the */
606 /* new mesh was already created so all we can do here is assign */
607 /* the material reference id (shader index) now. */
608 else if ( !_pico_stricmp( p->token,"*material_ref" ) ) {
611 /* get the material ref (0..n) */
612 if ( !_pico_parse_int( p,&mtlId ) ) {
613 _ase_error_return( "Missing material reference ID" );
618 /* fix up all of the aseFaceList in the surface to point to the parent material */
619 /* we've already saved off their subMtl */
620 for (; i < numFaces; ++i )
622 faces[i].materialId = mtlId;
626 /* model mesh vertex */
627 else if ( !_pico_stricmp( p->token,"*mesh_vertex" ) ) {
630 if ( numVertices == 0 ) {
631 _ase_error_return( "Vertex parse error" );
634 /* get vertex data (orig: index +y -x +z) */
635 if ( !_pico_parse_int( p,&index ) ) {
636 _ase_error_return( "Vertex parse error" );
638 if ( !_pico_parse_vec( p,vertices[index].xyz ) ) {
639 _ase_error_return( "Vertex parse error" );
642 vertices[index].id = vertexId++;
644 /* model mesh vertex normal */
645 else if ( !_pico_stricmp( p->token,"*mesh_vertexnormal" ) ) {
648 if ( numVertices == 0 ) {
649 _ase_error_return( "Vertex parse error" );
652 /* get vertex data (orig: index +y -x +z) */
653 if ( !_pico_parse_int( p,&index ) ) {
654 _ase_error_return( "Vertex parse error" );
656 if ( !_pico_parse_vec( p,vertices[index].normal ) ) {
657 _ase_error_return( "Vertex parse error" );
660 /* model mesh face */
661 else if ( !_pico_stricmp( p->token,"*mesh_face" ) ) {
662 picoIndex_t indexes[3];
665 if ( numFaces == 0 ) {
666 _ase_error_return( "Face parse error" );
670 if ( !_pico_parse_int( p,&index ) ) {
671 _ase_error_return( "Face parse error" );
674 /* get 1st vertex index */
676 if ( !_pico_parse_int( p,&indexes[0] ) ) {
677 _ase_error_return( "Face parse error" );
680 /* get 2nd vertex index */
682 if ( !_pico_parse_int( p,&indexes[1] ) ) {
683 _ase_error_return( "Face parse error" );
686 /* get 3rd vertex index */
688 if ( !_pico_parse_int( p,&indexes[2] ) ) {
689 _ase_error_return( "Face parse error" );
692 /* parse to the subMaterial ID */
695 if ( !_pico_parse( p,0 ) ) { /* EOL */
698 if ( !_pico_stricmp( p->token,"*MESH_SMOOTHING" ) ) {
699 _pico_parse_int( p, &faces[index].smoothingGroup );
701 if ( !_pico_stricmp( p->token,"*MESH_MTLID" ) ) {
702 _pico_parse_int( p, &faces[index].subMaterialId );
706 faces[index].materialId = 0;
707 faces[index].indices[0] = indexes[2];
708 faces[index].indices[1] = indexes[1];
709 faces[index].indices[2] = indexes[0];
711 /* model texture vertex */
712 else if ( !_pico_stricmp( p->token,"*mesh_tvert" ) ) {
715 if ( numVertices == 0 ) {
716 _ase_error_return( "Texture Vertex parse error" );
719 /* get uv vertex index */
720 if ( !_pico_parse_int( p,&index ) || index >= numTextureVertices ) {
721 _ase_error_return( "Texture vertex parse error" );
724 /* get uv vertex s */
725 if ( !_pico_parse_float( p,&texcoords[index].texcoord[0] ) ) {
726 _ase_error_return( "Texture vertex parse error" );
729 /* get uv vertex t */
730 if ( !_pico_parse_float( p,&texcoords[index].texcoord[1] ) ) {
731 _ase_error_return( "Texture vertex parse error" );
734 /* ydnar: invert t */
735 texcoords[index].texcoord[ 1 ] = 1.0f - texcoords[index].texcoord[ 1 ];
737 /* ydnar: model mesh texture face */
738 else if ( !_pico_stricmp( p->token, "*mesh_tface" ) ) {
739 picoIndex_t indexes[3];
742 if ( numFaces == 0 ) {
743 _ase_error_return( "Texture face parse error" );
747 if ( !_pico_parse_int( p,&index ) ) {
748 _ase_error_return( "Texture face parse error" );
751 /* get 1st vertex index */
752 if ( !_pico_parse_int( p,&indexes[0] ) ) {
753 _ase_error_return( "Texture face parse error" );
756 /* get 2nd vertex index */
757 if ( !_pico_parse_int( p,&indexes[1] ) ) {
758 _ase_error_return( "Texture face parse error" );
761 /* get 3rd vertex index */
762 if ( !_pico_parse_int( p,&indexes[2] ) ) {
763 _ase_error_return( "Texture face parse error" );
766 faces[index].indices[3] = indexes[2];
767 faces[index].indices[4] = indexes[1];
768 faces[index].indices[5] = indexes[0];
770 /* model color vertex */
771 else if ( !_pico_stricmp( p->token,"*mesh_vertcol" ) ) {
775 if ( numVertices == 0 ) {
776 _ase_error_return( "Color Vertex parse error" );
779 /* get color vertex index */
780 if ( !_pico_parse_int( p,&index ) ) {
781 _ase_error_return( "Color vertex parse error" );
784 /* get R component */
785 if ( !_pico_parse_float( p,&colorInput ) ) {
786 _ase_error_return( "Color vertex parse error" );
788 colors[index].color[0] = (picoByte_t)( colorInput * 255 );
790 /* get G component */
791 if ( !_pico_parse_float( p,&colorInput ) ) {
792 _ase_error_return( "Color vertex parse error" );
794 colors[index].color[1] = (picoByte_t)( colorInput * 255 );
796 /* get B component */
797 if ( !_pico_parse_float( p,&colorInput ) ) {
798 _ase_error_return( "Color vertex parse error" );
800 colors[index].color[2] = (picoByte_t)( colorInput * 255 );
802 /* leave alpha alone since we don't get any data from the ASE format */
803 colors[index].color[3] = 255;
805 /* model color face */
806 else if ( !_pico_stricmp( p->token,"*mesh_cface" ) ) {
807 picoIndex_t indexes[3];
810 if ( numFaces == 0 ) {
811 _ase_error_return( "Face parse error" );
815 if ( !_pico_parse_int( p,&index ) ) {
816 _ase_error_return( "Face parse error" );
819 /* get 1st cvertex index */
820 // _pico_parse( p,0 );
821 if ( !_pico_parse_int( p,&indexes[0] ) ) {
822 _ase_error_return( "Face parse error" );
825 /* get 2nd cvertex index */
826 // _pico_parse( p,0 );
827 if ( !_pico_parse_int( p,&indexes[1] ) ) {
828 _ase_error_return( "Face parse error" );
831 /* get 3rd cvertex index */
832 // _pico_parse( p,0 );
833 if ( !_pico_parse_int( p,&indexes[2] ) ) {
834 _ase_error_return( "Face parse error" );
837 faces[index].indices[6] = indexes[2];
838 faces[index].indices[7] = indexes[1];
839 faces[index].indices[8] = indexes[0];
842 else if ( !_pico_stricmp( p->token, "*material" ) ) {
843 aseSubMaterial_t* subMaterial = NULL;
844 picoShader_t *shader = NULL;
845 int level = 1, index;
846 char materialName[ 1024 ];
847 float transValue = 0.0f, shineValue = 1.0f;
848 picoColor_t ambientColor, diffuseColor, specularColor;
849 char *mapname = NULL;
850 int subMtlId, subMaterialLevel = -1;
853 /* get material index */
854 _pico_parse_int( p,&index );
857 if ( !_pico_parse_check( p,1,"{" ) ) {
858 _ase_error_return( "Material missing opening brace" );
861 /* parse material block */
865 if ( _pico_parse( p,1 ) == NULL ) {
868 if ( !strlen( p->token ) ) {
873 if ( p->token[0] == '{' ) {
876 if ( p->token[0] == '}' ) {
883 if ( level == subMaterialLevel ) {
884 /* set material name */
885 _pico_first_token( materialName );
886 shadername_convert( materialName );
887 PicoSetShaderName( shader, materialName );
889 /* set shader's transparency */
890 PicoSetShaderTransparency( shader,transValue );
892 /* set shader's ambient color */
893 PicoSetShaderAmbientColor( shader,ambientColor );
895 /* set diffuse alpha to transparency */
896 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
898 /* set shader's diffuse color */
899 PicoSetShaderDiffuseColor( shader,diffuseColor );
901 /* set shader's specular color */
902 PicoSetShaderSpecularColor( shader,specularColor );
904 /* set shader's shininess */
905 PicoSetShaderShininess( shader,shineValue );
907 /* set material map name */
908 PicoSetShaderMapName( shader, mapname );
910 subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader );
911 subMaterialLevel = -1;
914 /* parse submaterial index */
915 if ( !_pico_stricmp( p->token,"*submaterial" ) ) {
916 /* allocate new pico shader */
917 _pico_parse_int( p, &subMtlId );
919 shader = PicoNewShader( model );
920 if ( shader == NULL ) {
921 PicoFreeModel( model );
924 subMaterialLevel = level;
926 /* parse material name */
927 else if ( !_pico_stricmp( p->token,"*material_name" ) ) {
928 char* name = _pico_parse( p,0 );
929 if ( name == NULL ) {
930 _ase_error_return( "Missing material name" );
933 strcpy( materialName, name );
934 /* skip rest and continue with next token */
935 _pico_parse_skip_rest( p );
938 /* parse material transparency */
939 else if ( !_pico_stricmp( p->token,"*material_transparency" ) ) {
940 /* get transparency value from ase */
941 if ( !_pico_parse_float( p,&transValue ) ) {
942 _ase_error_return( "Material transparency parse error" );
945 /* skip rest and continue with next token */
946 _pico_parse_skip_rest( p );
949 /* parse material shininess */
950 else if ( !_pico_stricmp( p->token,"*material_shine" ) ) {
952 * - not sure but instead of '*material_shine' i might
953 * need to use '*material_shinestrength' */
955 /* get shine value from ase */
956 if ( !_pico_parse_float( p,&shineValue ) ) {
957 _ase_error_return( "Material shine parse error" );
960 /* scale ase shine range 0..1 to pico range 0..127 */
963 /* skip rest and continue with next token */
964 _pico_parse_skip_rest( p );
967 /* parse ambient material color */
968 else if ( !_pico_stricmp( p->token,"*material_ambient" ) ) {
970 /* get r,g,b float values from ase */
971 if ( !_pico_parse_vec( p,vec ) ) {
972 _ase_error_return( "Material color parse error" );
975 /* setup 0..255 range color values */
976 ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
977 ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
978 ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
979 ambientColor[ 3 ] = (int)( 255 );
981 /* skip rest and continue with next token */
982 _pico_parse_skip_rest( p );
985 /* parse diffuse material color */
986 else if ( !_pico_stricmp( p->token,"*material_diffuse" ) ) {
989 /* get r,g,b float values from ase */
990 if ( !_pico_parse_vec( p,vec ) ) {
991 _ase_error_return( "Material color parse error" );
994 /* setup 0..255 range color */
995 diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
996 diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
997 diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
998 diffuseColor[ 3 ] = (int)( 255 );
1000 /* skip rest and continue with next token */
1001 _pico_parse_skip_rest( p );
1004 /* parse specular material color */
1005 else if ( !_pico_stricmp( p->token,"*material_specular" ) ) {
1008 /* get r,g,b float values from ase */
1009 if ( !_pico_parse_vec( p,vec ) ) {
1010 _ase_error_return( "Material color parse error" );
1013 /* setup 0..255 range color */
1014 specularColor[ 0 ] = (int)( vec[ 0 ] * 255 );
1015 specularColor[ 1 ] = (int)( vec[ 1 ] * 255 );
1016 specularColor[ 2 ] = (int)( vec[ 2 ] * 255 );
1017 specularColor[ 3 ] = (int)( 255 );
1019 /* skip rest and continue with next token */
1020 _pico_parse_skip_rest( p );
1023 /* material diffuse map */
1024 else if ( !_pico_stricmp( p->token,"*map_diffuse" ) ) {
1027 /* parse material block */
1030 /* get next token */
1031 if ( _pico_parse( p,1 ) == NULL ) {
1034 if ( !strlen( p->token ) ) {
1039 if ( p->token[0] == '{' ) {
1042 if ( p->token[0] == '}' ) {
1049 /* parse diffuse map bitmap */
1050 if ( !_pico_stricmp( p->token,"*bitmap" ) ) {
1051 char* name = _pico_parse( p,0 );
1052 if ( name == NULL ) {
1053 _ase_error_return( "Missing material map bitmap name" );
1055 mapname = _pico_alloc( strlen( name ) + 1 );
1056 strcpy( mapname, name );
1057 /* skip rest and continue with next token */
1058 _pico_parse_skip_rest( p );
1063 /* end map_diffuse block */
1065 /* end material block */
1067 if ( subMaterial == NULL ) {
1068 /* allocate new pico shader */
1069 shader = PicoNewShader( model );
1070 if ( shader == NULL ) {
1071 PicoFreeModel( model );
1075 /* set material name */
1076 shadername_convert( materialName );
1077 PicoSetShaderName( shader,materialName );
1079 /* set shader's transparency */
1080 PicoSetShaderTransparency( shader,transValue );
1082 /* set shader's ambient color */
1083 PicoSetShaderAmbientColor( shader,ambientColor );
1085 /* set diffuse alpha to transparency */
1086 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
1088 /* set shader's diffuse color */
1089 PicoSetShaderDiffuseColor( shader,diffuseColor );
1091 /* set shader's specular color */
1092 PicoSetShaderSpecularColor( shader,specularColor );
1094 /* set shader's shininess */
1095 PicoSetShaderShininess( shader,shineValue );
1097 /* set material map name */
1098 PicoSetShaderMapName( shader, mapname );
1100 /* extract shadername from bitmap path */
1101 if ( mapname != NULL ) {
1104 /* convert to shader-name format */
1105 shadername_convert( mapname );
1107 /* remove extension */
1108 char* last_period = strrchr( p, '.' );
1109 if ( last_period != NULL ) {
1110 *last_period = '\0';
1114 /* find shader path */
1115 for (; *p != '\0'; ++p )
1117 if ( _pico_strnicmp( p, "models/", 7 ) == 0 || _pico_strnicmp( p, "textures/", 9 ) == 0 ) {
1123 /* set material name */
1124 PicoSetShaderName( shader,p );
1128 /* this is just a material with 1 submaterial */
1129 subMaterial = _ase_add_submaterial( &materials, index, 0, shader );
1132 /* ydnar: free mapname */
1133 if ( mapname != NULL ) {
1134 _pico_free( mapname );
1136 } // !_pico_stricmp ( "*material" )
1138 /* skip unparsed rest of line and continue */
1139 _pico_parse_skip_rest( p );
1142 /* ydnar: finish existing surface */
1143 _ase_submit_triangles( model, materials, vertices, texcoords, colors, faces, numFaces, lastNodeName );
1144 _pico_free( faces );
1145 _pico_free( vertices );
1146 _pico_free( texcoords );
1147 _pico_free( colors );
1150 _ase_print_materials( materials );
1152 elapsed = (double)( finish - start ) / CLOCKS_PER_SEC;
1153 _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed );
1154 #endif //DEBUG_PM_ASE
1156 _ase_free_materials( &materials );
1158 _pico_free_parser( p );
1160 /* return allocated pico model */
1164 /* pico file format module definition */
1165 const picoModule_t picoModuleASE =
1167 "1.0", /* module version string */
1168 "Autodesk 3DSMAX ASCII", /* module display name */
1169 "Jared Hefty, seaw0lf", /* author's name */
1170 "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */
1172 "ase",NULL,NULL,NULL /* default extensions to use */
1174 _ase_canload, /* validation routine */
1175 _ase_load, /* load routine */
1176 NULL, /* save validation routine */
1177 NULL /* save routine */