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"
48 static picoColor_t white = { 255, 255, 255, 255 };
50 /* jhefty - multi-subobject material support */
52 /* Material/SubMaterial management */
53 /* A material should have 1..n submaterials assigned to it */
55 typedef struct aseSubMaterial_s
57 struct aseSubMaterial_s* next;
63 typedef struct aseMaterial_s
65 struct aseMaterial_s* next;
66 struct aseSubMaterial_s* subMtls;
70 /* Material/SubMaterial management functions */
71 static aseMaterial_t* _ase_get_material( aseMaterial_t* list, int mtlIdParent ){
72 aseMaterial_t* mtl = list;
76 if ( mtlIdParent == mtl->mtlId ) {
84 static aseSubMaterial_t* _ase_get_submaterial( aseMaterial_t* list, int mtlIdParent, int subMtlId ){
85 aseMaterial_t* parent = _ase_get_material( list, mtlIdParent );
86 aseSubMaterial_t* subMtl = NULL;
89 _pico_printf( PICO_ERROR, "No ASE material exists with id %i\n", mtlIdParent );
93 subMtl = parent->subMtls;
96 if ( subMtlId == subMtl->subMtlId ) {
99 subMtl = subMtl->next;
104 aseSubMaterial_t* _ase_get_submaterial_or_default( aseMaterial_t* materials, int mtlIdParent, int subMtlId ){
105 aseSubMaterial_t* subMtl = _ase_get_submaterial( materials, mtlIdParent, subMtlId );
106 if ( subMtl != NULL ) {
110 /* ydnar: trying default submaterial */
111 subMtl = _ase_get_submaterial( materials, mtlIdParent, 0 );
112 if ( subMtl != NULL ) {
116 _pico_printf( PICO_ERROR, "Could not find material/submaterial for id %d/%d\n", mtlIdParent, subMtlId );
123 static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent ){
124 aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) );
125 mtl->mtlId = mtlIdParent;
133 static aseSubMaterial_t* _ase_add_submaterial( aseMaterial_t **list, int mtlIdParent, int subMtlId, picoShader_t* shader ){
134 aseMaterial_t *parent = _ase_get_material( *list, mtlIdParent );
135 aseSubMaterial_t *subMtl = _pico_calloc( 1, sizeof( aseSubMaterial_t ) );
138 parent = _ase_add_material( list, mtlIdParent );
141 subMtl->shader = shader;
142 subMtl->subMtlId = subMtlId;
143 subMtl->next = parent->subMtls;
144 parent->subMtls = subMtl;
149 static void _ase_free_materials( aseMaterial_t **list ){
150 aseMaterial_t* mtl = *list;
151 aseSubMaterial_t* subMtl = NULL;
153 aseMaterial_t* mtlTemp = NULL;
154 aseSubMaterial_t* subMtlTemp = NULL;
158 subMtl = mtl->subMtls;
161 subMtlTemp = subMtl->next;
162 _pico_free( subMtl );
173 static void _ase_print_materials( aseMaterial_t *list ){
174 aseMaterial_t* mtl = list;
175 aseSubMaterial_t* subMtl = NULL;
179 _pico_printf( PICO_NORMAL, "ASE Material %i", mtl->mtlId );
180 subMtl = mtl->subMtls;
183 _pico_printf( PICO_NORMAL, " -- ASE SubMaterial %i - %s\n", subMtl->subMtlId, subMtl->shader->name );
184 subMtl = subMtl->next;
189 #endif //DEBUG_PM_ASE
192 * - apply material specific uv offsets to uv coordinates
196 * validates a 3dsmax ase model file.
198 static int _ase_canload( PM_PARAMS_CANLOAD ){
202 /* quick data length validation */
203 if ( bufSize < 80 ) {
204 return PICO_PMV_ERROR_SIZE;
207 /* create pico parser */
208 p = _pico_new_parser( (const picoByte_t*) buffer, bufSize );
210 return PICO_PMV_ERROR_MEMORY;
213 /* get first token */
214 if ( _pico_parse_first( p ) == NULL ) {
215 return PICO_PMV_ERROR_IDENT;
218 /* check first token */
219 if ( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) ) {
220 _pico_free_parser( p );
221 return PICO_PMV_ERROR_IDENT;
224 /* free the pico parser object */
225 _pico_free_parser( p );
227 /* file seems to be a valid ase file */
231 typedef struct aseVertex_s aseVertex_t;
239 typedef struct aseTexCoord_s aseTexCoord_t;
245 typedef struct aseColor_s aseColor_t;
251 typedef struct aseFace_s aseFace_t;
254 picoIndex_t indices[9];
255 picoIndex_t smoothingGroup;
256 picoIndex_t materialId;
257 picoIndex_t subMaterialId;
259 typedef aseFace_t* aseFacesIter_t;
261 picoSurface_t* PicoModelFindOrAddSurface( picoModel_t *model, picoShader_t* shader ){
262 /* see if a surface already has the shader */
264 for ( ; i < model->numSurfaces ; i++ )
266 picoSurface_t* workSurface = model->surface[i];
267 if ( workSurface->shader == shader ) {
272 /* no surface uses this shader yet, so create a new surface */
275 /* create a new surface in the model for the unique shader */
276 picoSurface_t* workSurface = PicoNewSurface( model );
277 if ( !workSurface ) {
278 _pico_printf( PICO_ERROR, "Could not allocate a new surface!\n" );
282 /* do surface setup */
283 PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
284 PicoSetSurfaceName( workSurface, shader->name );
285 PicoSetSurfaceShader( workSurface, shader );
291 /* _ase_submit_triangles - jhefty
292 use the surface and the current face list to look up material/submaterial IDs
293 and submit them to the model for proper processing
295 The following still holds from ydnar's _ase_make_surface:
296 indexes 0 1 2 = vert indexes
297 indexes 3 4 5 = st indexes
298 indexes 6 7 8 = color indexes (new)
302 typedef picoIndex_t* picoIndexIter_t;
304 typedef struct aseUniqueIndices_s aseUniqueIndices_t;
305 struct aseUniqueIndices_s
313 size_t aseUniqueIndices_size( aseUniqueIndices_t* self ){
314 return self->last - self->data;
317 void aseUniqueIndices_reserve( aseUniqueIndices_t* self, picoIndex_t size ){
318 self->data = self->last = (picoIndex_t*)_pico_calloc( size, sizeof( picoIndex_t ) );
321 void aseUniqueIndices_clear( aseUniqueIndices_t* self ){
322 _pico_free( self->data );
325 void aseUniqueIndices_pushBack( aseUniqueIndices_t* self, picoIndex_t index ){
326 *self->last++ = index;
329 picoIndex_t aseFaces_getVertexIndex( aseFace_t* faces, picoIndex_t index ){
330 return faces[index / 3].indices[index % 3];
333 picoIndex_t aseFaces_getTexCoordIndex( aseFace_t* faces, picoIndex_t index ){
334 return faces[index / 3].indices[( index % 3 ) + 3];
337 picoIndex_t aseFaces_getColorIndex( aseFace_t* faces, picoIndex_t index ){
338 return faces[index / 3].indices[( index % 3 ) + 6];
341 int aseUniqueIndex_equal( aseFace_t* faces, picoIndex_t index, picoIndex_t other ){
342 return aseFaces_getVertexIndex( faces, index ) == aseFaces_getVertexIndex( faces, other )
343 && aseFaces_getTexCoordIndex( faces, index ) == aseFaces_getTexCoordIndex( faces, other )
344 && aseFaces_getColorIndex( faces, index ) == aseFaces_getColorIndex( faces, other );
347 picoIndex_t aseUniqueIndices_insertUniqueVertex( aseUniqueIndices_t* self, picoIndex_t index ){
348 picoIndexIter_t i = self->data;
349 for (; i != self->last; ++i )
351 picoIndex_t other = (picoIndex_t)( i - self->data );
352 if ( aseUniqueIndex_equal( self->faces, index, other ) ) {
357 aseUniqueIndices_pushBack( self, index );
358 return (picoIndex_t)( aseUniqueIndices_size( self ) - 1 );
361 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 ){
362 aseFacesIter_t i = faces, end = faces + numFaces;
364 aseUniqueIndices_t indices;
365 aseUniqueIndices_t remap;
366 aseUniqueIndices_reserve( &indices, numFaces * 3 );
367 aseUniqueIndices_reserve( &remap, numFaces * 3 );
368 indices.faces = faces;
370 for (; i != end; ++i )
372 /* look up the shader for the material/submaterial pair */
373 aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, ( *i ).materialId, ( *i ).subMaterialId );
374 if ( subMtl == NULL ) {
379 picoSurface_t* surface = PicoModelFindOrAddSurface( model, subMtl->shader );
381 /* we pull the data from the vertex, color and texcoord arrays using the face index data */
382 for ( j = 0 ; j < 3 ; j++ )
384 picoIndex_t index = (picoIndex_t)( ( ( i - faces ) * 3 ) + j );
385 picoIndex_t size = (picoIndex_t)aseUniqueIndices_size( &indices );
386 picoIndex_t unique = aseUniqueIndices_insertUniqueVertex( &indices, index );
388 picoIndex_t numVertexes = PicoGetSurfaceNumVertexes( surface );
389 picoIndex_t numIndexes = PicoGetSurfaceNumIndexes( surface );
391 aseUniqueIndices_pushBack( &remap, numIndexes );
393 PicoSetSurfaceIndex( surface, numIndexes, remap.data[unique] );
395 if ( unique == size ) {
396 PicoSetSurfaceXYZ( surface, numVertexes, vertices[( *i ).indices[j]].xyz );
397 PicoSetSurfaceNormal( surface, numVertexes, vertices[( *i ).indices[j]].normal );
398 PicoSetSurfaceST( surface, 0, numVertexes, texcoords[( *i ).indices[j + 3]].texcoord );
400 if ( ( *i ).indices[j + 6] >= 0 ) {
401 PicoSetSurfaceColor( surface, 0, numVertexes, colors[( *i ).indices[j + 6]].color );
405 PicoSetSurfaceColor( surface, 0, numVertexes, white );
408 PicoSetSurfaceSmoothingGroup( surface, numVertexes, ( vertices[( *i ).indices[j]].id * ( 1 << 16 ) ) + ( *i ).smoothingGroup );
414 aseUniqueIndices_clear( &indices );
415 aseUniqueIndices_clear( &remap );
420 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 ){
421 aseFacesIter_t i = faces, end = faces + numFaces;
422 for (; i != end; ++i )
424 /* look up the shader for the material/submaterial pair */
425 aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, ( *i ).materialId, ( *i ).subMaterialId );
426 if ( subMtl == NULL ) {
432 picoVec3_t* normal[3];
434 picoColor_t* color[3];
435 picoIndex_t smooth[3];
437 /* we pull the data from the vertex, color and texcoord arrays using the face index data */
438 for ( j = 0 ; j < 3 ; j++ )
440 xyz[j] = &vertices[( *i ).indices[j]].xyz;
441 normal[j] = &vertices[( *i ).indices[j]].normal;
442 st[j] = &texcoords[( *i ).indices[j + 3]].texcoord;
444 if ( colors != NULL && ( *i ).indices[j + 6] >= 0 ) {
445 color[j] = &colors[( *i ).indices[j + 6]].color;
452 smooth[j] = ( vertices[( *i ).indices[j]].id * ( 1 << 16 ) ) + ( *i ).smoothingGroup; /* don't merge vertices */
456 /* submit the triangle to the model */
457 PicoAddTriangleToModel( model, xyz, normal, 1, st, 1, color, subMtl->shader, name, smooth );
462 static void shadername_convert( char* shaderName ){
463 /* unix-style path separators */
464 char* s = shaderName;
465 for (; *s != '\0'; ++s )
475 * loads a 3dsmax ase model file.
477 static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
480 char lastNodeName[ 1024 ];
482 aseVertex_t* vertices = NULL;
483 aseTexCoord_t* texcoords = NULL;
484 aseColor_t* colors = NULL;
485 aseFace_t* faces = NULL;
488 int numTextureVertices = 0;
489 int numTextureVertexFaces = 0;
490 int numColorVertices = 0;
491 int numColorVertexFaces = 0;
494 aseMaterial_t* materials = NULL;
497 clock_t start, finish;
503 #define _ase_error_return( m ) \
505 _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine ); \
506 _pico_free_parser( p ); \
507 PicoFreeModel( model ); \
510 /* create a new pico parser */
511 p = _pico_new_parser( (const picoByte_t *)buffer,bufSize );
516 /* create a new pico model */
517 model = PicoNewModel();
518 if ( model == NULL ) {
519 _pico_free_parser( p );
523 PicoSetModelFrameNum( model, frameNum );
524 PicoSetModelName( model, fileName );
525 PicoSetModelFileName( model, fileName );
527 /* initialize some stuff */
528 memset( lastNodeName,0,sizeof( lastNodeName ) );
530 /* parse ase model file */
533 /* get first token on line */
534 if ( _pico_parse_first( p ) == NULL ) {
538 /* we just skip empty lines */
539 if ( p->token == NULL || !strlen( p->token ) ) {
543 /* we skip invalid ase statements */
544 if ( p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}' ) {
545 _pico_parse_skip_rest( p );
548 /* remember node name */
549 if ( !_pico_stricmp( p->token,"*node_name" ) ) {
551 char *ptr = _pico_parse( p,0 );
553 _ase_error_return( "Node name parse error" );
556 /* remember node name */
557 strncpy( lastNodeName,ptr,sizeof( lastNodeName ) );
559 /* model mesh (originally contained within geomobject) */
560 else if ( !_pico_stricmp( p->token,"*mesh" ) ) {
561 /* finish existing surface */
562 _ase_submit_triangles( model, materials, vertices, texcoords, colors, faces, numFaces, lastNodeName );
564 _pico_free( vertices );
565 _pico_free( texcoords );
566 _pico_free( colors );
568 else if ( !_pico_stricmp( p->token,"*mesh_numvertex" ) ) {
569 if ( !_pico_parse_int( p, &numVertices ) ) {
570 _ase_error_return( "Missing MESH_NUMVERTEX value" );
573 vertices = _pico_calloc( numVertices, sizeof( aseVertex_t ) );
575 else if ( !_pico_stricmp( p->token,"*mesh_numfaces" ) ) {
576 if ( !_pico_parse_int( p, &numFaces ) ) {
577 _ase_error_return( "Missing MESH_NUMFACES value" );
580 faces = _pico_calloc( numFaces, sizeof( aseFace_t ) );
582 else if ( !_pico_stricmp( p->token,"*mesh_numtvertex" ) ) {
583 if ( !_pico_parse_int( p, &numTextureVertices ) ) {
584 _ase_error_return( "Missing MESH_NUMTVERTEX value" );
587 texcoords = _pico_calloc( numTextureVertices, sizeof( aseTexCoord_t ) );
589 else if ( !_pico_stricmp( p->token,"*mesh_numtvfaces" ) ) {
590 if ( !_pico_parse_int( p, &numTextureVertexFaces ) ) {
591 _ase_error_return( "Missing MESH_NUMTVFACES value" );
594 else if ( !_pico_stricmp( p->token,"*mesh_numcvertex" ) ) {
595 if ( !_pico_parse_int( p, &numColorVertices ) ) {
596 _ase_error_return( "Missing MESH_NUMCVERTEX value" );
599 colors = _pico_calloc( numColorVertices, sizeof( aseColor_t ) );
600 memset( colors, 255, numColorVertices * sizeof( aseColor_t ) ); /* ydnar: force colors to white initially */
602 else if ( !_pico_stricmp( p->token,"*mesh_numcvfaces" ) ) {
603 if ( !_pico_parse_int( p, &numColorVertexFaces ) ) {
604 _ase_error_return( "Missing MESH_NUMCVFACES value" );
607 /* mesh material reference. this usually comes at the end of */
608 /* geomobjects after the mesh blocks. we must assume that the */
609 /* new mesh was already created so all we can do here is assign */
610 /* the material reference id (shader index) now. */
611 else if ( !_pico_stricmp( p->token,"*material_ref" ) ) {
614 /* get the material ref (0..n) */
615 if ( !_pico_parse_int( p,&mtlId ) ) {
616 _ase_error_return( "Missing material reference ID" );
621 /* fix up all of the aseFaceList in the surface to point to the parent material */
622 /* we've already saved off their subMtl */
623 for (; i < numFaces; ++i )
625 faces[i].materialId = mtlId;
629 /* model mesh vertex */
630 else if ( !_pico_stricmp( p->token,"*mesh_vertex" ) ) {
633 if ( numVertices == 0 ) {
634 _ase_error_return( "Vertex parse error" );
637 /* get vertex data (orig: index +y -x +z) */
638 if ( !_pico_parse_int( p,&index ) ) {
639 _ase_error_return( "Vertex parse error" );
641 if ( !_pico_parse_vec( p,vertices[index].xyz ) ) {
642 _ase_error_return( "Vertex parse error" );
645 vertices[index].id = vertexId++;
647 /* model mesh vertex normal */
648 else if ( !_pico_stricmp( p->token,"*mesh_vertexnormal" ) ) {
651 if ( numVertices == 0 ) {
652 _ase_error_return( "Vertex parse error" );
655 /* get vertex data (orig: index +y -x +z) */
656 if ( !_pico_parse_int( p,&index ) ) {
657 _ase_error_return( "Vertex parse error" );
659 if ( !_pico_parse_vec( p,vertices[index].normal ) ) {
660 _ase_error_return( "Vertex parse error" );
663 /* model mesh face */
664 else if ( !_pico_stricmp( p->token,"*mesh_face" ) ) {
665 picoIndex_t indexes[3];
668 if ( numFaces == 0 ) {
669 _ase_error_return( "Face parse error" );
673 if ( !_pico_parse_int( p,&index ) ) {
674 _ase_error_return( "Face parse error" );
677 /* get 1st vertex index */
679 if ( !_pico_parse_int( p,&indexes[0] ) ) {
680 _ase_error_return( "Face parse error" );
683 /* get 2nd vertex index */
685 if ( !_pico_parse_int( p,&indexes[1] ) ) {
686 _ase_error_return( "Face parse error" );
689 /* get 3rd vertex index */
691 if ( !_pico_parse_int( p,&indexes[2] ) ) {
692 _ase_error_return( "Face parse error" );
695 /* parse to the subMaterial ID */
698 if ( !_pico_parse( p,0 ) ) { /* EOL */
701 if ( !_pico_stricmp( p->token,"*MESH_SMOOTHING" ) ) {
702 _pico_parse_int( p, &faces[index].smoothingGroup );
704 if ( !_pico_stricmp( p->token,"*MESH_MTLID" ) ) {
705 _pico_parse_int( p, &faces[index].subMaterialId );
709 faces[index].materialId = 0;
710 faces[index].indices[0] = indexes[2];
711 faces[index].indices[1] = indexes[1];
712 faces[index].indices[2] = indexes[0];
714 /* model texture vertex */
715 else if ( !_pico_stricmp( p->token,"*mesh_tvert" ) ) {
718 if ( numVertices == 0 ) {
719 _ase_error_return( "Texture Vertex parse error" );
722 /* get uv vertex index */
723 if ( !_pico_parse_int( p,&index ) || index >= numTextureVertices ) {
724 _ase_error_return( "Texture vertex parse error" );
727 /* get uv vertex s */
728 if ( !_pico_parse_float( p,&texcoords[index].texcoord[0] ) ) {
729 _ase_error_return( "Texture vertex parse error" );
732 /* get uv vertex t */
733 if ( !_pico_parse_float( p,&texcoords[index].texcoord[1] ) ) {
734 _ase_error_return( "Texture vertex parse error" );
737 /* ydnar: invert t */
738 texcoords[index].texcoord[ 1 ] = 1.0f - texcoords[index].texcoord[ 1 ];
740 /* ydnar: model mesh texture face */
741 else if ( !_pico_stricmp( p->token, "*mesh_tface" ) ) {
742 picoIndex_t indexes[3];
745 if ( numFaces == 0 ) {
746 _ase_error_return( "Texture face parse error" );
750 if ( !_pico_parse_int( p,&index ) ) {
751 _ase_error_return( "Texture face parse error" );
754 /* get 1st vertex index */
755 if ( !_pico_parse_int( p,&indexes[0] ) ) {
756 _ase_error_return( "Texture face parse error" );
759 /* get 2nd vertex index */
760 if ( !_pico_parse_int( p,&indexes[1] ) ) {
761 _ase_error_return( "Texture face parse error" );
764 /* get 3rd vertex index */
765 if ( !_pico_parse_int( p,&indexes[2] ) ) {
766 _ase_error_return( "Texture face parse error" );
769 faces[index].indices[3] = indexes[2];
770 faces[index].indices[4] = indexes[1];
771 faces[index].indices[5] = indexes[0];
773 /* model color vertex */
774 else if ( !_pico_stricmp( p->token,"*mesh_vertcol" ) ) {
778 if ( numVertices == 0 ) {
779 _ase_error_return( "Color Vertex parse error" );
782 /* get color vertex index */
783 if ( !_pico_parse_int( p,&index ) ) {
784 _ase_error_return( "Color vertex parse error" );
787 /* get R component */
788 if ( !_pico_parse_float( p,&colorInput ) ) {
789 _ase_error_return( "Color vertex parse error" );
791 colors[index].color[0] = (picoByte_t)( colorInput * 255 );
793 /* get G component */
794 if ( !_pico_parse_float( p,&colorInput ) ) {
795 _ase_error_return( "Color vertex parse error" );
797 colors[index].color[1] = (picoByte_t)( colorInput * 255 );
799 /* get B component */
800 if ( !_pico_parse_float( p,&colorInput ) ) {
801 _ase_error_return( "Color vertex parse error" );
803 colors[index].color[2] = (picoByte_t)( colorInput * 255 );
805 /* leave alpha alone since we don't get any data from the ASE format */
806 colors[index].color[3] = 255;
808 /* model color face */
809 else if ( !_pico_stricmp( p->token,"*mesh_cface" ) ) {
810 picoIndex_t indexes[3];
813 if ( numFaces == 0 ) {
814 _ase_error_return( "Face parse error" );
818 if ( !_pico_parse_int( p,&index ) ) {
819 _ase_error_return( "Face parse error" );
822 /* get 1st cvertex index */
823 // _pico_parse( p,0 );
824 if ( !_pico_parse_int( p,&indexes[0] ) ) {
825 _ase_error_return( "Face parse error" );
828 /* get 2nd cvertex index */
829 // _pico_parse( p,0 );
830 if ( !_pico_parse_int( p,&indexes[1] ) ) {
831 _ase_error_return( "Face parse error" );
834 /* get 3rd cvertex index */
835 // _pico_parse( p,0 );
836 if ( !_pico_parse_int( p,&indexes[2] ) ) {
837 _ase_error_return( "Face parse error" );
840 faces[index].indices[6] = indexes[2];
841 faces[index].indices[7] = indexes[1];
842 faces[index].indices[8] = indexes[0];
845 else if ( !_pico_stricmp( p->token, "*material" ) ) {
846 aseSubMaterial_t* subMaterial = NULL;
847 picoShader_t *shader = NULL;
848 int level = 1, index;
849 char materialName[ 1024 ];
850 float transValue = 0.0f, shineValue = 1.0f;
851 picoColor_t ambientColor, diffuseColor, specularColor;
852 char *mapname = NULL;
853 int subMtlId, subMaterialLevel = -1;
856 /* get material index */
857 _pico_parse_int( p,&index );
860 if ( !_pico_parse_check( p,1,"{" ) ) {
861 _ase_error_return( "Material missing opening brace" );
864 /* parse material block */
868 if ( _pico_parse( p,1 ) == NULL ) {
871 if ( !strlen( p->token ) ) {
876 if ( p->token[0] == '{' ) {
879 if ( p->token[0] == '}' ) {
886 if ( level == subMaterialLevel ) {
887 /* set material name */
888 _pico_first_token( materialName );
889 shadername_convert( materialName );
890 PicoSetShaderName( shader, materialName );
892 /* set shader's transparency */
893 PicoSetShaderTransparency( shader,transValue );
895 /* set shader's ambient color */
896 PicoSetShaderAmbientColor( shader,ambientColor );
898 /* set diffuse alpha to transparency */
899 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
901 /* set shader's diffuse color */
902 PicoSetShaderDiffuseColor( shader,diffuseColor );
904 /* set shader's specular color */
905 PicoSetShaderSpecularColor( shader,specularColor );
907 /* set shader's shininess */
908 PicoSetShaderShininess( shader,shineValue );
910 /* set material map name */
911 PicoSetShaderMapName( shader, mapname );
913 subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader );
914 subMaterialLevel = -1;
917 /* parse submaterial index */
918 if ( !_pico_stricmp( p->token,"*submaterial" ) ) {
919 /* allocate new pico shader */
920 _pico_parse_int( p, &subMtlId );
922 shader = PicoNewShader( model );
923 if ( shader == NULL ) {
924 PicoFreeModel( model );
927 subMaterialLevel = level;
929 /* parse material name */
930 else if ( !_pico_stricmp( p->token,"*material_name" ) ) {
931 char* name = _pico_parse( p,0 );
932 if ( name == NULL ) {
933 _ase_error_return( "Missing material name" );
936 strcpy( materialName, name );
937 /* skip rest and continue with next token */
938 _pico_parse_skip_rest( p );
941 /* parse material transparency */
942 else if ( !_pico_stricmp( p->token,"*material_transparency" ) ) {
943 /* get transparency value from ase */
944 if ( !_pico_parse_float( p,&transValue ) ) {
945 _ase_error_return( "Material transparency parse error" );
948 /* skip rest and continue with next token */
949 _pico_parse_skip_rest( p );
952 /* parse material shininess */
953 else if ( !_pico_stricmp( p->token,"*material_shine" ) ) {
955 * - not sure but instead of '*material_shine' i might
956 * need to use '*material_shinestrength' */
958 /* get shine value from ase */
959 if ( !_pico_parse_float( p,&shineValue ) ) {
960 _ase_error_return( "Material shine parse error" );
963 /* scale ase shine range 0..1 to pico range 0..127 */
966 /* skip rest and continue with next token */
967 _pico_parse_skip_rest( p );
970 /* parse ambient material color */
971 else if ( !_pico_stricmp( p->token,"*material_ambient" ) ) {
973 /* get r,g,b float values from ase */
974 if ( !_pico_parse_vec( p,vec ) ) {
975 _ase_error_return( "Material color parse error" );
978 /* setup 0..255 range color values */
979 ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
980 ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
981 ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
982 ambientColor[ 3 ] = (int)( 255 );
984 /* skip rest and continue with next token */
985 _pico_parse_skip_rest( p );
988 /* parse diffuse material color */
989 else if ( !_pico_stricmp( p->token,"*material_diffuse" ) ) {
992 /* get r,g,b float values from ase */
993 if ( !_pico_parse_vec( p,vec ) ) {
994 _ase_error_return( "Material color parse error" );
997 /* setup 0..255 range color */
998 diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
999 diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
1000 diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
1001 diffuseColor[ 3 ] = (int)( 255 );
1003 /* skip rest and continue with next token */
1004 _pico_parse_skip_rest( p );
1007 /* parse specular material color */
1008 else if ( !_pico_stricmp( p->token,"*material_specular" ) ) {
1011 /* get r,g,b float values from ase */
1012 if ( !_pico_parse_vec( p,vec ) ) {
1013 _ase_error_return( "Material color parse error" );
1016 /* setup 0..255 range color */
1017 specularColor[ 0 ] = (int)( vec[ 0 ] * 255 );
1018 specularColor[ 1 ] = (int)( vec[ 1 ] * 255 );
1019 specularColor[ 2 ] = (int)( vec[ 2 ] * 255 );
1020 specularColor[ 3 ] = (int)( 255 );
1022 /* skip rest and continue with next token */
1023 _pico_parse_skip_rest( p );
1026 /* material diffuse map */
1027 else if ( !_pico_stricmp( p->token,"*map_diffuse" ) ) {
1030 /* parse material block */
1033 /* get next token */
1034 if ( _pico_parse( p,1 ) == NULL ) {
1037 if ( !strlen( p->token ) ) {
1042 if ( p->token[0] == '{' ) {
1045 if ( p->token[0] == '}' ) {
1052 /* parse diffuse map bitmap */
1053 if ( !_pico_stricmp( p->token,"*bitmap" ) ) {
1054 char* name = _pico_parse( p,0 );
1055 if ( name == NULL ) {
1056 _ase_error_return( "Missing material map bitmap name" );
1058 mapname = _pico_alloc( strlen( name ) + 1 );
1059 strcpy( mapname, name );
1060 /* skip rest and continue with next token */
1061 _pico_parse_skip_rest( p );
1066 /* end map_diffuse block */
1068 /* end material block */
1070 if ( subMaterial == NULL ) {
1071 /* allocate new pico shader */
1072 shader = PicoNewShader( model );
1073 if ( shader == NULL ) {
1074 PicoFreeModel( model );
1078 /* set material name */
1079 shadername_convert( materialName );
1080 PicoSetShaderName( shader,materialName );
1082 /* set shader's transparency */
1083 PicoSetShaderTransparency( shader,transValue );
1085 /* set shader's ambient color */
1086 PicoSetShaderAmbientColor( shader,ambientColor );
1088 /* set diffuse alpha to transparency */
1089 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
1091 /* set shader's diffuse color */
1092 PicoSetShaderDiffuseColor( shader,diffuseColor );
1094 /* set shader's specular color */
1095 PicoSetShaderSpecularColor( shader,specularColor );
1097 /* set shader's shininess */
1098 PicoSetShaderShininess( shader,shineValue );
1100 /* set material map name */
1101 PicoSetShaderMapName( shader, mapname );
1103 /* extract shadername from bitmap path */
1104 if ( mapname != NULL ) {
1107 /* convert to shader-name format */
1108 shadername_convert( mapname );
1110 /* remove extension */
1111 char* last_period = strrchr( p, '.' );
1112 if ( last_period != NULL ) {
1113 *last_period = '\0';
1117 /* find shader path */
1118 for (; *p != '\0'; ++p )
1120 if ( _pico_strnicmp( p, "models/", 7 ) == 0 || _pico_strnicmp( p, "textures/", 9 ) == 0 ) {
1126 /* set material name */
1127 PicoSetShaderName( shader,p );
1131 /* this is just a material with 1 submaterial */
1132 subMaterial = _ase_add_submaterial( &materials, index, 0, shader );
1135 /* ydnar: free mapname */
1136 if ( mapname != NULL ) {
1137 _pico_free( mapname );
1139 } // !_pico_stricmp ( "*material" )
1141 /* skip unparsed rest of line and continue */
1142 _pico_parse_skip_rest( p );
1145 /* ydnar: finish existing surface */
1146 _ase_submit_triangles( model, materials, vertices, texcoords, colors, faces, numFaces, lastNodeName );
1147 _pico_free( faces );
1148 _pico_free( vertices );
1149 _pico_free( texcoords );
1150 _pico_free( colors );
1153 _ase_print_materials( materials );
1155 elapsed = (double)( finish - start ) / CLOCKS_PER_SEC;
1156 _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed );
1157 #endif //DEBUG_PM_ASE
1159 _ase_free_materials( &materials );
1161 _pico_free_parser( p );
1163 /* return allocated pico model */
1167 /* pico file format module definition */
1168 const picoModule_t picoModuleASE =
1170 "1.0", /* module version string */
1171 "Autodesk 3DSMAX ASCII", /* module display name */
1172 "Jared Hefty, seaw0lf", /* author's name */
1173 "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */
1175 "ase",NULL,NULL,NULL /* default extensions to use */
1177 _ase_canload, /* validation routine */
1178 _ase_load, /* load routine */
1179 NULL, /* save validation routine */
1180 NULL /* save routine */