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 )
77 aseMaterial_t* mtl = list;
81 if ( mtlIdParent == mtl->mtlId )
90 static aseSubMaterial_t* _ase_get_submaterial ( aseMaterial_t* list, int mtlIdParent , int subMtlId )
92 aseMaterial_t* parent = _ase_get_material ( list , mtlIdParent );
93 aseSubMaterial_t* subMtl = NULL;
97 _pico_printf ( PICO_ERROR , "No ASE material exists with id %i\n" , mtlIdParent );
101 subMtl = parent->subMtls;
104 if ( subMtlId == subMtl->subMtlId )
108 subMtl = subMtl->next;
113 aseSubMaterial_t* _ase_get_submaterial_or_default ( aseMaterial_t* materials, int mtlIdParent , int subMtlId )
115 aseSubMaterial_t* subMtl = _ase_get_submaterial( materials, mtlIdParent, subMtlId );
121 /* ydnar: trying default submaterial */
122 subMtl = _ase_get_submaterial( materials, mtlIdParent, 0 );
128 _pico_printf( PICO_ERROR, "Could not find material/submaterial for id %d/%d\n", mtlIdParent, subMtlId );
135 static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent )
137 aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) );
138 mtl->mtlId = mtlIdParent;
146 static aseSubMaterial_t* _ase_add_submaterial( aseMaterial_t **list, int mtlIdParent, int subMtlId, picoShader_t* shader )
148 aseMaterial_t *parent = _ase_get_material( *list, mtlIdParent );
149 aseSubMaterial_t *subMtl = _pico_calloc( 1, sizeof ( aseSubMaterial_t ) );
153 parent = _ase_add_material ( list , mtlIdParent );
156 subMtl->shader = shader;
157 subMtl->subMtlId = subMtlId;
158 subMtl->next = parent->subMtls;
159 parent->subMtls = subMtl;
164 static void _ase_free_materials( aseMaterial_t **list )
166 aseMaterial_t* mtl = *list;
167 aseSubMaterial_t* subMtl = NULL;
169 aseMaterial_t* mtlTemp = NULL;
170 aseSubMaterial_t* subMtlTemp = NULL;
174 subMtl = mtl->subMtls;
177 subMtlTemp = subMtl->next;
178 _pico_free ( subMtl );
189 static void _ase_print_materials( aseMaterial_t *list )
191 aseMaterial_t* mtl = list;
192 aseSubMaterial_t* subMtl = NULL;
196 _pico_printf ( PICO_NORMAL , "ASE Material %i" , mtl->mtlId );
197 subMtl = mtl->subMtls;
200 _pico_printf ( PICO_NORMAL , " -- ASE SubMaterial %i - %s\n" , subMtl->subMtlId , subMtl->shader->name );
201 subMtl = subMtl->next;
206 #endif //DEBUG_PM_ASE
209 * - apply material specific uv offsets to uv coordinates
213 * validates a 3dsmax ase model file.
215 static int _ase_canload( PM_PARAMS_CANLOAD )
220 /* quick data length validation */
222 return PICO_PMV_ERROR_SIZE;
224 /* keep the friggin compiler happy */
225 *fileName = *fileName;
227 /* create pico parser */
228 p = _pico_new_parser( (picoByte_t*) buffer, bufSize );
230 return PICO_PMV_ERROR_MEMORY;
232 /* get first token */
233 if( _pico_parse_first( p ) == NULL)
235 return PICO_PMV_ERROR_IDENT;
238 /* check first token */
239 if( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) )
241 _pico_free_parser( p );
242 return PICO_PMV_ERROR_IDENT;
245 /* free the pico parser object */
246 _pico_free_parser( p );
248 /* file seems to be a valid ase file */
252 typedef struct aseVertex_s aseVertex_t;
260 typedef struct aseTexCoord_s aseTexCoord_t;
266 typedef struct aseColor_s aseColor_t;
272 typedef struct aseFace_s aseFace_t;
275 picoIndex_t indices[9];
276 picoIndex_t smoothingGroup;
277 picoIndex_t materialId;
278 picoIndex_t subMaterialId;
280 typedef aseFace_t* aseFacesIter_t;
282 picoSurface_t* PicoModelFindOrAddSurface( picoModel_t *model, picoShader_t* shader )
284 /* see if a surface already has the shader */
286 for ( ; i < model->numSurfaces ; i++ )
288 picoSurface_t* workSurface = model->surface[i];
289 if ( workSurface->shader == shader )
295 /* no surface uses this shader yet, so create a new surface */
298 /* create a new surface in the model for the unique shader */
299 picoSurface_t* workSurface = PicoNewSurface(model);
302 _pico_printf ( PICO_ERROR , "Could not allocate a new surface!\n" );
306 /* do surface setup */
307 PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
308 PicoSetSurfaceName( workSurface, shader->name );
309 PicoSetSurfaceShader( workSurface, shader );
315 /* _ase_submit_triangles - jhefty
316 use the surface and the current face list to look up material/submaterial IDs
317 and submit them to the model for proper processing
319 The following still holds from ydnar's _ase_make_surface:
320 indexes 0 1 2 = vert indexes
321 indexes 3 4 5 = st indexes
322 indexes 6 7 8 = color indexes (new)
326 typedef picoIndex_t* picoIndexIter_t;
328 typedef struct aseUniqueIndices_s aseUniqueIndices_t;
329 struct aseUniqueIndices_s
337 size_t aseUniqueIndices_size(aseUniqueIndices_t* self)
339 return self->last - self->data;
342 void aseUniqueIndices_reserve(aseUniqueIndices_t* self, picoIndex_t size)
344 self->data = self->last = (picoIndex_t*)_pico_calloc(size, sizeof(picoIndex_t));
347 void aseUniqueIndices_clear(aseUniqueIndices_t* self)
349 _pico_free(self->data);
352 void aseUniqueIndices_pushBack(aseUniqueIndices_t* self, picoIndex_t index)
354 *self->last++ = index;
357 picoIndex_t aseFaces_getVertexIndex(aseFace_t* faces, picoIndex_t index)
359 return faces[index / 3].indices[index % 3];
362 picoIndex_t aseFaces_getTexCoordIndex(aseFace_t* faces, picoIndex_t index)
364 return faces[index / 3].indices[(index % 3) + 3];
367 picoIndex_t aseFaces_getColorIndex(aseFace_t* faces, picoIndex_t index)
369 return faces[index / 3].indices[(index % 3) + 6];
372 int aseUniqueIndex_equal(aseFace_t* faces, picoIndex_t index, picoIndex_t other)
374 return aseFaces_getVertexIndex(faces, index) == aseFaces_getVertexIndex(faces, other)
375 && aseFaces_getTexCoordIndex(faces, index) == aseFaces_getTexCoordIndex(faces, other)
376 && aseFaces_getColorIndex(faces, index) == aseFaces_getColorIndex(faces, other);
379 picoIndex_t aseUniqueIndices_insertUniqueVertex(aseUniqueIndices_t* self, picoIndex_t index)
381 picoIndexIter_t i = self->data;
382 for(; i != self->last; ++i)
384 picoIndex_t other = (picoIndex_t)(i - self->data);
385 if(aseUniqueIndex_equal(self->faces, index, other))
391 aseUniqueIndices_pushBack(self, index);
392 return (picoIndex_t)(aseUniqueIndices_size(self) - 1);
395 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 )
397 aseFacesIter_t i = faces, end = faces + numFaces;
399 aseUniqueIndices_t indices;
400 aseUniqueIndices_t remap;
401 aseUniqueIndices_reserve(&indices, numFaces * 3);
402 aseUniqueIndices_reserve(&remap, numFaces * 3);
403 indices.faces = faces;
407 /* look up the shader for the material/submaterial pair */
408 aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, (*i).materialId, (*i).subMaterialId );
415 picoSurface_t* surface = PicoModelFindOrAddSurface(model, subMtl->shader);
417 /* we pull the data from the vertex, color and texcoord arrays using the face index data */
418 for ( j = 0 ; j < 3 ; j ++ )
420 picoIndex_t index = (picoIndex_t)(((i - faces) * 3) + j);
421 picoIndex_t size = (picoIndex_t)aseUniqueIndices_size(&indices);
422 picoIndex_t unique = aseUniqueIndices_insertUniqueVertex(&indices, index);
424 picoIndex_t numVertexes = PicoGetSurfaceNumVertexes(surface);
425 picoIndex_t numIndexes = PicoGetSurfaceNumIndexes(surface);
427 aseUniqueIndices_pushBack(&remap, numIndexes);
429 PicoSetSurfaceIndex(surface, numIndexes, remap.data[unique]);
433 PicoSetSurfaceXYZ(surface, numVertexes, vertices[(*i).indices[j]].xyz);
434 PicoSetSurfaceNormal(surface, numVertexes, vertices[(*i).indices[j]].normal);
435 PicoSetSurfaceST(surface, 0, numVertexes, texcoords[(*i).indices[j + 3]].texcoord);
437 if ( (*i).indices[j + 6] >= 0 )
439 PicoSetSurfaceColor(surface, 0, numVertexes, colors[(*i).indices[j + 6]].color);
443 PicoSetSurfaceColor(surface, 0, numVertexes, white);
446 PicoSetSurfaceSmoothingGroup(surface, numVertexes, (vertices[(*i).indices[j]].id * (1 << 16)) + (*i).smoothingGroup);
452 aseUniqueIndices_clear(&indices);
453 aseUniqueIndices_clear(&remap);
458 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 )
460 aseFacesIter_t i = faces, end = faces + numFaces;
463 /* look up the shader for the material/submaterial pair */
464 aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, (*i).materialId, (*i).subMaterialId );
472 picoVec3_t* normal[3];
474 picoColor_t* color[3];
475 picoIndex_t smooth[3];
477 /* we pull the data from the vertex, color and texcoord arrays using the face index data */
478 for ( j = 0 ; j < 3 ; j ++ )
480 xyz[j] = &vertices[(*i).indices[j]].xyz;
481 normal[j] = &vertices[(*i).indices[j]].normal;
482 st[j] = &texcoords[(*i).indices[j + 3]].texcoord;
484 if( colors != NULL && (*i).indices[j + 6] >= 0 )
486 color[j] = &colors[(*i).indices[j + 6]].color;
493 smooth[j] = (vertices[(*i).indices[j]].id * (1 << 16)) + (*i).smoothingGroup; /* don't merge vertices */
497 /* submit the triangle to the model */
498 PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader, smooth );
503 static void shadername_convert(char* shaderName)
505 /* unix-style path separators */
506 char* s = shaderName;
507 for(; *s != '\0'; ++s)
518 * loads a 3dsmax ase model file.
520 static picoModel_t *_ase_load( PM_PARAMS_LOAD )
524 char lastNodeName[ 1024 ];
526 aseVertex_t* vertices = NULL;
527 aseTexCoord_t* texcoords = NULL;
528 aseColor_t* colors = NULL;
529 aseFace_t* faces = NULL;
532 int numTextureVertices = 0;
533 int numTextureVertexFaces = 0;
534 int numColorVertices = 0;
535 int numColorVertexFaces = 0;
538 aseMaterial_t* materials = NULL;
541 clock_t start, finish;
547 #define _ase_error_return(m) \
549 _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine); \
550 _pico_free_parser( p ); \
551 PicoFreeModel( model ); \
554 /* create a new pico parser */
555 p = _pico_new_parser( (picoByte_t *)buffer,bufSize );
556 if (p == NULL) return NULL;
558 /* create a new pico model */
559 model = PicoNewModel();
562 _pico_free_parser( p );
566 PicoSetModelFrameNum( model, frameNum );
567 PicoSetModelName( model, fileName );
568 PicoSetModelFileName( model, fileName );
570 /* initialize some stuff */
571 memset( lastNodeName,0,sizeof(lastNodeName) );
573 /* parse ase model file */
576 /* get first token on line */
577 if (_pico_parse_first( p ) == NULL)
580 /* we just skip empty lines */
581 if (p->token == NULL || !strlen( p->token ))
584 /* we skip invalid ase statements */
585 if (p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}')
587 _pico_parse_skip_rest( p );
590 /* remember node name */
591 if (!_pico_stricmp(p->token,"*node_name"))
594 char *ptr = _pico_parse( p,0 );
596 _ase_error_return("Node name parse error");
598 /* remember node name */
599 strncpy( lastNodeName,ptr,sizeof(lastNodeName) );
601 /* model mesh (originally contained within geomobject) */
602 else if (!_pico_stricmp(p->token,"*mesh"))
604 /* finish existing surface */
605 _ase_submit_triangles(model, materials, vertices, texcoords, colors, faces, numFaces);
607 _pico_free(vertices);
608 _pico_free(texcoords);
611 else if (!_pico_stricmp(p->token,"*mesh_numvertex"))
613 if (!_pico_parse_int( p, &numVertices) )
614 _ase_error_return("Missing MESH_NUMVERTEX value");
616 vertices = _pico_calloc(numVertices, sizeof(aseVertex_t));
618 else if (!_pico_stricmp(p->token,"*mesh_numfaces"))
620 if (!_pico_parse_int( p, &numFaces) )
621 _ase_error_return("Missing MESH_NUMFACES value");
623 faces = _pico_calloc(numFaces, sizeof(aseFace_t));
625 else if (!_pico_stricmp(p->token,"*mesh_numtvertex"))
627 if (!_pico_parse_int( p, &numTextureVertices) )
628 _ase_error_return("Missing MESH_NUMTVERTEX value");
630 texcoords = _pico_calloc(numTextureVertices, sizeof(aseTexCoord_t));
632 else if (!_pico_stricmp(p->token,"*mesh_numtvfaces"))
634 if (!_pico_parse_int( p, &numTextureVertexFaces) )
635 _ase_error_return("Missing MESH_NUMTVFACES value");
637 else if (!_pico_stricmp(p->token,"*mesh_numcvertex"))
639 if (!_pico_parse_int( p, &numColorVertices) )
640 _ase_error_return("Missing MESH_NUMCVERTEX value");
642 colors = _pico_calloc(numColorVertices, sizeof(aseColor_t));
643 memset( colors, 255, numColorVertices * sizeof( aseColor_t ) ); /* ydnar: force colors to white initially */
645 else if (!_pico_stricmp(p->token,"*mesh_numcvfaces"))
647 if (!_pico_parse_int( p, &numColorVertexFaces) )
648 _ase_error_return("Missing MESH_NUMCVFACES value");
650 /* mesh material reference. this usually comes at the end of */
651 /* geomobjects after the mesh blocks. we must assume that the */
652 /* new mesh was already created so all we can do here is assign */
653 /* the material reference id (shader index) now. */
654 else if (!_pico_stricmp(p->token,"*material_ref"))
658 /* get the material ref (0..n) */
659 if (!_pico_parse_int( p,&mtlId) )
660 _ase_error_return("Missing material reference ID");
664 /* fix up all of the aseFaceList in the surface to point to the parent material */
665 /* we've already saved off their subMtl */
666 for(; i < numFaces; ++i)
668 faces[i].materialId = mtlId;
672 /* model mesh vertex */
673 else if (!_pico_stricmp(p->token,"*mesh_vertex"))
677 if( numVertices == 0 )
678 _ase_error_return("Vertex parse error");
680 /* get vertex data (orig: index +y -x +z) */
681 if (!_pico_parse_int( p,&index ))
682 _ase_error_return("Vertex parse error");
683 if (!_pico_parse_vec( p,vertices[index].xyz ))
684 _ase_error_return("Vertex parse error");
686 vertices[index].id = vertexId++;
688 /* model mesh vertex normal */
689 else if (!_pico_stricmp(p->token,"*mesh_vertexnormal"))
693 if( numVertices == 0 )
694 _ase_error_return("Vertex parse error");
696 /* get vertex data (orig: index +y -x +z) */
697 if (!_pico_parse_int( p,&index ))
698 _ase_error_return("Vertex parse error");
699 if (!_pico_parse_vec( p,vertices[index].normal ))
700 _ase_error_return("Vertex parse error");
702 /* model mesh face */
703 else if (!_pico_stricmp(p->token,"*mesh_face"))
705 picoIndex_t indexes[3];
709 _ase_error_return("Face parse error");
712 if (!_pico_parse_int( p,&index ))
713 _ase_error_return("Face parse error");
715 /* get 1st vertex index */
717 if (!_pico_parse_int( p,&indexes[0] ))
718 _ase_error_return("Face parse error");
720 /* get 2nd vertex index */
722 if (!_pico_parse_int( p,&indexes[1] ))
723 _ase_error_return("Face parse error");
725 /* get 3rd vertex index */
727 if (!_pico_parse_int( p,&indexes[2] ))
728 _ase_error_return("Face parse error");
730 /* parse to the subMaterial ID */
733 if (!_pico_parse (p,0)) /* EOL */
737 if (!_pico_stricmp (p->token,"*MESH_SMOOTHING" ))
739 _pico_parse_int ( p , &faces[index].smoothingGroup );
741 if (!_pico_stricmp (p->token,"*MESH_MTLID" ))
743 _pico_parse_int ( p , &faces[index].subMaterialId );
747 faces[index].materialId = 0;
748 faces[index].indices[0] = indexes[2];
749 faces[index].indices[1] = indexes[1];
750 faces[index].indices[2] = indexes[0];
752 /* model texture vertex */
753 else if (!_pico_stricmp(p->token,"*mesh_tvert"))
757 if( numVertices == 0 )
758 _ase_error_return("Texture Vertex parse error");
760 /* get uv vertex index */
761 if (!_pico_parse_int( p,&index ) || index >= numTextureVertices)
762 _ase_error_return("Texture vertex parse error");
764 /* get uv vertex s */
765 if (!_pico_parse_float( p,&texcoords[index].texcoord[0] ))
766 _ase_error_return("Texture vertex parse error");
768 /* get uv vertex t */
769 if (!_pico_parse_float( p,&texcoords[index].texcoord[1] ))
770 _ase_error_return("Texture vertex parse error");
772 /* ydnar: invert t */
773 texcoords[index].texcoord[ 1 ] = 1.0f - texcoords[index].texcoord[ 1 ];
775 /* ydnar: model mesh texture face */
776 else if( !_pico_stricmp( p->token, "*mesh_tface" ) )
778 picoIndex_t indexes[3];
782 _ase_error_return("Texture face parse error");
785 if (!_pico_parse_int( p,&index ))
786 _ase_error_return("Texture face parse error");
788 /* get 1st vertex index */
789 if (!_pico_parse_int( p,&indexes[0] ))
790 _ase_error_return("Texture face parse error");
792 /* get 2nd vertex index */
793 if (!_pico_parse_int( p,&indexes[1] ))
794 _ase_error_return("Texture face parse error");
796 /* get 3rd vertex index */
797 if (!_pico_parse_int( p,&indexes[2] ))
798 _ase_error_return("Texture face parse error");
800 faces[index].indices[3] = indexes[2];
801 faces[index].indices[4] = indexes[1];
802 faces[index].indices[5] = indexes[0];
804 /* model color vertex */
805 else if (!_pico_stricmp(p->token,"*mesh_vertcol"))
810 if( numVertices == 0 )
811 _ase_error_return("Color Vertex parse error");
813 /* get color vertex index */
814 if (!_pico_parse_int( p,&index ))
815 _ase_error_return("Color vertex parse error");
817 /* get R component */
818 if (!_pico_parse_float( p,&colorInput ))
819 _ase_error_return("Color vertex parse error");
820 colors[index].color[0] = (picoByte_t)(colorInput * 255);
822 /* get G component */
823 if (!_pico_parse_float( p,&colorInput ))
824 _ase_error_return("Color vertex parse error");
825 colors[index].color[1] = (picoByte_t)(colorInput * 255);
827 /* get B component */
828 if (!_pico_parse_float( p,&colorInput ))
829 _ase_error_return("Color vertex parse error");
830 colors[index].color[2] = (picoByte_t)(colorInput * 255);
832 /* leave alpha alone since we don't get any data from the ASE format */
833 colors[index].color[3] = 255;
835 /* model color face */
836 else if (!_pico_stricmp(p->token,"*mesh_cface"))
838 picoIndex_t indexes[3];
842 _ase_error_return("Face parse error");
845 if (!_pico_parse_int( p,&index ))
846 _ase_error_return("Face parse error");
848 /* get 1st cvertex index */
849 // _pico_parse( p,0 );
850 if (!_pico_parse_int( p,&indexes[0] ))
851 _ase_error_return("Face parse error");
853 /* get 2nd cvertex index */
854 // _pico_parse( p,0 );
855 if (!_pico_parse_int( p,&indexes[1] ))
856 _ase_error_return("Face parse error");
858 /* get 3rd cvertex index */
859 // _pico_parse( p,0 );
860 if (!_pico_parse_int( p,&indexes[2] ))
861 _ase_error_return("Face parse error");
863 faces[index].indices[6] = indexes[2];
864 faces[index].indices[7] = indexes[1];
865 faces[index].indices[8] = indexes[0];
868 else if( !_pico_stricmp( p->token, "*material" ) )
870 aseSubMaterial_t* subMaterial = NULL;
871 picoShader_t *shader;
872 int level = 1, index;
873 char materialName[ 1024 ];
874 float transValue = 0.0f, shineValue = 1.0f;
875 picoColor_t ambientColor, diffuseColor, specularColor;
876 char *mapname = NULL;
877 int subMtlId, subMaterialLevel = -1;
880 /* get material index */
881 _pico_parse_int( p,&index );
884 if (!_pico_parse_check(p,1,"{"))
885 _ase_error_return("Material missing opening brace");
887 /* parse material block */
891 if (_pico_parse(p,1) == NULL) break;
892 if (!strlen(p->token)) continue;
895 if (p->token[0] == '{') level++;
896 if (p->token[0] == '}') level--;
899 if( level == subMaterialLevel )
901 /* set material name */
902 _pico_first_token( materialName );
903 shadername_convert(materialName);
904 PicoSetShaderName( shader, materialName);
906 /* set shader's transparency */
907 PicoSetShaderTransparency( shader,transValue );
909 /* set shader's ambient color */
910 PicoSetShaderAmbientColor( shader,ambientColor );
912 /* set diffuse alpha to transparency */
913 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
915 /* set shader's diffuse color */
916 PicoSetShaderDiffuseColor( shader,diffuseColor );
918 /* set shader's specular color */
919 PicoSetShaderSpecularColor( shader,specularColor );
921 /* set shader's shininess */
922 PicoSetShaderShininess( shader,shineValue );
924 /* set material map name */
925 PicoSetShaderMapName( shader, mapname );
927 subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader );
928 subMaterialLevel = -1;
931 /* parse submaterial index */
932 if (!_pico_stricmp(p->token,"*submaterial"))
934 /* allocate new pico shader */
935 _pico_parse_int( p , &subMtlId );
937 shader = PicoNewShader( model );
940 PicoFreeModel( model );
943 subMaterialLevel = level;
945 /* parse material name */
946 else if (!_pico_stricmp(p->token,"*material_name"))
948 char* name = _pico_parse(p,0);
950 _ase_error_return("Missing material name");
952 strcpy ( materialName , name );
953 /* skip rest and continue with next token */
954 _pico_parse_skip_rest( p );
957 /* parse material transparency */
958 else if (!_pico_stricmp(p->token,"*material_transparency"))
960 /* get transparency value from ase */
961 if (!_pico_parse_float( p,&transValue ))
962 _ase_error_return("Material transparency parse error");
964 /* skip rest and continue with next token */
965 _pico_parse_skip_rest( p );
968 /* parse material shininess */
969 else if (!_pico_stricmp(p->token,"*material_shine"))
972 * - not sure but instead of '*material_shine' i might
973 * need to use '*material_shinestrength' */
975 /* get shine value from ase */
976 if (!_pico_parse_float( p,&shineValue ))
977 _ase_error_return("Material shine parse error");
979 /* scale ase shine range 0..1 to pico range 0..127 */
982 /* skip rest and continue with next token */
983 _pico_parse_skip_rest( p );
986 /* parse ambient material color */
987 else if (!_pico_stricmp(p->token,"*material_ambient"))
990 /* get r,g,b float values from ase */
991 if (!_pico_parse_vec( p,vec ))
992 _ase_error_return("Material color parse error");
994 /* setup 0..255 range color values */
995 ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
996 ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
997 ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
998 ambientColor[ 3 ] = (int)( 255 );
1000 /* skip rest and continue with next token */
1001 _pico_parse_skip_rest( p );
1004 /* parse diffuse material color */
1005 else if (!_pico_stricmp(p->token,"*material_diffuse"))
1009 /* get r,g,b float values from ase */
1010 if (!_pico_parse_vec( p,vec ))
1011 _ase_error_return("Material color parse error");
1013 /* setup 0..255 range color */
1014 diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
1015 diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
1016 diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
1017 diffuseColor[ 3 ] = (int)( 255 );
1019 /* skip rest and continue with next token */
1020 _pico_parse_skip_rest( p );
1023 /* parse specular material color */
1024 else if (!_pico_stricmp(p->token,"*material_specular"))
1028 /* get r,g,b float values from ase */
1029 if (!_pico_parse_vec( p,vec ))
1030 _ase_error_return("Material color parse error");
1032 /* setup 0..255 range color */
1033 specularColor[ 0 ] = (int)( vec[ 0 ] * 255 );
1034 specularColor[ 1 ] = (int)( vec[ 1 ] * 255 );
1035 specularColor[ 2 ] = (int)( vec[ 2 ] * 255 );
1036 specularColor[ 3 ] = (int)( 255 );
1038 /* skip rest and continue with next token */
1039 _pico_parse_skip_rest( p );
1042 /* material diffuse map */
1043 else if (!_pico_stricmp(p->token,"*map_diffuse") )
1047 /* parse material block */
1050 /* get next token */
1051 if (_pico_parse(p,1) == NULL) break;
1052 if (!strlen(p->token)) continue;
1055 if (p->token[0] == '{') sublevel++;
1056 if (p->token[0] == '}') sublevel--;
1057 if (!sublevel) break;
1059 /* parse diffuse map bitmap */
1060 if (!_pico_stricmp(p->token,"*bitmap"))
1062 char* name = _pico_parse(p,0);
1064 _ase_error_return("Missing material map bitmap name");
1065 mapname = _pico_alloc ( strlen ( name ) + 1 );
1066 strcpy ( mapname, name );
1067 /* skip rest and continue with next token */
1068 _pico_parse_skip_rest( p );
1073 /* end map_diffuse block */
1075 /* end material block */
1077 if( subMaterial == NULL )
1079 /* allocate new pico shader */
1080 shader = PicoNewShader( model );
1083 PicoFreeModel( model );
1087 /* set material name */
1088 shadername_convert(materialName);
1089 PicoSetShaderName( shader,materialName );
1091 /* set shader's transparency */
1092 PicoSetShaderTransparency( shader,transValue );
1094 /* set shader's ambient color */
1095 PicoSetShaderAmbientColor( shader,ambientColor );
1097 /* set diffuse alpha to transparency */
1098 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
1100 /* set shader's diffuse color */
1101 PicoSetShaderDiffuseColor( shader,diffuseColor );
1103 /* set shader's specular color */
1104 PicoSetShaderSpecularColor( shader,specularColor );
1106 /* set shader's shininess */
1107 PicoSetShaderShininess( shader,shineValue );
1109 /* set material map name */
1110 PicoSetShaderMapName( shader, mapname );
1112 /* extract shadername from bitmap path */
1117 /* convert to shader-name format */
1118 shadername_convert(mapname);
1120 /* remove extension */
1121 char* last_period = strrchr(p, '.');
1122 if(last_period != NULL)
1124 *last_period = '\0';
1128 /* find shader path */
1129 for(; *p != '\0'; ++p)
1131 if(_pico_strnicmp(p, "models/", 7) == 0 || _pico_strnicmp(p, "textures/", 9) == 0)
1139 /* set material name */
1140 PicoSetShaderName( shader,p );
1144 /* this is just a material with 1 submaterial */
1145 subMaterial = _ase_add_submaterial( &materials, index, 0, shader );
1148 /* ydnar: free mapname */
1149 if( mapname != NULL )
1150 _pico_free( mapname );
1151 } // !_pico_stricmp ( "*material" )
1153 /* skip unparsed rest of line and continue */
1154 _pico_parse_skip_rest( p );
1157 /* ydnar: finish existing surface */
1158 _ase_submit_triangles(model, materials, vertices, texcoords, colors, faces, numFaces);
1160 _pico_free(vertices);
1161 _pico_free(texcoords);
1165 _ase_print_materials(materials);
1167 elapsed = (double)(finish - start) / CLOCKS_PER_SEC;
1168 _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed );
1169 #endif //DEBUG_PM_ASE
1171 _ase_free_materials(&materials);
1173 _pico_free_parser( p );
1175 /* return allocated pico model */
1179 /* pico file format module definition */
1180 const picoModule_t picoModuleASE =
1182 "1.0", /* module version string */
1183 "Autodesk 3DSMAX ASCII", /* module display name */
1184 "Jared Hefty, seaw0lf", /* author's name */
1185 "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */
1187 "ase",NULL,NULL,NULL /* default extensions to use */
1189 _ase_canload, /* validation routine */
1190 _ase_load, /* load routine */
1191 NULL, /* save validation routine */
1192 NULL /* save routine */