-/* -----------------------------------------------------------------------------\r
-\r
-PicoModel Library\r
-\r
-Copyright (c) 2002, Randy Reddig & seaw0lf\r
-All rights reserved.\r
-\r
-Redistribution and use in source and binary forms, with or without modification,\r
-are permitted provided that the following conditions are met:\r
-\r
-Redistributions of source code must retain the above copyright notice, this list\r
-of conditions and the following disclaimer.\r
-\r
-Redistributions in binary form must reproduce the above copyright notice, this\r
-list of conditions and the following disclaimer in the documentation and/or\r
-other aseMaterialList provided with the distribution.\r
-\r
-Neither the names of the copyright holders nor the names of its contributors may\r
-be used to endorse or promote products derived from this software without\r
-specific prior written permission.\r
-\r
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-\r
------------------------------------------------------------------------------ */\r
-\r
-\r
-/* marker */\r
-#define PM_ASE_C\r
-\r
-/* uncomment when debugging this module */\r
-//#define DEBUG_PM_ASE \r
-//#define DEBUG_PM_ASE_EX\r
-\r
-\r
-/* dependencies */\r
-#include "picointernal.h"\r
-\r
-#ifdef DEBUG_PM_ASE\r
-#include "time.h"\r
-#endif\r
-\r
-/* plain white */\r
-static picoColor_t white = { 255, 255, 255, 255 };\r
-\r
-/* jhefty - multi-subobject material support */\r
-\r
-/* Material/SubMaterial management */\r
-/* A material should have 1..n submaterials assigned to it */\r
-\r
-typedef struct aseSubMaterial_s\r
-{\r
- struct aseSubMaterial_s* next;\r
- int subMtlId;\r
- picoShader_t* shader;\r
- \r
-} aseSubMaterial_t;\r
-\r
-typedef struct aseMaterial_s\r
-{\r
- struct aseMaterial_s* next;\r
- struct aseSubMaterial_s* subMtls;\r
- int mtlId; \r
-} aseMaterial_t;\r
-\r
-/* Material/SubMaterial management functions */\r
-static aseMaterial_t* _ase_get_material ( aseMaterial_t* list , int mtlIdParent )\r
-{\r
- aseMaterial_t* mtl = list;\r
-\r
- while ( mtl )\r
- {\r
- if ( mtlIdParent == mtl->mtlId )\r
- {\r
- break;\r
- }\r
- mtl = mtl->next;\r
- }\r
- return mtl;\r
-}\r
-\r
-static aseSubMaterial_t* _ase_get_submaterial ( aseMaterial_t* list, int mtlIdParent , int subMtlId )\r
-{\r
- aseMaterial_t* parent = _ase_get_material ( list , mtlIdParent );\r
- aseSubMaterial_t* subMtl = NULL;\r
-\r
- if ( !parent )\r
- {\r
- _pico_printf ( PICO_ERROR , "No ASE material exists with id %i\n" , mtlIdParent );\r
- return NULL;\r
- }\r
-\r
- subMtl = parent->subMtls;\r
- while ( subMtl )\r
- {\r
- if ( subMtlId == subMtl->subMtlId )\r
- {\r
- break;\r
- }\r
- subMtl = subMtl->next;\r
- }\r
- return subMtl;\r
-}\r
-\r
-static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent )\r
-{\r
- aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) );\r
- mtl->mtlId = mtlIdParent;\r
- mtl->subMtls = NULL;\r
- mtl->next = *list;\r
- *list = mtl;\r
-\r
- return mtl;\r
-}\r
-\r
-static aseSubMaterial_t* _ase_add_submaterial( aseMaterial_t **list, int mtlIdParent, int subMtlId, picoShader_t* shader )\r
-{\r
- aseMaterial_t *parent = _ase_get_material( *list, mtlIdParent );\r
- aseSubMaterial_t *subMtl = _pico_calloc( 1, sizeof ( aseSubMaterial_t ) );\r
-\r
- if ( !parent )\r
- {\r
- parent = _ase_add_material ( list , mtlIdParent );\r
- }\r
-\r
- subMtl->shader = shader;\r
- subMtl->subMtlId = subMtlId;\r
- subMtl->next = parent->subMtls;\r
- parent->subMtls = subMtl;\r
-\r
- return subMtl;\r
-}\r
-\r
-static void _ase_free_materials( aseMaterial_t **list )\r
-{\r
- aseMaterial_t* mtl = *list;\r
- aseSubMaterial_t* subMtl = NULL;\r
-\r
- aseMaterial_t* mtlTemp = NULL;\r
- aseSubMaterial_t* subMtlTemp = NULL;\r
-\r
- while ( mtl )\r
- {\r
- subMtl = mtl->subMtls;\r
- while ( subMtl )\r
- {\r
- subMtlTemp = subMtl->next;\r
- _pico_free ( subMtl );\r
- subMtl = subMtlTemp;\r
- }\r
- mtlTemp = mtl->next;\r
- _pico_free ( mtl );\r
- mtl = mtlTemp;\r
- }\r
- (*list) = NULL;\r
-}\r
-\r
-#ifdef DEBUG_PM_ASE\r
-static void _ase_print_materials( aseMaterial_t *list )\r
-{\r
- aseMaterial_t* mtl = list;\r
- aseSubMaterial_t* subMtl = NULL;\r
-\r
- while ( mtl )\r
- {\r
- _pico_printf ( PICO_NORMAL , "ASE Material %i" , mtl->mtlId );\r
- subMtl = mtl->subMtls;\r
- while ( subMtl )\r
- {\r
- _pico_printf ( PICO_NORMAL , " -- ASE SubMaterial %i - %s\n" , subMtl->subMtlId , subMtl->shader->name );\r
- subMtl = subMtl->next;\r
- }\r
- mtl = mtl->next;\r
- }\r
-}\r
-#endif //DEBUG_PM_ASE\r
-\r
-/* ASE Face management */\r
-/* These are used to keep an association between a submaterial and a face definition */\r
-/* They are kept in parallel with the current picoSurface, */\r
-/* and are used by _ase_submit_triangles to lookup the proper material/submaterial IDs */\r
-typedef struct aseFace_s\r
-{\r
- struct aseFace_s* next;\r
- int mtlId;\r
- int subMtlId;\r
- int index[9];\r
-} aseFace_t;\r
-\r
-/* ASE Face management functions */\r
-void _ase_add_face( aseFace_t **list, aseFace_t **tail, aseFace_t *newFace )\r
-{\r
- aseFace_t* face = *list;\r
- aseFace_t* tempFace = NULL;\r
-\r
- /* insert as head of list */\r
- if ( !(*list) )\r
- {\r
- *list = newFace;\r
- }\r
- else\r
- {\r
- (*tail)->next = newFace;\r
- } \r
-\r
- *tail = newFace;\r
- newFace->next = NULL;\r
- \r
- //tag the color indices so we can detect them and apply the default color to them\r
- newFace->index[6] = -1;\r
- newFace->index[7] = -1;\r
- newFace->index[8] = -1;\r
-}\r
-\r
-aseFace_t* _ase_get_face_for_index( aseFace_t *list, int index )\r
-{\r
- int counter = 0;\r
- aseFace_t* face = list;\r
-\r
- while ( counter < index )\r
- {\r
- face = face->next;\r
- counter++;\r
- }\r
- return face;\r
-}\r
-static void _ase_free_faces (aseFace_t** list, aseFace_t** tail )\r
-{\r
- aseFace_t* face = *list;\r
- aseFace_t* tempFace = NULL;\r
-\r
- while ( face )\r
- {\r
- tempFace = face->next;\r
- _pico_free ( face );\r
- face = tempFace;\r
- }\r
-\r
- (*list) = NULL;\r
- (*tail) = NULL;\r
-}\r
-\r
-/* todo:\r
- * - apply material specific uv offsets to uv coordinates\r
- */\r
-\r
-/* _ase_canload:\r
- * validates a 3dsmax ase model file.\r
- */\r
-static int _ase_canload( PM_PARAMS_CANLOAD )\r
-{\r
- picoParser_t *p;\r
- \r
- \r
- /* quick data length validation */\r
- if( bufSize < 80 )\r
- return PICO_PMV_ERROR_SIZE;\r
- \r
- /* keep the friggin compiler happy */\r
- *fileName = *fileName;\r
- \r
- /* create pico parser */\r
- p = _pico_new_parser( (picoByte_t*) buffer, bufSize );\r
- if( p == NULL )\r
- return PICO_PMV_ERROR_MEMORY;\r
- \r
- /* get first token */\r
- if( _pico_parse_first( p ) == NULL)\r
- {\r
- return PICO_PMV_ERROR_IDENT;\r
- }\r
- \r
- /* check first token */\r
- if( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) )\r
- {\r
- _pico_free_parser( p );\r
- return PICO_PMV_ERROR_IDENT;\r
- }\r
- \r
- /* free the pico parser object */\r
- _pico_free_parser( p );\r
- \r
- /* file seems to be a valid ase file */\r
- return PICO_PMV_OK;\r
-}\r
-\r
-\r
-\r
-/* _ase_submit_triangles - jhefty\r
- use the surface and the current face list to look up material/submaterial IDs\r
- and submit them to the model for proper processing\r
-\r
-The following still holds from ydnar's _ase_make_surface:\r
- indexes 0 1 2 = vert indexes\r
- indexes 3 4 5 = st indexes\r
- indexes 6 7 8 = color indexes (new)\r
-*/\r
-\r
-static void _ase_submit_triangles ( picoSurface_t* surface , picoModel_t* model , aseMaterial_t* materials , aseFace_t* faces )\r
-{\r
- aseFace_t* face;\r
- aseSubMaterial_t* subMtl;\r
- picoVec3_t* xyz[3];\r
- picoVec3_t* normal[3];\r
- picoVec2_t* st[3];\r
- picoColor_t* color[3];\r
- int i;\r
-\r
- face = faces;\r
- while ( face != NULL )\r
- {\r
- /* look up the shader for the material/submaterial pair */\r
- subMtl = _ase_get_submaterial( materials, face->mtlId, face->subMtlId );\r
- if( subMtl == NULL )\r
- {\r
- /* ydnar: trying default submaterial */\r
- subMtl = _ase_get_submaterial( materials, face->mtlId, 0 );\r
- if( subMtl == NULL )\r
- {\r
- _pico_printf( PICO_ERROR, "Could not find material/submaterial for id %d/%d\n", face->mtlId, face->subMtlId );\r
- return;\r
- }\r
- }\r
- \r
- /* we pull the data from the surface using the facelist data */\r
- for ( i = 0 ; i < 3 ; i ++ )\r
- {\r
- xyz[i] = (picoVec3_t*) PicoGetSurfaceXYZ ( surface, face->index[ i ] );\r
- normal[i] = (picoVec3_t*) PicoGetSurfaceNormal( surface, face->index[ i ] ); \r
- st[i] = (picoVec2_t*) PicoGetSurfaceST ( surface, 0, face->index[ i + 3 ] );\r
- \r
- if ( face->index [ i + 6] >= 0 )\r
- {\r
- color[i] = (picoColor_t*)PicoGetSurfaceColor ( surface, 0, face->index[ i + 6 ] );\r
- }\r
- else\r
- {\r
- color[i] = &white;\r
- }\r
- \r
- }\r
-\r
- /* submit the triangle to the model */\r
- PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader );\r
-\r
- /* advance to the next face */\r
- face = face->next; \r
- } \r
-}\r
-\r
-/* _ase_load:\r
- * loads a 3dsmax ase model file.\r
-*/\r
-static picoModel_t *_ase_load( PM_PARAMS_LOAD )\r
-{\r
- picoModel_t *model;\r
- picoSurface_t *surface = NULL;\r
- picoParser_t *p;\r
- char lastNodeName[ 1024 ];\r
-\r
- aseFace_t* faces = NULL;\r
- aseFace_t* facesTail = NULL;\r
- aseMaterial_t* materials = NULL;\r
-\r
-#ifdef DEBUG_PM_ASE\r
- clock_t start, finish;\r
- double elapsed;\r
- start = clock();\r
-#endif\r
-\r
- /* helper */\r
- #define _ase_error_return(m) \\r
- { \\r
- _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine); \\r
- _pico_free_parser( p ); \\r
- PicoFreeModel( model ); \\r
- return NULL; \\r
- }\r
- /* create a new pico parser */\r
- p = _pico_new_parser( (picoByte_t *)buffer,bufSize );\r
- if (p == NULL) return NULL;\r
-\r
- /* create a new pico model */\r
- model = PicoNewModel();\r
- if (model == NULL)\r
- {\r
- _pico_free_parser( p );\r
- return NULL;\r
- }\r
- /* do model setup */\r
- PicoSetModelFrameNum( model, frameNum );\r
- PicoSetModelName( model, fileName );\r
- PicoSetModelFileName( model, fileName );\r
-\r
- /* initialize some stuff */\r
- memset( lastNodeName,0,sizeof(lastNodeName) );\r
-\r
- /* parse ase model file */\r
- while( 1 )\r
- {\r
- /* get first token on line */\r
- if (_pico_parse_first( p ) == NULL)\r
- break;\r
-\r
- /* we just skip empty lines */\r
- if (p->token == NULL || !strlen( p->token ))\r
- continue;\r
-\r
- /* we skip invalid ase statements */\r
- if (p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}')\r
- {\r
- _pico_parse_skip_rest( p );\r
- continue;\r
- }\r
- /* remember node name */\r
- if (!_pico_stricmp(p->token,"*node_name"))\r
- {\r
- /* read node name */\r
- char *ptr = _pico_parse( p,0 );\r
- if (ptr == NULL)\r
- _ase_error_return("Node name parse error");\r
-\r
- /* remember node name */\r
- strncpy( lastNodeName,ptr,sizeof(lastNodeName) );\r
- }\r
- /* model mesh (originally contained within geomobject) */\r
- else if (!_pico_stricmp(p->token,"*mesh"))\r
- {\r
- /* finish existing surface */\r
- //_ase_make_surface( model, &surface );\r
- _ase_submit_triangles (surface, model ,materials,faces);\r
- _ase_free_faces (&faces,&facesTail);\r
- \r
- /* allocate new pico surface */\r
- surface = PicoNewSurface( NULL );\r
- if (surface == NULL)\r
- {\r
- PicoFreeModel( model );\r
- return NULL;\r
- }\r
- }\r
- /* mesh material reference. this usually comes at the end of */\r
- /* geomobjects after the mesh blocks. we must assume that the */\r
- /* new mesh was already created so all we can do here is assign */\r
- /* the material reference id (shader index) now. */\r
- else if (!_pico_stricmp(p->token,"*material_ref"))\r
- {\r
- int mtlId;\r
- aseFace_t* face;\r
-\r
- /* we must have a valid surface */\r
- if( surface == NULL )\r
- _ase_error_return("Missing mesh for material reference");\r
-\r
- /* get the material ref (0..n) */\r
- if (!_pico_parse_int( p,&mtlId) )\r
- _ase_error_return("Missing material reference ID");\r
-\r
- /* fix up all of the aseFaceList in the surface to point to the parent material */\r
- /* we've already saved off their subMtl */\r
- face = faces;\r
- while ( face != NULL )\r
- {\r
- face->mtlId = mtlId;\r
- face = face->next;\r
- }\r
- }\r
- /* model mesh vertex */\r
- else if (!_pico_stricmp(p->token,"*mesh_vertex"))\r
- {\r
- picoVec3_t v;\r
- int index;\r
-\r
- /* we must have a valid surface */\r
- if( surface == NULL )\r
- continue;\r
-\r
- /* get vertex data (orig: index +y -x +z) */\r
- if (!_pico_parse_int( p,&index ))\r
- _ase_error_return("Vertex parse error");\r
- if (!_pico_parse_vec( p,v ))\r
- _ase_error_return("Vertex parse error");\r
-\r
- /* set vertex */\r
- PicoSetSurfaceXYZ( surface,index,v );\r
- }\r
- /* model mesh vertex normal */\r
- else if (!_pico_stricmp(p->token,"*mesh_vertexnormal"))\r
- {\r
- picoVec3_t v;\r
- int index;\r
-\r
- /* we must have a valid surface */\r
- if( surface == NULL )\r
- continue;\r
-\r
- /* get vertex data (orig: index +y -x +z) */\r
- if (!_pico_parse_int( p,&index ))\r
- _ase_error_return("Vertex parse error");\r
- if (!_pico_parse_vec( p,v ))\r
- _ase_error_return("Vertex parse error");\r
-\r
- /* set vertex */\r
- PicoSetSurfaceNormal( surface,index,v );\r
- }\r
- /* model mesh face */\r
- else if (!_pico_stricmp(p->token,"*mesh_face"))\r
- {\r
- picoIndex_t indexes[3];\r
- int index;\r
-\r
- /* we must have a valid surface */\r
- if( surface == NULL )\r
- continue;\r
-\r
- /* get face index */\r
- if (!_pico_parse_int( p,&index ))\r
- _ase_error_return("Face parse error");\r
-\r
- /* get 1st vertex index */\r
- _pico_parse( p,0 );\r
- if (!_pico_parse_int( p,&indexes[0] ))\r
- _ase_error_return("Face parse error");\r
-\r
- /* get 2nd vertex index */\r
- _pico_parse( p,0 );\r
- if (!_pico_parse_int( p,&indexes[1] ))\r
- _ase_error_return("Face parse error");\r
-\r
- /* get 3rd vertex index */\r
- _pico_parse( p,0 );\r
- if (!_pico_parse_int( p,&indexes[2] ))\r
- _ase_error_return("Face parse error");\r
-\r
- /* set face indexes (note interleaved offset!) */\r
- PicoSetSurfaceIndex( surface, (index * 9 + 0), indexes[2] );\r
- PicoSetSurfaceIndex( surface, (index * 9 + 1), indexes[1] );\r
- PicoSetSurfaceIndex( surface, (index * 9 + 2), indexes[0] );\r
- \r
- /* parse to the subMaterial ID */\r
- while ( 1 )\r
- {\r
- _pico_parse (p,0);\r
- if (!_pico_stricmp (p->token,"*MESH_MTLID" ))\r
- {\r
- aseFace_t* newFace;\r
- int subMtlId;\r
- \r
- _pico_parse_int ( p , &subMtlId );\r
- newFace = _pico_calloc ( 1 , sizeof ( aseFace_t ));\r
- \r
- /* we fix up the mtlId later when we parse the material_ref */\r
- newFace->mtlId = 0; \r
- newFace->subMtlId = subMtlId;\r
- newFace->index[0] = indexes[2];\r
- newFace->index[1] = indexes[1];\r
- newFace->index[2] = indexes[0];\r
-\r
- _ase_add_face ( &faces,&facesTail,newFace );\r
- break;\r
- }\r
- }\r
- \r
- }\r
- /* model texture vertex */\r
- else if (!_pico_stricmp(p->token,"*mesh_tvert"))\r
- {\r
- picoVec2_t uv;\r
- int index;\r
-\r
- /* we must have a valid surface */\r
- if( surface == NULL )\r
- continue;\r
-\r
- /* get uv vertex index */\r
- if (!_pico_parse_int( p,&index ))\r
- _ase_error_return("UV vertex parse error");\r
-\r
- /* get uv vertex s */\r
- if (!_pico_parse_float( p,&uv[0] ))\r
- _ase_error_return("UV vertex parse error");\r
-\r
- /* get uv vertex t */\r
- if (!_pico_parse_float( p,&uv[1] ))\r
- _ase_error_return("UV vertex parse error");\r
- \r
- /* ydnar: invert t */\r
- uv[ 1 ] = 1.0f - uv[ 1 ];\r
- \r
- /* set texture vertex */\r
- PicoSetSurfaceST( surface,0,index,uv );\r
- }\r
- /* ydnar: model mesh texture face */\r
- else if( !_pico_stricmp( p->token, "*mesh_tface" ) )\r
- {\r
- picoIndex_t indexes[3];\r
- int index;\r
- aseFace_t* face;\r
- \r
- /* we must have a valid surface */\r
- if( surface == NULL )\r
- continue;\r
- \r
- /* get face index */\r
- if (!_pico_parse_int( p,&index ))\r
- _ase_error_return("Texture face parse error");\r
- \r
- /* get 1st vertex index */\r
- if (!_pico_parse_int( p,&indexes[0] ))\r
- _ase_error_return("Texture face parse error");\r
- \r
- /* get 2nd vertex index */\r
- if (!_pico_parse_int( p,&indexes[1] ))\r
- _ase_error_return("Texture face parse error");\r
- \r
- /* get 3rd vertex index */\r
- if (!_pico_parse_int( p,&indexes[2] ))\r
- _ase_error_return("Texture face parse error");\r
- \r
- /* set face indexes (note interleaved offset!) */\r
- PicoSetSurfaceIndex( surface, (index * 9 + 3), indexes[2] );\r
- PicoSetSurfaceIndex( surface, (index * 9 + 4), indexes[1] );\r
- PicoSetSurfaceIndex( surface, (index * 9 + 5), indexes[0] );\r
-\r
- face = _ase_get_face_for_index(faces,index);\r
- face->index[3] = indexes[2];\r
- face->index[4] = indexes[1];\r
- face->index[5] = indexes[0];\r
- }\r
- /* model color vertex */\r
- else if (!_pico_stricmp(p->token,"*mesh_vertcol"))\r
- {\r
- picoColor_t color;\r
- int index;\r
- float colorInput;\r
-\r
- /* we must have a valid surface */\r
- if( surface == NULL )\r
- continue;\r
-\r
- /* get color vertex index */\r
- if (!_pico_parse_int( p,&index ))\r
- _ase_error_return("UV vertex parse error");\r
-\r
- /* get R component */\r
- if (!_pico_parse_float( p,&colorInput ))\r
- _ase_error_return("color vertex parse error");\r
- color[0] = (picoByte_t)(colorInput * 255);\r
-\r
- /* get G component */\r
- if (!_pico_parse_float( p,&colorInput ))\r
- _ase_error_return("color vertex parse error");\r
- color[1] = (picoByte_t)(colorInput * 255);\r
-\r
- /* get B component */\r
- if (!_pico_parse_float( p,&colorInput ))\r
- _ase_error_return("color vertex parse error");\r
- color[2] = (picoByte_t)(colorInput * 255);\r
- \r
- /* leave alpha alone since we don't get any data from the ASE format */\r
- color[3] = 255;\r
-\r
- /* set texture vertex */\r
- PicoSetSurfaceColor( surface,0,index,color );\r
- }\r
- /* model color face */\r
- else if (!_pico_stricmp(p->token,"*mesh_cface"))\r
- {\r
- picoIndex_t indexes[3];\r
- int index;\r
- aseFace_t* face;\r
-\r
- /* we must have a valid surface */\r
- if( surface == NULL )\r
- continue;\r
-\r
- /* get face index */\r
- if (!_pico_parse_int( p,&index ))\r
- _ase_error_return("Face parse error");\r
-\r
- /* get 1st cvertex index */\r
- // _pico_parse( p,0 );\r
- if (!_pico_parse_int( p,&indexes[0] ))\r
- _ase_error_return("Face parse error");\r
-\r
- /* get 2nd cvertex index */\r
- // _pico_parse( p,0 );\r
- if (!_pico_parse_int( p,&indexes[1] ))\r
- _ase_error_return("Face parse error");\r
-\r
- /* get 3rd cvertex index */\r
- // _pico_parse( p,0 );\r
- if (!_pico_parse_int( p,&indexes[2] ))\r
- _ase_error_return("Face parse error");\r
-\r
- /* set face indexes (note interleaved offset!) */\r
- PicoSetSurfaceIndex( surface, (index * 9 + 6), indexes[2] );\r
- PicoSetSurfaceIndex( surface, (index * 9 + 7), indexes[1] );\r
- PicoSetSurfaceIndex( surface, (index * 9 + 8), indexes[0] );\r
-\r
- face = _ase_get_face_for_index(faces,index);\r
- face->index[6] = indexes[2];\r
- face->index[7] = indexes[1];\r
- face->index[8] = indexes[0];\r
- }\r
- /* model material */\r
- else if( !_pico_stricmp( p->token, "*material" ) )\r
- {\r
- aseSubMaterial_t* subMaterial = NULL;\r
- picoShader_t *shader;\r
- int level = 1, index;\r
- char materialName[ 1024 ];\r
- float transValue = 0.0f, shineValue = 1.0f;\r
- picoColor_t ambientColor, diffuseColor, specularColor;\r
- char *mapname = NULL;\r
- int subMtlId, subMaterialLevel = -1;\r
- \r
- \r
- /* get material index */\r
- _pico_parse_int( p,&index );\r
- \r
- /* check brace */\r
- if (!_pico_parse_check(p,1,"{"))\r
- _ase_error_return("Material missing opening brace");\r
- \r
- /* parse material block */\r
- while( 1 )\r
- {\r
- /* get next token */\r
- if (_pico_parse(p,1) == NULL) break;\r
- if (!strlen(p->token)) continue;\r
-\r
- /* handle levels */\r
- if (p->token[0] == '{') level++;\r
- if (p->token[0] == '}') level--;\r
- if (!level) break;\r
-\r
- if( level == subMaterialLevel )\r
- {\r
- /* set material name */\r
- PicoSetShaderName( shader, materialName);\r
-\r
- /* set shader's transparency */\r
- PicoSetShaderTransparency( shader,transValue );\r
-\r
- /* set shader's ambient color */\r
- PicoSetShaderAmbientColor( shader,ambientColor );\r
-\r
- /* set diffuse alpha to transparency */\r
- diffuseColor[3] = (picoByte_t)( transValue * 255.0 );\r
-\r
- /* set shader's diffuse color */\r
- PicoSetShaderDiffuseColor( shader,diffuseColor );\r
-\r
- /* set shader's specular color */\r
- PicoSetShaderSpecularColor( shader,specularColor );\r
-\r
- /* set shader's shininess */\r
- PicoSetShaderShininess( shader,shineValue );\r
-\r
- /* set material map name */\r
- PicoSetShaderMapName( shader, mapname );\r
-\r
- subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader );\r
- subMaterialLevel = -1;\r
- }\r
-\r
- /* parse submaterial index */\r
- if (!_pico_stricmp(p->token,"*submaterial"))\r
- { \r
- /* allocate new pico shader */\r
- _pico_parse_int( p , &subMtlId );\r
-\r
- shader = PicoNewShader( model );\r
- if (shader == NULL)\r
- {\r
- PicoFreeModel( model );\r
- return NULL;\r
- } \r
- subMaterialLevel = level;\r
- }\r
- /* parse material name */\r
- else if (!_pico_stricmp(p->token,"*material_name"))\r
- {\r
- char* name = _pico_parse(p,0);\r
- if ( name == NULL)\r
- _ase_error_return("Missing material name");\r
- \r
- strcpy ( materialName , name );\r
- /* skip rest and continue with next token */\r
- _pico_parse_skip_rest( p );\r
- continue;\r
- }\r
- /* parse material transparency */\r
- else if (!_pico_stricmp(p->token,"*material_transparency"))\r
- {\r
- /* get transparency value from ase */\r
- if (!_pico_parse_float( p,&transValue ))\r
- _ase_error_return("Material transparency parse error");\r
-\r
- /* skip rest and continue with next token */\r
- _pico_parse_skip_rest( p );\r
- continue;\r
- }\r
- /* parse material shininess */\r
- else if (!_pico_stricmp(p->token,"*material_shine"))\r
- {\r
- /* remark:\r
- * - not sure but instead of '*material_shine' i might\r
- * need to use '*material_shinestrength' */\r
-\r
- /* get shine value from ase */\r
- if (!_pico_parse_float( p,&shineValue ))\r
- _ase_error_return("Material shine parse error");\r
-\r
- /* scale ase shine range 0..1 to pico range 0..127 */\r
- shineValue *= 128.0;\r
-\r
- /* skip rest and continue with next token */\r
- _pico_parse_skip_rest( p );\r
- continue;\r
- }\r
- /* parse ambient material color */\r
- else if (!_pico_stricmp(p->token,"*material_ambient"))\r
- {\r
- picoVec3_t vec;\r
- /* get r,g,b float values from ase */\r
- if (!_pico_parse_vec( p,vec ))\r
- _ase_error_return("Material color parse error");\r
-\r
- /* setup 0..255 range color values */\r
- ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );\r
- ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );\r
- ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );\r
- ambientColor[ 3 ] = (int)( 255 );\r
-\r
- /* skip rest and continue with next token */\r
- _pico_parse_skip_rest( p );\r
- continue;\r
- }\r
- /* parse diffuse material color */\r
- else if (!_pico_stricmp(p->token,"*material_diffuse"))\r
- {\r
- picoVec3_t vec;\r
-\r
- /* get r,g,b float values from ase */\r
- if (!_pico_parse_vec( p,vec ))\r
- _ase_error_return("Material color parse error");\r
-\r
- /* setup 0..255 range color */\r
- diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );\r
- diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );\r
- diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );\r
- diffuseColor[ 3 ] = (int)( 255 );\r
-\r
- /* skip rest and continue with next token */\r
- _pico_parse_skip_rest( p );\r
- continue;\r
- }\r
- /* parse specular material color */\r
- else if (!_pico_stricmp(p->token,"*material_specular"))\r
- {\r
- picoVec3_t vec;\r
-\r
- /* get r,g,b float values from ase */\r
- if (!_pico_parse_vec( p,vec ))\r
- _ase_error_return("Material color parse error");\r
-\r
- /* setup 0..255 range color */\r
- specularColor[ 0 ] = (int)( vec[ 0 ] * 255 );\r
- specularColor[ 1 ] = (int)( vec[ 1 ] * 255 );\r
- specularColor[ 2 ] = (int)( vec[ 2 ] * 255 );\r
- specularColor[ 3 ] = (int)( 255 );\r
-\r
- /* skip rest and continue with next token */\r
- _pico_parse_skip_rest( p );\r
- continue;\r
- }\r
- /* material diffuse map */\r
- else if (!_pico_stricmp(p->token,"*map_diffuse") )\r
- {\r
- int sublevel = 0;\r
-\r
- /* parse material block */\r
- while( 1 )\r
- {\r
- /* get next token */\r
- if (_pico_parse(p,1) == NULL) break;\r
- if (!strlen(p->token)) continue;\r
- \r
- /* handle levels */\r
- if (p->token[0] == '{') sublevel++;\r
- if (p->token[0] == '}') sublevel--;\r
- if (!sublevel) break;\r
- \r
- /* parse diffuse map bitmap */\r
- if (!_pico_stricmp(p->token,"*bitmap"))\r
- {\r
- char* name = _pico_parse(p,0);\r
- if (name == NULL)\r
- _ase_error_return("Missing material map bitmap name");\r
- mapname = _pico_alloc ( strlen ( name ) + 1 );\r
- strcpy ( mapname, name );\r
- /* skip rest and continue with next token */\r
- _pico_parse_skip_rest( p );\r
- continue;\r
- }\r
- }\r
- }\r
- /* end map_diffuse block */\r
- }\r
- /* end material block */\r
-\r
- if( subMaterial == NULL )\r
- {\r
- /* allocate new pico shader */\r
- shader = PicoNewShader( model );\r
- if (shader == NULL)\r
- {\r
- PicoFreeModel( model );\r
- return NULL;\r
- }\r
-\r
- /* set material name */\r
- PicoSetShaderName( shader,materialName );\r
-\r
- /* set shader's transparency */\r
- PicoSetShaderTransparency( shader,transValue );\r
-\r
- /* set shader's ambient color */\r
- PicoSetShaderAmbientColor( shader,ambientColor );\r
-\r
- /* set diffuse alpha to transparency */\r
- diffuseColor[3] = (picoByte_t)( transValue * 255.0 );\r
-\r
- /* set shader's diffuse color */\r
- PicoSetShaderDiffuseColor( shader,diffuseColor );\r
-\r
- /* set shader's specular color */\r
- PicoSetShaderSpecularColor( shader,specularColor );\r
-\r
- /* set shader's shininess */\r
- PicoSetShaderShininess( shader,shineValue );\r
-\r
- /* set material map name */\r
- PicoSetShaderMapName( shader, mapname );\r
-\r
- /* this is just a material with 1 submaterial */\r
- subMaterial = _ase_add_submaterial( &materials, index, 0, shader );\r
- }\r
- \r
- /* ydnar: free mapname */\r
- if( mapname != NULL )\r
- _pico_free( mapname );\r
- } // !_pico_stricmp ( "*material" )\r
-\r
- /* skip unparsed rest of line and continue */\r
- _pico_parse_skip_rest( p );\r
- }\r
- \r
- /* ydnar: finish existing surface */\r
-// _ase_make_surface( model, &surface );\r
- _ase_submit_triangles (surface, model ,materials,faces);\r
- _ase_free_faces (&faces,&facesTail);\r
-\r
-#ifdef DEBUG_PM_ASE\r
- _ase_print_materials(materials);\r
- finish = clock();\r
- elapsed = (double)(finish - start) / CLOCKS_PER_SEC;\r
- _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed );\r
-#endif //DEBUG_PM_ASE\r
-\r
- _ase_free_materials(&materials);\r
-\r
- /* return allocated pico model */\r
- return model;\r
-}\r
-\r
-/* pico file format module definition */\r
-const picoModule_t picoModuleASE =\r
-{\r
- "1.0", /* module version string */\r
- "Autodesk 3DSMAX ASCII", /* module display name */\r
- "Jared Hefty, seaw0lf", /* author's name */\r
- "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */\r
- {\r
- "ase",NULL,NULL,NULL /* default extensions to use */\r
- },\r
- _ase_canload, /* validation routine */\r
- _ase_load, /* load routine */\r
- NULL, /* save validation routine */\r
- NULL /* save routine */\r
-};\r
+/* -----------------------------------------------------------------------------
+
+PicoModel Library
+
+Copyright (c) 2002, Randy Reddig & seaw0lf
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other aseMaterialList provided with the distribution.
+
+Neither the names of the copyright holders nor the names of its contributors may
+be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------------- */
+
+
+/* marker */
+#define PM_ASE_C
+
+/* uncomment when debugging this module */
+//#define DEBUG_PM_ASE
+//#define DEBUG_PM_ASE_EX
+
+
+/* dependencies */
+#include "picointernal.h"
+
+#ifdef DEBUG_PM_ASE
+#include "time.h"
+#endif
+
+/* plain white */
+static picoColor_t white = { 255, 255, 255, 255 };
+
+/* jhefty - multi-subobject material support */
+
+/* Material/SubMaterial management */
+/* A material should have 1..n submaterials assigned to it */
+
+typedef struct aseSubMaterial_s
+{
+ struct aseSubMaterial_s* next;
+ int subMtlId;
+ picoShader_t* shader;
+
+} aseSubMaterial_t;
+
+typedef struct aseMaterial_s
+{
+ struct aseMaterial_s* next;
+ struct aseSubMaterial_s* subMtls;
+ int mtlId;
+} aseMaterial_t;
+
+/* Material/SubMaterial management functions */
+static aseMaterial_t* _ase_get_material ( aseMaterial_t* list , int mtlIdParent )
+{
+ aseMaterial_t* mtl = list;
+
+ while ( mtl )
+ {
+ if ( mtlIdParent == mtl->mtlId )
+ {
+ break;
+ }
+ mtl = mtl->next;
+ }
+ return mtl;
+}
+
+static aseSubMaterial_t* _ase_get_submaterial ( aseMaterial_t* list, int mtlIdParent , int subMtlId )
+{
+ aseMaterial_t* parent = _ase_get_material ( list , mtlIdParent );
+ aseSubMaterial_t* subMtl = NULL;
+
+ if ( !parent )
+ {
+ _pico_printf ( PICO_ERROR , "No ASE material exists with id %i\n" , mtlIdParent );
+ return NULL;
+ }
+
+ subMtl = parent->subMtls;
+ while ( subMtl )
+ {
+ if ( subMtlId == subMtl->subMtlId )
+ {
+ break;
+ }
+ subMtl = subMtl->next;
+ }
+ return subMtl;
+}
+
+static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent )
+{
+ aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) );
+ mtl->mtlId = mtlIdParent;
+ mtl->subMtls = NULL;
+ mtl->next = *list;
+ *list = mtl;
+
+ return mtl;
+}
+
+static aseSubMaterial_t* _ase_add_submaterial( aseMaterial_t **list, int mtlIdParent, int subMtlId, picoShader_t* shader )
+{
+ aseMaterial_t *parent = _ase_get_material( *list, mtlIdParent );
+ aseSubMaterial_t *subMtl = _pico_calloc( 1, sizeof ( aseSubMaterial_t ) );
+
+ if ( !parent )
+ {
+ parent = _ase_add_material ( list , mtlIdParent );
+ }
+
+ subMtl->shader = shader;
+ subMtl->subMtlId = subMtlId;
+ subMtl->next = parent->subMtls;
+ parent->subMtls = subMtl;
+
+ return subMtl;
+}
+
+static void _ase_free_materials( aseMaterial_t **list )
+{
+ aseMaterial_t* mtl = *list;
+ aseSubMaterial_t* subMtl = NULL;
+
+ aseMaterial_t* mtlTemp = NULL;
+ aseSubMaterial_t* subMtlTemp = NULL;
+
+ while ( mtl )
+ {
+ subMtl = mtl->subMtls;
+ while ( subMtl )
+ {
+ subMtlTemp = subMtl->next;
+ _pico_free ( subMtl );
+ subMtl = subMtlTemp;
+ }
+ mtlTemp = mtl->next;
+ _pico_free ( mtl );
+ mtl = mtlTemp;
+ }
+ (*list) = NULL;
+}
+
+#ifdef DEBUG_PM_ASE
+static void _ase_print_materials( aseMaterial_t *list )
+{
+ aseMaterial_t* mtl = list;
+ aseSubMaterial_t* subMtl = NULL;
+
+ while ( mtl )
+ {
+ _pico_printf ( PICO_NORMAL , "ASE Material %i" , mtl->mtlId );
+ subMtl = mtl->subMtls;
+ while ( subMtl )
+ {
+ _pico_printf ( PICO_NORMAL , " -- ASE SubMaterial %i - %s\n" , subMtl->subMtlId , subMtl->shader->name );
+ subMtl = subMtl->next;
+ }
+ mtl = mtl->next;
+ }
+}
+#endif //DEBUG_PM_ASE
+
+/* ASE Face management */
+/* These are used to keep an association between a submaterial and a face definition */
+/* They are kept in parallel with the current picoSurface, */
+/* and are used by _ase_submit_triangles to lookup the proper material/submaterial IDs */
+typedef struct aseFace_s
+{
+ struct aseFace_s* next;
+ int mtlId;
+ int subMtlId;
+ int index[9];
+} aseFace_t;
+
+/* ASE Face management functions */
+void _ase_add_face( aseFace_t **list, aseFace_t **tail, aseFace_t *newFace )
+{
+ aseFace_t* face = *list;
+ aseFace_t* tempFace = NULL;
+
+ /* insert as head of list */
+ if ( !(*list) )
+ {
+ *list = newFace;
+ }
+ else
+ {
+ (*tail)->next = newFace;
+ }
+
+ *tail = newFace;
+ newFace->next = NULL;
+
+ //tag the color indices so we can detect them and apply the default color to them
+ newFace->index[6] = -1;
+ newFace->index[7] = -1;
+ newFace->index[8] = -1;
+}
+
+aseFace_t* _ase_get_face_for_index( aseFace_t *list, int index )
+{
+ int counter = 0;
+ aseFace_t* face = list;
+
+ while ( counter < index )
+ {
+ face = face->next;
+ counter++;
+ }
+ return face;
+}
+static void _ase_free_faces (aseFace_t** list, aseFace_t** tail )
+{
+ aseFace_t* face = *list;
+ aseFace_t* tempFace = NULL;
+
+ while ( face )
+ {
+ tempFace = face->next;
+ _pico_free ( face );
+ face = tempFace;
+ }
+
+ (*list) = NULL;
+ (*tail) = NULL;
+}
+
+/* todo:
+ * - apply material specific uv offsets to uv coordinates
+ */
+
+/* _ase_canload:
+ * validates a 3dsmax ase model file.
+ */
+static int _ase_canload( PM_PARAMS_CANLOAD )
+{
+ picoParser_t *p;
+
+
+ /* quick data length validation */
+ if( bufSize < 80 )
+ return PICO_PMV_ERROR_SIZE;
+
+ /* keep the friggin compiler happy */
+ *fileName = *fileName;
+
+ /* create pico parser */
+ p = _pico_new_parser( (picoByte_t*) buffer, bufSize );
+ if( p == NULL )
+ return PICO_PMV_ERROR_MEMORY;
+
+ /* get first token */
+ if( _pico_parse_first( p ) == NULL)
+ {
+ return PICO_PMV_ERROR_IDENT;
+ }
+
+ /* check first token */
+ if( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) )
+ {
+ _pico_free_parser( p );
+ return PICO_PMV_ERROR_IDENT;
+ }
+
+ /* free the pico parser object */
+ _pico_free_parser( p );
+
+ /* file seems to be a valid ase file */
+ return PICO_PMV_OK;
+}
+
+
+
+/* _ase_submit_triangles - jhefty
+ use the surface and the current face list to look up material/submaterial IDs
+ and submit them to the model for proper processing
+
+The following still holds from ydnar's _ase_make_surface:
+ indexes 0 1 2 = vert indexes
+ indexes 3 4 5 = st indexes
+ indexes 6 7 8 = color indexes (new)
+*/
+
+static void _ase_submit_triangles ( picoSurface_t* surface , picoModel_t* model , aseMaterial_t* materials , aseFace_t* faces )
+{
+ aseFace_t* face;
+ aseSubMaterial_t* subMtl;
+ picoVec3_t* xyz[3];
+ picoVec3_t* normal[3];
+ picoVec2_t* st[3];
+ picoColor_t* color[3];
+ int i;
+
+ face = faces;
+ while ( face != NULL )
+ {
+ /* look up the shader for the material/submaterial pair */
+ subMtl = _ase_get_submaterial( materials, face->mtlId, face->subMtlId );
+ if( subMtl == NULL )
+ {
+ /* ydnar: trying default submaterial */
+ subMtl = _ase_get_submaterial( materials, face->mtlId, 0 );
+ if( subMtl == NULL )
+ {
+ _pico_printf( PICO_ERROR, "Could not find material/submaterial for id %d/%d\n", face->mtlId, face->subMtlId );
+ return;
+ }
+ }
+
+ /* we pull the data from the surface using the facelist data */
+ for ( i = 0 ; i < 3 ; i ++ )
+ {
+ xyz[i] = (picoVec3_t*) PicoGetSurfaceXYZ ( surface, face->index[ i ] );
+ normal[i] = (picoVec3_t*) PicoGetSurfaceNormal( surface, face->index[ i ] );
+ st[i] = (picoVec2_t*) PicoGetSurfaceST ( surface, 0, face->index[ i + 3 ] );
+
+ if ( face->index [ i + 6] >= 0 )
+ {
+ color[i] = (picoColor_t*)PicoGetSurfaceColor ( surface, 0, face->index[ i + 6 ] );
+ }
+ else
+ {
+ color[i] = &white;
+ }
+
+ }
+
+ /* submit the triangle to the model */
+ PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader );
+
+ /* advance to the next face */
+ face = face->next;
+ }
+}
+
+/* _ase_load:
+ * loads a 3dsmax ase model file.
+*/
+static picoModel_t *_ase_load( PM_PARAMS_LOAD )
+{
+ picoModel_t *model;
+ picoSurface_t *surface = NULL;
+ picoParser_t *p;
+ char lastNodeName[ 1024 ];
+
+ aseFace_t* faces = NULL;
+ aseFace_t* facesTail = NULL;
+ aseMaterial_t* materials = NULL;
+
+#ifdef DEBUG_PM_ASE
+ clock_t start, finish;
+ double elapsed;
+ start = clock();
+#endif
+
+ /* helper */
+ #define _ase_error_return(m) \
+ { \
+ _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine); \
+ _pico_free_parser( p ); \
+ PicoFreeModel( model ); \
+ return NULL; \
+ }
+ /* create a new pico parser */
+ p = _pico_new_parser( (picoByte_t *)buffer,bufSize );
+ if (p == NULL) return NULL;
+
+ /* create a new pico model */
+ model = PicoNewModel();
+ if (model == NULL)
+ {
+ _pico_free_parser( p );
+ return NULL;
+ }
+ /* do model setup */
+ PicoSetModelFrameNum( model, frameNum );
+ PicoSetModelName( model, fileName );
+ PicoSetModelFileName( model, fileName );
+
+ /* initialize some stuff */
+ memset( lastNodeName,0,sizeof(lastNodeName) );
+
+ /* parse ase model file */
+ while( 1 )
+ {
+ /* get first token on line */
+ if (_pico_parse_first( p ) == NULL)
+ break;
+
+ /* we just skip empty lines */
+ if (p->token == NULL || !strlen( p->token ))
+ continue;
+
+ /* we skip invalid ase statements */
+ if (p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}')
+ {
+ _pico_parse_skip_rest( p );
+ continue;
+ }
+ /* remember node name */
+ if (!_pico_stricmp(p->token,"*node_name"))
+ {
+ /* read node name */
+ char *ptr = _pico_parse( p,0 );
+ if (ptr == NULL)
+ _ase_error_return("Node name parse error");
+
+ /* remember node name */
+ strncpy( lastNodeName,ptr,sizeof(lastNodeName) );
+ }
+ /* model mesh (originally contained within geomobject) */
+ else if (!_pico_stricmp(p->token,"*mesh"))
+ {
+ /* finish existing surface */
+ //_ase_make_surface( model, &surface );
+ _ase_submit_triangles (surface, model ,materials,faces);
+ _ase_free_faces (&faces,&facesTail);
+
+ /* allocate new pico surface */
+ surface = PicoNewSurface( NULL );
+ if (surface == NULL)
+ {
+ PicoFreeModel( model );
+ return NULL;
+ }
+ }
+ /* mesh material reference. this usually comes at the end of */
+ /* geomobjects after the mesh blocks. we must assume that the */
+ /* new mesh was already created so all we can do here is assign */
+ /* the material reference id (shader index) now. */
+ else if (!_pico_stricmp(p->token,"*material_ref"))
+ {
+ int mtlId;
+ aseFace_t* face;
+
+ /* we must have a valid surface */
+ if( surface == NULL )
+ _ase_error_return("Missing mesh for material reference");
+
+ /* get the material ref (0..n) */
+ if (!_pico_parse_int( p,&mtlId) )
+ _ase_error_return("Missing material reference ID");
+
+ /* fix up all of the aseFaceList in the surface to point to the parent material */
+ /* we've already saved off their subMtl */
+ face = faces;
+ while ( face != NULL )
+ {
+ face->mtlId = mtlId;
+ face = face->next;
+ }
+ }
+ /* model mesh vertex */
+ else if (!_pico_stricmp(p->token,"*mesh_vertex"))
+ {
+ picoVec3_t v;
+ int index;
+
+ /* we must have a valid surface */
+ if( surface == NULL )
+ continue;
+
+ /* get vertex data (orig: index +y -x +z) */
+ if (!_pico_parse_int( p,&index ))
+ _ase_error_return("Vertex parse error");
+ if (!_pico_parse_vec( p,v ))
+ _ase_error_return("Vertex parse error");
+
+ /* set vertex */
+ PicoSetSurfaceXYZ( surface,index,v );
+ }
+ /* model mesh vertex normal */
+ else if (!_pico_stricmp(p->token,"*mesh_vertexnormal"))
+ {
+ picoVec3_t v;
+ int index;
+
+ /* we must have a valid surface */
+ if( surface == NULL )
+ continue;
+
+ /* get vertex data (orig: index +y -x +z) */
+ if (!_pico_parse_int( p,&index ))
+ _ase_error_return("Vertex parse error");
+ if (!_pico_parse_vec( p,v ))
+ _ase_error_return("Vertex parse error");
+
+ /* set vertex */
+ PicoSetSurfaceNormal( surface,index,v );
+ }
+ /* model mesh face */
+ else if (!_pico_stricmp(p->token,"*mesh_face"))
+ {
+ picoIndex_t indexes[3];
+ int index;
+
+ /* we must have a valid surface */
+ if( surface == NULL )
+ continue;
+
+ /* get face index */
+ if (!_pico_parse_int( p,&index ))
+ _ase_error_return("Face parse error");
+
+ /* get 1st vertex index */
+ _pico_parse( p,0 );
+ if (!_pico_parse_int( p,&indexes[0] ))
+ _ase_error_return("Face parse error");
+
+ /* get 2nd vertex index */
+ _pico_parse( p,0 );
+ if (!_pico_parse_int( p,&indexes[1] ))
+ _ase_error_return("Face parse error");
+
+ /* get 3rd vertex index */
+ _pico_parse( p,0 );
+ if (!_pico_parse_int( p,&indexes[2] ))
+ _ase_error_return("Face parse error");
+
+ /* set face indexes (note interleaved offset!) */
+ PicoSetSurfaceIndex( surface, (index * 9 + 0), indexes[2] );
+ PicoSetSurfaceIndex( surface, (index * 9 + 1), indexes[1] );
+ PicoSetSurfaceIndex( surface, (index * 9 + 2), indexes[0] );
+
+ /* parse to the subMaterial ID */
+ while ( 1 )
+ {
+ _pico_parse (p,0);
+ if (!_pico_stricmp (p->token,"*MESH_MTLID" ))
+ {
+ aseFace_t* newFace;
+ int subMtlId;
+
+ _pico_parse_int ( p , &subMtlId );
+ newFace = _pico_calloc ( 1 , sizeof ( aseFace_t ));
+
+ /* we fix up the mtlId later when we parse the material_ref */
+ newFace->mtlId = 0;
+ newFace->subMtlId = subMtlId;
+ newFace->index[0] = indexes[2];
+ newFace->index[1] = indexes[1];
+ newFace->index[2] = indexes[0];
+
+ _ase_add_face ( &faces,&facesTail,newFace );
+ break;
+ }
+ }
+
+ }
+ /* model texture vertex */
+ else if (!_pico_stricmp(p->token,"*mesh_tvert"))
+ {
+ picoVec2_t uv;
+ int index;
+
+ /* we must have a valid surface */
+ if( surface == NULL )
+ continue;
+
+ /* get uv vertex index */
+ if (!_pico_parse_int( p,&index ))
+ _ase_error_return("UV vertex parse error");
+
+ /* get uv vertex s */
+ if (!_pico_parse_float( p,&uv[0] ))
+ _ase_error_return("UV vertex parse error");
+
+ /* get uv vertex t */
+ if (!_pico_parse_float( p,&uv[1] ))
+ _ase_error_return("UV vertex parse error");
+
+ /* ydnar: invert t */
+ uv[ 1 ] = 1.0f - uv[ 1 ];
+
+ /* set texture vertex */
+ PicoSetSurfaceST( surface,0,index,uv );
+ }
+ /* ydnar: model mesh texture face */
+ else if( !_pico_stricmp( p->token, "*mesh_tface" ) )
+ {
+ picoIndex_t indexes[3];
+ int index;
+ aseFace_t* face;
+
+ /* we must have a valid surface */
+ if( surface == NULL )
+ continue;
+
+ /* get face index */
+ if (!_pico_parse_int( p,&index ))
+ _ase_error_return("Texture face parse error");
+
+ /* get 1st vertex index */
+ if (!_pico_parse_int( p,&indexes[0] ))
+ _ase_error_return("Texture face parse error");
+
+ /* get 2nd vertex index */
+ if (!_pico_parse_int( p,&indexes[1] ))
+ _ase_error_return("Texture face parse error");
+
+ /* get 3rd vertex index */
+ if (!_pico_parse_int( p,&indexes[2] ))
+ _ase_error_return("Texture face parse error");
+
+ /* set face indexes (note interleaved offset!) */
+ PicoSetSurfaceIndex( surface, (index * 9 + 3), indexes[2] );
+ PicoSetSurfaceIndex( surface, (index * 9 + 4), indexes[1] );
+ PicoSetSurfaceIndex( surface, (index * 9 + 5), indexes[0] );
+
+ face = _ase_get_face_for_index(faces,index);
+ face->index[3] = indexes[2];
+ face->index[4] = indexes[1];
+ face->index[5] = indexes[0];
+ }
+ /* model color vertex */
+ else if (!_pico_stricmp(p->token,"*mesh_vertcol"))
+ {
+ picoColor_t color;
+ int index;
+ float colorInput;
+
+ /* we must have a valid surface */
+ if( surface == NULL )
+ continue;
+
+ /* get color vertex index */
+ if (!_pico_parse_int( p,&index ))
+ _ase_error_return("UV vertex parse error");
+
+ /* get R component */
+ if (!_pico_parse_float( p,&colorInput ))
+ _ase_error_return("color vertex parse error");
+ color[0] = (picoByte_t)(colorInput * 255);
+
+ /* get G component */
+ if (!_pico_parse_float( p,&colorInput ))
+ _ase_error_return("color vertex parse error");
+ color[1] = (picoByte_t)(colorInput * 255);
+
+ /* get B component */
+ if (!_pico_parse_float( p,&colorInput ))
+ _ase_error_return("color vertex parse error");
+ color[2] = (picoByte_t)(colorInput * 255);
+
+ /* leave alpha alone since we don't get any data from the ASE format */
+ color[3] = 255;
+
+ /* set texture vertex */
+ PicoSetSurfaceColor( surface,0,index,color );
+ }
+ /* model color face */
+ else if (!_pico_stricmp(p->token,"*mesh_cface"))
+ {
+ picoIndex_t indexes[3];
+ int index;
+ aseFace_t* face;
+
+ /* we must have a valid surface */
+ if( surface == NULL )
+ continue;
+
+ /* get face index */
+ if (!_pico_parse_int( p,&index ))
+ _ase_error_return("Face parse error");
+
+ /* get 1st cvertex index */
+ // _pico_parse( p,0 );
+ if (!_pico_parse_int( p,&indexes[0] ))
+ _ase_error_return("Face parse error");
+
+ /* get 2nd cvertex index */
+ // _pico_parse( p,0 );
+ if (!_pico_parse_int( p,&indexes[1] ))
+ _ase_error_return("Face parse error");
+
+ /* get 3rd cvertex index */
+ // _pico_parse( p,0 );
+ if (!_pico_parse_int( p,&indexes[2] ))
+ _ase_error_return("Face parse error");
+
+ /* set face indexes (note interleaved offset!) */
+ PicoSetSurfaceIndex( surface, (index * 9 + 6), indexes[2] );
+ PicoSetSurfaceIndex( surface, (index * 9 + 7), indexes[1] );
+ PicoSetSurfaceIndex( surface, (index * 9 + 8), indexes[0] );
+
+ face = _ase_get_face_for_index(faces,index);
+ face->index[6] = indexes[2];
+ face->index[7] = indexes[1];
+ face->index[8] = indexes[0];
+ }
+ /* model material */
+ else if( !_pico_stricmp( p->token, "*material" ) )
+ {
+ aseSubMaterial_t* subMaterial = NULL;
+ picoShader_t *shader;
+ int level = 1, index;
+ char materialName[ 1024 ];
+ float transValue = 0.0f, shineValue = 1.0f;
+ picoColor_t ambientColor, diffuseColor, specularColor;
+ char *mapname = NULL;
+ int subMtlId, subMaterialLevel = -1;
+
+
+ /* get material index */
+ _pico_parse_int( p,&index );
+
+ /* check brace */
+ if (!_pico_parse_check(p,1,"{"))
+ _ase_error_return("Material missing opening brace");
+
+ /* parse material block */
+ while( 1 )
+ {
+ /* get next token */
+ if (_pico_parse(p,1) == NULL) break;
+ if (!strlen(p->token)) continue;
+
+ /* handle levels */
+ if (p->token[0] == '{') level++;
+ if (p->token[0] == '}') level--;
+ if (!level) break;
+
+ if( level == subMaterialLevel )
+ {
+ /* set material name */
+ PicoSetShaderName( shader, materialName);
+
+ /* set shader's transparency */
+ PicoSetShaderTransparency( shader,transValue );
+
+ /* set shader's ambient color */
+ PicoSetShaderAmbientColor( shader,ambientColor );
+
+ /* set diffuse alpha to transparency */
+ diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
+
+ /* set shader's diffuse color */
+ PicoSetShaderDiffuseColor( shader,diffuseColor );
+
+ /* set shader's specular color */
+ PicoSetShaderSpecularColor( shader,specularColor );
+
+ /* set shader's shininess */
+ PicoSetShaderShininess( shader,shineValue );
+
+ /* set material map name */
+ PicoSetShaderMapName( shader, mapname );
+
+ subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader );
+ subMaterialLevel = -1;
+ }
+
+ /* parse submaterial index */
+ if (!_pico_stricmp(p->token,"*submaterial"))
+ {
+ /* allocate new pico shader */
+ _pico_parse_int( p , &subMtlId );
+
+ shader = PicoNewShader( model );
+ if (shader == NULL)
+ {
+ PicoFreeModel( model );
+ return NULL;
+ }
+ subMaterialLevel = level;
+ }
+ /* parse material name */
+ else if (!_pico_stricmp(p->token,"*material_name"))
+ {
+ char* name = _pico_parse(p,0);
+ if ( name == NULL)
+ _ase_error_return("Missing material name");
+
+ strcpy ( materialName , name );
+ /* skip rest and continue with next token */
+ _pico_parse_skip_rest( p );
+ continue;
+ }
+ /* parse material transparency */
+ else if (!_pico_stricmp(p->token,"*material_transparency"))
+ {
+ /* get transparency value from ase */
+ if (!_pico_parse_float( p,&transValue ))
+ _ase_error_return("Material transparency parse error");
+
+ /* skip rest and continue with next token */
+ _pico_parse_skip_rest( p );
+ continue;
+ }
+ /* parse material shininess */
+ else if (!_pico_stricmp(p->token,"*material_shine"))
+ {
+ /* remark:
+ * - not sure but instead of '*material_shine' i might
+ * need to use '*material_shinestrength' */
+
+ /* get shine value from ase */
+ if (!_pico_parse_float( p,&shineValue ))
+ _ase_error_return("Material shine parse error");
+
+ /* scale ase shine range 0..1 to pico range 0..127 */
+ shineValue *= 128.0;
+
+ /* skip rest and continue with next token */
+ _pico_parse_skip_rest( p );
+ continue;
+ }
+ /* parse ambient material color */
+ else if (!_pico_stricmp(p->token,"*material_ambient"))
+ {
+ picoVec3_t vec;
+ /* get r,g,b float values from ase */
+ if (!_pico_parse_vec( p,vec ))
+ _ase_error_return("Material color parse error");
+
+ /* setup 0..255 range color values */
+ ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
+ ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
+ ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
+ ambientColor[ 3 ] = (int)( 255 );
+
+ /* skip rest and continue with next token */
+ _pico_parse_skip_rest( p );
+ continue;
+ }
+ /* parse diffuse material color */
+ else if (!_pico_stricmp(p->token,"*material_diffuse"))
+ {
+ picoVec3_t vec;
+
+ /* get r,g,b float values from ase */
+ if (!_pico_parse_vec( p,vec ))
+ _ase_error_return("Material color parse error");
+
+ /* setup 0..255 range color */
+ diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
+ diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
+ diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
+ diffuseColor[ 3 ] = (int)( 255 );
+
+ /* skip rest and continue with next token */
+ _pico_parse_skip_rest( p );
+ continue;
+ }
+ /* parse specular material color */
+ else if (!_pico_stricmp(p->token,"*material_specular"))
+ {
+ picoVec3_t vec;
+
+ /* get r,g,b float values from ase */
+ if (!_pico_parse_vec( p,vec ))
+ _ase_error_return("Material color parse error");
+
+ /* setup 0..255 range color */
+ specularColor[ 0 ] = (int)( vec[ 0 ] * 255 );
+ specularColor[ 1 ] = (int)( vec[ 1 ] * 255 );
+ specularColor[ 2 ] = (int)( vec[ 2 ] * 255 );
+ specularColor[ 3 ] = (int)( 255 );
+
+ /* skip rest and continue with next token */
+ _pico_parse_skip_rest( p );
+ continue;
+ }
+ /* material diffuse map */
+ else if (!_pico_stricmp(p->token,"*map_diffuse") )
+ {
+ int sublevel = 0;
+
+ /* parse material block */
+ while( 1 )
+ {
+ /* get next token */
+ if (_pico_parse(p,1) == NULL) break;
+ if (!strlen(p->token)) continue;
+
+ /* handle levels */
+ if (p->token[0] == '{') sublevel++;
+ if (p->token[0] == '}') sublevel--;
+ if (!sublevel) break;
+
+ /* parse diffuse map bitmap */
+ if (!_pico_stricmp(p->token,"*bitmap"))
+ {
+ char* name = _pico_parse(p,0);
+ if (name == NULL)
+ _ase_error_return("Missing material map bitmap name");
+ mapname = _pico_alloc ( strlen ( name ) + 1 );
+ strcpy ( mapname, name );
+ /* skip rest and continue with next token */
+ _pico_parse_skip_rest( p );
+ continue;
+ }
+ }
+ }
+ /* end map_diffuse block */
+ }
+ /* end material block */
+
+ if( subMaterial == NULL )
+ {
+ /* allocate new pico shader */
+ shader = PicoNewShader( model );
+ if (shader == NULL)
+ {
+ PicoFreeModel( model );
+ return NULL;
+ }
+
+ /* set material name */
+ PicoSetShaderName( shader,materialName );
+
+ /* set shader's transparency */
+ PicoSetShaderTransparency( shader,transValue );
+
+ /* set shader's ambient color */
+ PicoSetShaderAmbientColor( shader,ambientColor );
+
+ /* set diffuse alpha to transparency */
+ diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
+
+ /* set shader's diffuse color */
+ PicoSetShaderDiffuseColor( shader,diffuseColor );
+
+ /* set shader's specular color */
+ PicoSetShaderSpecularColor( shader,specularColor );
+
+ /* set shader's shininess */
+ PicoSetShaderShininess( shader,shineValue );
+
+ /* set material map name */
+ PicoSetShaderMapName( shader, mapname );
+
+ /* this is just a material with 1 submaterial */
+ subMaterial = _ase_add_submaterial( &materials, index, 0, shader );
+ }
+
+ /* ydnar: free mapname */
+ if( mapname != NULL )
+ _pico_free( mapname );
+ } // !_pico_stricmp ( "*material" )
+
+ /* skip unparsed rest of line and continue */
+ _pico_parse_skip_rest( p );
+ }
+
+ /* ydnar: finish existing surface */
+// _ase_make_surface( model, &surface );
+ _ase_submit_triangles (surface, model ,materials,faces);
+ _ase_free_faces (&faces,&facesTail);
+
+#ifdef DEBUG_PM_ASE
+ _ase_print_materials(materials);
+ finish = clock();
+ elapsed = (double)(finish - start) / CLOCKS_PER_SEC;
+ _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed );
+#endif //DEBUG_PM_ASE
+
+ _ase_free_materials(&materials);
+
+ /* return allocated pico model */
+ return model;
+}
+
+/* pico file format module definition */
+const picoModule_t picoModuleASE =
+{
+ "1.0", /* module version string */
+ "Autodesk 3DSMAX ASCII", /* module display name */
+ "Jared Hefty, seaw0lf", /* author's name */
+ "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */
+ {
+ "ase",NULL,NULL,NULL /* default extensions to use */
+ },
+ _ase_canload, /* validation routine */
+ _ase_load, /* load routine */
+ NULL, /* save validation routine */
+ NULL /* save routine */
+};