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 ----------------------------------------------------------------------------- */
39 /* uncomment when debugging this module */
40 //#define DEBUG_PM_ASE
41 //#define DEBUG_PM_ASE_EX
45 #include "picointernal.h"
52 static picoColor_t white = { 255, 255, 255, 255 };
54 /* jhefty - multi-subobject material support */
56 /* Material/SubMaterial management */
57 /* A material should have 1..n submaterials assigned to it */
59 typedef struct aseSubMaterial_s
61 struct aseSubMaterial_s* next;
67 typedef struct aseMaterial_s
69 struct aseMaterial_s* next;
70 struct aseSubMaterial_s* subMtls;
74 /* Material/SubMaterial management functions */
75 static aseMaterial_t* _ase_get_material( aseMaterial_t* list, int mtlIdParent ){
76 aseMaterial_t* mtl = list;
80 if ( mtlIdParent == mtl->mtlId ) {
88 static aseSubMaterial_t* _ase_get_submaterial( aseMaterial_t* list, int mtlIdParent, int subMtlId ){
89 aseMaterial_t* parent = _ase_get_material( list, mtlIdParent );
90 aseSubMaterial_t* subMtl = NULL;
93 _pico_printf( PICO_ERROR, "No ASE material exists with id %i\n", mtlIdParent );
97 subMtl = parent->subMtls;
100 if ( subMtlId == subMtl->subMtlId ) {
103 subMtl = subMtl->next;
108 aseSubMaterial_t* _ase_get_submaterial_or_default( aseMaterial_t* materials, int mtlIdParent, int subMtlId ){
109 aseSubMaterial_t* subMtl = _ase_get_submaterial( materials, mtlIdParent, subMtlId );
110 if ( subMtl != NULL ) {
114 /* ydnar: trying default submaterial */
115 subMtl = _ase_get_submaterial( materials, mtlIdParent, 0 );
116 if ( subMtl != NULL ) {
120 _pico_printf( PICO_ERROR, "Could not find material/submaterial for id %d/%d\n", mtlIdParent, subMtlId );
127 static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent ){
128 aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) );
129 mtl->mtlId = mtlIdParent;
137 static aseSubMaterial_t* _ase_add_submaterial( aseMaterial_t **list, int mtlIdParent, int subMtlId, picoShader_t* shader ){
138 aseMaterial_t *parent = _ase_get_material( *list, mtlIdParent );
139 aseSubMaterial_t *subMtl = _pico_calloc( 1, sizeof( aseSubMaterial_t ) );
142 parent = _ase_add_material( list, mtlIdParent );
145 subMtl->shader = shader;
146 subMtl->subMtlId = subMtlId;
147 subMtl->next = parent->subMtls;
148 parent->subMtls = subMtl;
153 static void _ase_free_materials( aseMaterial_t **list ){
154 aseMaterial_t* mtl = *list;
155 aseSubMaterial_t* subMtl = NULL;
157 aseMaterial_t* mtlTemp = NULL;
158 aseSubMaterial_t* subMtlTemp = NULL;
162 subMtl = mtl->subMtls;
165 subMtlTemp = subMtl->next;
166 _pico_free( subMtl );
177 static void _ase_print_materials( aseMaterial_t *list ){
178 aseMaterial_t* mtl = list;
179 aseSubMaterial_t* subMtl = NULL;
183 _pico_printf( PICO_NORMAL, "ASE Material %i", mtl->mtlId );
184 subMtl = mtl->subMtls;
187 _pico_printf( PICO_NORMAL, " -- ASE SubMaterial %i - %s\n", subMtl->subMtlId, subMtl->shader->name );
188 subMtl = subMtl->next;
193 #endif //DEBUG_PM_ASE
196 * - apply material specific uv offsets to uv coordinates
200 * validates a 3dsmax ase model file.
202 static int _ase_canload( PM_PARAMS_CANLOAD ){
206 /* quick data length validation */
207 if ( bufSize < 80 ) {
208 return PICO_PMV_ERROR_SIZE;
211 /* create pico parser */
212 p = _pico_new_parser( (const picoByte_t*) buffer, bufSize );
214 return PICO_PMV_ERROR_MEMORY;
217 /* get first token */
218 if ( _pico_parse_first( p ) == NULL ) {
219 return PICO_PMV_ERROR_IDENT;
222 /* check first token */
223 if ( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) ) {
224 _pico_free_parser( p );
225 return PICO_PMV_ERROR_IDENT;
228 /* free the pico parser object */
229 _pico_free_parser( p );
231 /* file seems to be a valid ase file */
235 typedef struct aseVertex_s aseVertex_t;
243 typedef struct aseTexCoord_s aseTexCoord_t;
249 typedef struct aseColor_s aseColor_t;
255 typedef struct aseFace_s aseFace_t;
258 picoIndex_t indices[9];
259 picoIndex_t smoothingGroup;
260 picoIndex_t materialId;
261 picoIndex_t subMaterialId;
263 typedef aseFace_t* aseFacesIter_t;
265 picoSurface_t* PicoModelFindOrAddSurface( picoModel_t *model, picoShader_t* shader ){
266 /* see if a surface already has the shader */
268 for ( ; i < model->numSurfaces ; i++ )
270 picoSurface_t* workSurface = model->surface[i];
271 if ( workSurface->shader == shader ) {
276 /* no surface uses this shader yet, so create a new surface */
279 /* create a new surface in the model for the unique shader */
280 picoSurface_t* workSurface = PicoNewSurface( model );
281 if ( !workSurface ) {
282 _pico_printf( PICO_ERROR, "Could not allocate a new surface!\n" );
286 /* do surface setup */
287 PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
288 PicoSetSurfaceName( workSurface, shader->name );
289 PicoSetSurfaceShader( workSurface, shader );
295 /* _ase_submit_triangles - jhefty
296 use the surface and the current face list to look up material/submaterial IDs
297 and submit them to the model for proper processing
299 The following still holds from ydnar's _ase_make_surface:
300 indexes 0 1 2 = vert indexes
301 indexes 3 4 5 = st indexes
302 indexes 6 7 8 = color indexes (new)
306 typedef picoIndex_t* picoIndexIter_t;
308 typedef struct aseUniqueIndices_s aseUniqueIndices_t;
309 struct aseUniqueIndices_s
317 size_t aseUniqueIndices_size( aseUniqueIndices_t* self ){
318 return self->last - self->data;
321 void aseUniqueIndices_reserve( aseUniqueIndices_t* self, picoIndex_t size ){
322 self->data = self->last = (picoIndex_t*)_pico_calloc( size, sizeof( picoIndex_t ) );
325 void aseUniqueIndices_clear( aseUniqueIndices_t* self ){
326 _pico_free( self->data );
329 void aseUniqueIndices_pushBack( aseUniqueIndices_t* self, picoIndex_t index ){
330 *self->last++ = index;
333 picoIndex_t aseFaces_getVertexIndex( aseFace_t* faces, picoIndex_t index ){
334 return faces[index / 3].indices[index % 3];
337 picoIndex_t aseFaces_getTexCoordIndex( aseFace_t* faces, picoIndex_t index ){
338 return faces[index / 3].indices[( index % 3 ) + 3];
341 picoIndex_t aseFaces_getColorIndex( aseFace_t* faces, picoIndex_t index ){
342 return faces[index / 3].indices[( index % 3 ) + 6];
345 int aseUniqueIndex_equal( aseFace_t* faces, picoIndex_t index, picoIndex_t other ){
346 return aseFaces_getVertexIndex( faces, index ) == aseFaces_getVertexIndex( faces, other )
347 && aseFaces_getTexCoordIndex( faces, index ) == aseFaces_getTexCoordIndex( faces, other )
348 && aseFaces_getColorIndex( faces, index ) == aseFaces_getColorIndex( faces, other );
351 picoIndex_t aseUniqueIndices_insertUniqueVertex( aseUniqueIndices_t* self, picoIndex_t index ){
352 picoIndexIter_t i = self->data;
353 for (; i != self->last; ++i )
355 picoIndex_t other = (picoIndex_t)( i - self->data );
356 if ( aseUniqueIndex_equal( self->faces, index, other ) ) {
361 aseUniqueIndices_pushBack( self, index );
362 return (picoIndex_t)( aseUniqueIndices_size( self ) - 1 );
365 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 ){
366 aseFacesIter_t i = faces, end = faces + numFaces;
368 aseUniqueIndices_t indices;
369 aseUniqueIndices_t remap;
370 aseUniqueIndices_reserve( &indices, numFaces * 3 );
371 aseUniqueIndices_reserve( &remap, numFaces * 3 );
372 indices.faces = faces;
374 for (; i != end; ++i )
376 /* look up the shader for the material/submaterial pair */
377 aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, ( *i ).materialId, ( *i ).subMaterialId );
378 if ( subMtl == NULL ) {
383 picoSurface_t* surface = PicoModelFindOrAddSurface( model, subMtl->shader );
385 /* we pull the data from the vertex, color and texcoord arrays using the face index data */
386 for ( j = 0 ; j < 3 ; j++ )
388 picoIndex_t index = (picoIndex_t)( ( ( i - faces ) * 3 ) + j );
389 picoIndex_t size = (picoIndex_t)aseUniqueIndices_size( &indices );
390 picoIndex_t unique = aseUniqueIndices_insertUniqueVertex( &indices, index );
392 picoIndex_t numVertexes = PicoGetSurfaceNumVertexes( surface );
393 picoIndex_t numIndexes = PicoGetSurfaceNumIndexes( surface );
395 aseUniqueIndices_pushBack( &remap, numIndexes );
397 PicoSetSurfaceIndex( surface, numIndexes, remap.data[unique] );
399 if ( unique == size ) {
400 PicoSetSurfaceXYZ( surface, numVertexes, vertices[( *i ).indices[j]].xyz );
401 PicoSetSurfaceNormal( surface, numVertexes, vertices[( *i ).indices[j]].normal );
402 PicoSetSurfaceST( surface, 0, numVertexes, texcoords[( *i ).indices[j + 3]].texcoord );
404 if ( ( *i ).indices[j + 6] >= 0 ) {
405 PicoSetSurfaceColor( surface, 0, numVertexes, colors[( *i ).indices[j + 6]].color );
409 PicoSetSurfaceColor( surface, 0, numVertexes, white );
412 PicoSetSurfaceSmoothingGroup( surface, numVertexes, ( vertices[( *i ).indices[j]].id * ( 1 << 16 ) ) + ( *i ).smoothingGroup );
418 aseUniqueIndices_clear( &indices );
419 aseUniqueIndices_clear( &remap );
424 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 ){
425 aseFacesIter_t i = faces, end = faces + numFaces;
426 for (; i != end; ++i )
428 /* look up the shader for the material/submaterial pair */
429 aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, ( *i ).materialId, ( *i ).subMaterialId );
430 if ( subMtl == NULL ) {
436 picoVec3_t* normal[3];
438 picoColor_t* color[3];
439 picoIndex_t smooth[3];
441 /* we pull the data from the vertex, color and texcoord arrays using the face index data */
442 for ( j = 0 ; j < 3 ; j++ )
444 xyz[j] = &vertices[( *i ).indices[j]].xyz;
445 normal[j] = &vertices[( *i ).indices[j]].normal;
446 st[j] = &texcoords[( *i ).indices[j + 3]].texcoord;
448 if ( colors != NULL && ( *i ).indices[j + 6] >= 0 ) {
449 color[j] = &colors[( *i ).indices[j + 6]].color;
456 smooth[j] = ( vertices[( *i ).indices[j]].id * ( 1 << 16 ) ) + ( *i ).smoothingGroup; /* don't merge vertices */
460 /* submit the triangle to the model */
461 PicoAddTriangleToModel( model, xyz, normal, 1, st, 1, color, subMtl->shader, name, smooth );
466 static void shadername_convert( char* shaderName ){
467 /* unix-style path separators */
468 char* s = shaderName;
469 for (; *s != '\0'; ++s )
479 * loads a 3dsmax ase model file.
481 static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
484 char lastNodeName[ 1024 ];
486 aseVertex_t* vertices = NULL;
487 aseTexCoord_t* texcoords = NULL;
488 aseColor_t* colors = NULL;
489 aseFace_t* faces = NULL;
492 int numTextureVertices = 0;
493 int numTextureVertexFaces = 0;
494 int numColorVertices = 0;
495 int numColorVertexFaces = 0;
498 aseMaterial_t* materials = NULL;
501 clock_t start, finish;
507 #define _ase_error_return( m ) \
509 _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine ); \
510 _pico_free_parser( p ); \
511 PicoFreeModel( model ); \
514 /* create a new pico parser */
515 p = _pico_new_parser( (const picoByte_t *)buffer,bufSize );
520 /* create a new pico model */
521 model = PicoNewModel();
522 if ( model == NULL ) {
523 _pico_free_parser( p );
527 PicoSetModelFrameNum( model, frameNum );
528 PicoSetModelName( model, fileName );
529 PicoSetModelFileName( model, fileName );
531 /* initialize some stuff */
532 memset( lastNodeName,0,sizeof( lastNodeName ) );
534 /* parse ase model file */
537 /* get first token on line */
538 if ( _pico_parse_first( p ) == NULL ) {
542 /* we just skip empty lines */
543 if ( p->token == NULL || !strlen( p->token ) ) {
547 /* we skip invalid ase statements */
548 if ( p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}' ) {
549 _pico_parse_skip_rest( p );
552 /* remember node name */
553 if ( !_pico_stricmp( p->token,"*node_name" ) ) {
555 char *ptr = _pico_parse( p,0 );
557 _ase_error_return( "Node name parse error" );
560 /* remember node name */
561 strncpy( lastNodeName,ptr,sizeof( lastNodeName ) );
563 /* model mesh (originally contained within geomobject) */
564 else if ( !_pico_stricmp( p->token,"*mesh" ) ) {
565 /* finish existing surface */
566 _ase_submit_triangles( model, materials, vertices, texcoords, colors, faces, numFaces, lastNodeName );
568 _pico_free( vertices );
569 _pico_free( texcoords );
570 _pico_free( colors );
572 else if ( !_pico_stricmp( p->token,"*mesh_numvertex" ) ) {
573 if ( !_pico_parse_int( p, &numVertices ) ) {
574 _ase_error_return( "Missing MESH_NUMVERTEX value" );
577 vertices = _pico_calloc( numVertices, sizeof( aseVertex_t ) );
579 else if ( !_pico_stricmp( p->token,"*mesh_numfaces" ) ) {
580 if ( !_pico_parse_int( p, &numFaces ) ) {
581 _ase_error_return( "Missing MESH_NUMFACES value" );
584 faces = _pico_calloc( numFaces, sizeof( aseFace_t ) );
586 else if ( !_pico_stricmp( p->token,"*mesh_numtvertex" ) ) {
587 if ( !_pico_parse_int( p, &numTextureVertices ) ) {
588 _ase_error_return( "Missing MESH_NUMTVERTEX value" );
591 texcoords = _pico_calloc( numTextureVertices, sizeof( aseTexCoord_t ) );
593 else if ( !_pico_stricmp( p->token,"*mesh_numtvfaces" ) ) {
594 if ( !_pico_parse_int( p, &numTextureVertexFaces ) ) {
595 _ase_error_return( "Missing MESH_NUMTVFACES value" );
598 else if ( !_pico_stricmp( p->token,"*mesh_numcvertex" ) ) {
599 if ( !_pico_parse_int( p, &numColorVertices ) ) {
600 _ase_error_return( "Missing MESH_NUMCVERTEX value" );
603 colors = _pico_calloc( numColorVertices, sizeof( aseColor_t ) );
604 memset( colors, 255, numColorVertices * sizeof( aseColor_t ) ); /* ydnar: force colors to white initially */
606 else if ( !_pico_stricmp( p->token,"*mesh_numcvfaces" ) ) {
607 if ( !_pico_parse_int( p, &numColorVertexFaces ) ) {
608 _ase_error_return( "Missing MESH_NUMCVFACES value" );
611 /* mesh material reference. this usually comes at the end of */
612 /* geomobjects after the mesh blocks. we must assume that the */
613 /* new mesh was already created so all we can do here is assign */
614 /* the material reference id (shader index) now. */
615 else if ( !_pico_stricmp( p->token,"*material_ref" ) ) {
618 /* get the material ref (0..n) */
619 if ( !_pico_parse_int( p,&mtlId ) ) {
620 _ase_error_return( "Missing material reference ID" );
625 /* fix up all of the aseFaceList in the surface to point to the parent material */
626 /* we've already saved off their subMtl */
627 for (; i < numFaces; ++i )
629 faces[i].materialId = mtlId;
633 /* model mesh vertex */
634 else if ( !_pico_stricmp( p->token,"*mesh_vertex" ) ) {
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].xyz ) ) {
646 _ase_error_return( "Vertex parse error" );
649 vertices[index].id = vertexId++;
651 /* model mesh vertex normal */
652 else if ( !_pico_stricmp( p->token,"*mesh_vertexnormal" ) ) {
655 if ( numVertices == 0 ) {
656 _ase_error_return( "Vertex parse error" );
659 /* get vertex data (orig: index +y -x +z) */
660 if ( !_pico_parse_int( p,&index ) ) {
661 _ase_error_return( "Vertex parse error" );
663 if ( !_pico_parse_vec( p,vertices[index].normal ) ) {
664 _ase_error_return( "Vertex parse error" );
667 /* model mesh face */
668 else if ( !_pico_stricmp( p->token,"*mesh_face" ) ) {
669 picoIndex_t indexes[3];
672 if ( numFaces == 0 ) {
673 _ase_error_return( "Face parse error" );
677 if ( !_pico_parse_int( p,&index ) ) {
678 _ase_error_return( "Face parse error" );
681 /* get 1st vertex index */
683 if ( !_pico_parse_int( p,&indexes[0] ) ) {
684 _ase_error_return( "Face parse error" );
687 /* get 2nd vertex index */
689 if ( !_pico_parse_int( p,&indexes[1] ) ) {
690 _ase_error_return( "Face parse error" );
693 /* get 3rd vertex index */
695 if ( !_pico_parse_int( p,&indexes[2] ) ) {
696 _ase_error_return( "Face parse error" );
699 /* parse to the subMaterial ID */
702 if ( !_pico_parse( p,0 ) ) { /* EOL */
705 if ( !_pico_stricmp( p->token,"*MESH_SMOOTHING" ) ) {
706 _pico_parse_int( p, &faces[index].smoothingGroup );
708 if ( !_pico_stricmp( p->token,"*MESH_MTLID" ) ) {
709 _pico_parse_int( p, &faces[index].subMaterialId );
713 faces[index].materialId = 0;
714 faces[index].indices[0] = indexes[2];
715 faces[index].indices[1] = indexes[1];
716 faces[index].indices[2] = indexes[0];
718 /* model texture vertex */
719 else if ( !_pico_stricmp( p->token,"*mesh_tvert" ) ) {
722 if ( numVertices == 0 ) {
723 _ase_error_return( "Texture Vertex parse error" );
726 /* get uv vertex index */
727 if ( !_pico_parse_int( p,&index ) || index >= numTextureVertices ) {
728 _ase_error_return( "Texture vertex parse error" );
731 /* get uv vertex s */
732 if ( !_pico_parse_float( p,&texcoords[index].texcoord[0] ) ) {
733 _ase_error_return( "Texture vertex parse error" );
736 /* get uv vertex t */
737 if ( !_pico_parse_float( p,&texcoords[index].texcoord[1] ) ) {
738 _ase_error_return( "Texture vertex parse error" );
741 /* ydnar: invert t */
742 texcoords[index].texcoord[ 1 ] = 1.0f - texcoords[index].texcoord[ 1 ];
744 /* ydnar: model mesh texture face */
745 else if ( !_pico_stricmp( p->token, "*mesh_tface" ) ) {
746 picoIndex_t indexes[3];
749 if ( numFaces == 0 ) {
750 _ase_error_return( "Texture face parse error" );
754 if ( !_pico_parse_int( p,&index ) ) {
755 _ase_error_return( "Texture face parse error" );
758 /* get 1st vertex index */
759 if ( !_pico_parse_int( p,&indexes[0] ) ) {
760 _ase_error_return( "Texture face parse error" );
763 /* get 2nd vertex index */
764 if ( !_pico_parse_int( p,&indexes[1] ) ) {
765 _ase_error_return( "Texture face parse error" );
768 /* get 3rd vertex index */
769 if ( !_pico_parse_int( p,&indexes[2] ) ) {
770 _ase_error_return( "Texture face parse error" );
773 faces[index].indices[3] = indexes[2];
774 faces[index].indices[4] = indexes[1];
775 faces[index].indices[5] = indexes[0];
777 /* model color vertex */
778 else if ( !_pico_stricmp( p->token,"*mesh_vertcol" ) ) {
782 if ( numVertices == 0 ) {
783 _ase_error_return( "Color Vertex parse error" );
786 /* get color vertex index */
787 if ( !_pico_parse_int( p,&index ) ) {
788 _ase_error_return( "Color vertex parse error" );
791 /* get R component */
792 if ( !_pico_parse_float( p,&colorInput ) ) {
793 _ase_error_return( "Color vertex parse error" );
795 colors[index].color[0] = (picoByte_t)( colorInput * 255 );
797 /* get G component */
798 if ( !_pico_parse_float( p,&colorInput ) ) {
799 _ase_error_return( "Color vertex parse error" );
801 colors[index].color[1] = (picoByte_t)( colorInput * 255 );
803 /* get B component */
804 if ( !_pico_parse_float( p,&colorInput ) ) {
805 _ase_error_return( "Color vertex parse error" );
807 colors[index].color[2] = (picoByte_t)( colorInput * 255 );
809 /* leave alpha alone since we don't get any data from the ASE format */
810 colors[index].color[3] = 255;
812 /* model color face */
813 else if ( !_pico_stricmp( p->token,"*mesh_cface" ) ) {
814 picoIndex_t indexes[3];
817 if ( numFaces == 0 ) {
818 _ase_error_return( "Face parse error" );
822 if ( !_pico_parse_int( p,&index ) ) {
823 _ase_error_return( "Face parse error" );
826 /* get 1st cvertex index */
827 // _pico_parse( p,0 );
828 if ( !_pico_parse_int( p,&indexes[0] ) ) {
829 _ase_error_return( "Face parse error" );
832 /* get 2nd cvertex index */
833 // _pico_parse( p,0 );
834 if ( !_pico_parse_int( p,&indexes[1] ) ) {
835 _ase_error_return( "Face parse error" );
838 /* get 3rd cvertex index */
839 // _pico_parse( p,0 );
840 if ( !_pico_parse_int( p,&indexes[2] ) ) {
841 _ase_error_return( "Face parse error" );
844 faces[index].indices[6] = indexes[2];
845 faces[index].indices[7] = indexes[1];
846 faces[index].indices[8] = indexes[0];
849 else if ( !_pico_stricmp( p->token, "*material" ) ) {
850 aseSubMaterial_t* subMaterial = NULL;
851 picoShader_t *shader = NULL;
852 int level = 1, index;
853 char materialName[ 1024 ];
854 float transValue = 0.0f, shineValue = 1.0f;
855 picoColor_t ambientColor, diffuseColor, specularColor;
856 char *mapname = NULL;
857 int subMtlId, subMaterialLevel = -1;
860 /* get material index */
861 _pico_parse_int( p,&index );
864 if ( !_pico_parse_check( p,1,"{" ) ) {
865 _ase_error_return( "Material missing opening brace" );
868 /* parse material block */
872 if ( _pico_parse( p,1 ) == NULL ) {
875 if ( !strlen( p->token ) ) {
880 if ( p->token[0] == '{' ) {
883 if ( p->token[0] == '}' ) {
890 if ( level == subMaterialLevel ) {
891 /* set material name */
892 _pico_first_token( materialName );
893 shadername_convert( materialName );
894 PicoSetShaderName( shader, materialName );
896 /* set shader's transparency */
897 PicoSetShaderTransparency( shader,transValue );
899 /* set shader's ambient color */
900 PicoSetShaderAmbientColor( shader,ambientColor );
902 /* set diffuse alpha to transparency */
903 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
905 /* set shader's diffuse color */
906 PicoSetShaderDiffuseColor( shader,diffuseColor );
908 /* set shader's specular color */
909 PicoSetShaderSpecularColor( shader,specularColor );
911 /* set shader's shininess */
912 PicoSetShaderShininess( shader,shineValue );
914 /* set material map name */
915 PicoSetShaderMapName( shader, mapname );
917 subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader );
918 subMaterialLevel = -1;
921 /* parse submaterial index */
922 if ( !_pico_stricmp( p->token,"*submaterial" ) ) {
923 /* allocate new pico shader */
924 _pico_parse_int( p, &subMtlId );
926 shader = PicoNewShader( model );
927 if ( shader == NULL ) {
928 PicoFreeModel( model );
931 subMaterialLevel = level;
933 /* parse material name */
934 else if ( !_pico_stricmp( p->token,"*material_name" ) ) {
935 char* name = _pico_parse( p,0 );
936 if ( name == NULL ) {
937 _ase_error_return( "Missing material name" );
940 strcpy( materialName, name );
941 /* skip rest and continue with next token */
942 _pico_parse_skip_rest( p );
945 /* parse material transparency */
946 else if ( !_pico_stricmp( p->token,"*material_transparency" ) ) {
947 /* get transparency value from ase */
948 if ( !_pico_parse_float( p,&transValue ) ) {
949 _ase_error_return( "Material transparency parse error" );
952 /* skip rest and continue with next token */
953 _pico_parse_skip_rest( p );
956 /* parse material shininess */
957 else if ( !_pico_stricmp( p->token,"*material_shine" ) ) {
959 * - not sure but instead of '*material_shine' i might
960 * need to use '*material_shinestrength' */
962 /* get shine value from ase */
963 if ( !_pico_parse_float( p,&shineValue ) ) {
964 _ase_error_return( "Material shine parse error" );
967 /* scale ase shine range 0..1 to pico range 0..127 */
970 /* skip rest and continue with next token */
971 _pico_parse_skip_rest( p );
974 /* parse ambient material color */
975 else if ( !_pico_stricmp( p->token,"*material_ambient" ) ) {
977 /* get r,g,b float values from ase */
978 if ( !_pico_parse_vec( p,vec ) ) {
979 _ase_error_return( "Material color parse error" );
982 /* setup 0..255 range color values */
983 ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
984 ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
985 ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
986 ambientColor[ 3 ] = (int)( 255 );
988 /* skip rest and continue with next token */
989 _pico_parse_skip_rest( p );
992 /* parse diffuse material color */
993 else if ( !_pico_stricmp( p->token,"*material_diffuse" ) ) {
996 /* get r,g,b float values from ase */
997 if ( !_pico_parse_vec( p,vec ) ) {
998 _ase_error_return( "Material color parse error" );
1001 /* setup 0..255 range color */
1002 diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
1003 diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
1004 diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
1005 diffuseColor[ 3 ] = (int)( 255 );
1007 /* skip rest and continue with next token */
1008 _pico_parse_skip_rest( p );
1011 /* parse specular material color */
1012 else if ( !_pico_stricmp( p->token,"*material_specular" ) ) {
1015 /* get r,g,b float values from ase */
1016 if ( !_pico_parse_vec( p,vec ) ) {
1017 _ase_error_return( "Material color parse error" );
1020 /* setup 0..255 range color */
1021 specularColor[ 0 ] = (int)( vec[ 0 ] * 255 );
1022 specularColor[ 1 ] = (int)( vec[ 1 ] * 255 );
1023 specularColor[ 2 ] = (int)( vec[ 2 ] * 255 );
1024 specularColor[ 3 ] = (int)( 255 );
1026 /* skip rest and continue with next token */
1027 _pico_parse_skip_rest( p );
1030 /* material diffuse map */
1031 else if ( !_pico_stricmp( p->token,"*map_diffuse" ) ) {
1034 /* parse material block */
1037 /* get next token */
1038 if ( _pico_parse( p,1 ) == NULL ) {
1041 if ( !strlen( p->token ) ) {
1046 if ( p->token[0] == '{' ) {
1049 if ( p->token[0] == '}' ) {
1056 /* parse diffuse map bitmap */
1057 if ( !_pico_stricmp( p->token,"*bitmap" ) ) {
1058 char* name = _pico_parse( p,0 );
1059 if ( name == NULL ) {
1060 _ase_error_return( "Missing material map bitmap name" );
1062 mapname = _pico_alloc( strlen( name ) + 1 );
1063 strcpy( mapname, name );
1064 /* skip rest and continue with next token */
1065 _pico_parse_skip_rest( p );
1070 /* end map_diffuse block */
1072 /* end material block */
1074 if ( subMaterial == NULL ) {
1075 /* allocate new pico shader */
1076 shader = PicoNewShader( model );
1077 if ( shader == NULL ) {
1078 PicoFreeModel( model );
1082 /* set material name */
1083 shadername_convert( materialName );
1084 PicoSetShaderName( shader,materialName );
1086 /* set shader's transparency */
1087 PicoSetShaderTransparency( shader,transValue );
1089 /* set shader's ambient color */
1090 PicoSetShaderAmbientColor( shader,ambientColor );
1092 /* set diffuse alpha to transparency */
1093 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
1095 /* set shader's diffuse color */
1096 PicoSetShaderDiffuseColor( shader,diffuseColor );
1098 /* set shader's specular color */
1099 PicoSetShaderSpecularColor( shader,specularColor );
1101 /* set shader's shininess */
1102 PicoSetShaderShininess( shader,shineValue );
1104 /* set material map name */
1105 PicoSetShaderMapName( shader, mapname );
1107 /* extract shadername from bitmap path */
1108 if ( mapname != NULL ) {
1111 /* convert to shader-name format */
1112 shadername_convert( mapname );
1114 /* remove extension */
1115 char* last_period = strrchr( p, '.' );
1116 if ( last_period != NULL ) {
1117 *last_period = '\0';
1121 /* find shader path */
1122 for (; *p != '\0'; ++p )
1124 if ( _pico_strnicmp( p, "models/", 7 ) == 0 || _pico_strnicmp( p, "textures/", 9 ) == 0 ) {
1130 /* set material name */
1131 PicoSetShaderName( shader,p );
1135 /* this is just a material with 1 submaterial */
1136 subMaterial = _ase_add_submaterial( &materials, index, 0, shader );
1139 /* ydnar: free mapname */
1140 if ( mapname != NULL ) {
1141 _pico_free( mapname );
1143 } // !_pico_stricmp ( "*material" )
1145 /* skip unparsed rest of line and continue */
1146 _pico_parse_skip_rest( p );
1149 /* ydnar: finish existing surface */
1150 _ase_submit_triangles( model, materials, vertices, texcoords, colors, faces, numFaces, lastNodeName );
1151 _pico_free( faces );
1152 _pico_free( vertices );
1153 _pico_free( texcoords );
1154 _pico_free( colors );
1157 _ase_print_materials( materials );
1159 elapsed = (double)( finish - start ) / CLOCKS_PER_SEC;
1160 _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed );
1161 #endif //DEBUG_PM_ASE
1163 _ase_free_materials( &materials );
1165 _pico_free_parser( p );
1167 /* return allocated pico model */
1171 /* pico file format module definition */
1172 const picoModule_t picoModuleASE =
1174 "1.0", /* module version string */
1175 "Autodesk 3DSMAX ASCII", /* module display name */
1176 "Jared Hefty, seaw0lf", /* author's name */
1177 "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */
1179 "ase",NULL,NULL,NULL /* default extensions to use */
1181 _ase_canload, /* validation routine */
1182 _ase_load, /* load routine */
1183 NULL, /* save validation routine */
1184 NULL /* save routine */