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 /* create pico parser */
225 p = _pico_new_parser( (const picoByte_t*) buffer, bufSize );
227 return PICO_PMV_ERROR_MEMORY;
229 /* get first token */
230 if( _pico_parse_first( p ) == NULL)
232 return PICO_PMV_ERROR_IDENT;
235 /* check first token */
236 if( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) )
238 _pico_free_parser( p );
239 return PICO_PMV_ERROR_IDENT;
242 /* free the pico parser object */
243 _pico_free_parser( p );
245 /* file seems to be a valid ase file */
249 typedef struct aseVertex_s aseVertex_t;
257 typedef struct aseTexCoord_s aseTexCoord_t;
263 typedef struct aseColor_s aseColor_t;
269 typedef struct aseFace_s aseFace_t;
272 picoIndex_t indices[9];
273 picoIndex_t smoothingGroup;
274 picoIndex_t materialId;
275 picoIndex_t subMaterialId;
277 typedef aseFace_t* aseFacesIter_t;
279 picoSurface_t* PicoModelFindOrAddSurface( picoModel_t *model, picoShader_t* shader )
281 /* see if a surface already has the shader */
283 for ( ; i < model->numSurfaces ; i++ )
285 picoSurface_t* workSurface = model->surface[i];
286 if ( workSurface->shader == shader )
292 /* no surface uses this shader yet, so create a new surface */
295 /* create a new surface in the model for the unique shader */
296 picoSurface_t* workSurface = PicoNewSurface(model);
299 _pico_printf ( PICO_ERROR , "Could not allocate a new surface!\n" );
303 /* do surface setup */
304 PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
305 PicoSetSurfaceName( workSurface, shader->name );
306 PicoSetSurfaceShader( workSurface, shader );
312 /* _ase_submit_triangles - jhefty
313 use the surface and the current face list to look up material/submaterial IDs
314 and submit them to the model for proper processing
316 The following still holds from ydnar's _ase_make_surface:
317 indexes 0 1 2 = vert indexes
318 indexes 3 4 5 = st indexes
319 indexes 6 7 8 = color indexes (new)
323 typedef picoIndex_t* picoIndexIter_t;
325 typedef struct aseUniqueIndices_s aseUniqueIndices_t;
326 struct aseUniqueIndices_s
334 size_t aseUniqueIndices_size(aseUniqueIndices_t* self)
336 return self->last - self->data;
339 void aseUniqueIndices_reserve(aseUniqueIndices_t* self, picoIndex_t size)
341 self->data = self->last = (picoIndex_t*)_pico_calloc(size, sizeof(picoIndex_t));
344 void aseUniqueIndices_clear(aseUniqueIndices_t* self)
346 _pico_free(self->data);
349 void aseUniqueIndices_pushBack(aseUniqueIndices_t* self, picoIndex_t index)
351 *self->last++ = index;
354 picoIndex_t aseFaces_getVertexIndex(aseFace_t* faces, picoIndex_t index)
356 return faces[index / 3].indices[index % 3];
359 picoIndex_t aseFaces_getTexCoordIndex(aseFace_t* faces, picoIndex_t index)
361 return faces[index / 3].indices[(index % 3) + 3];
364 picoIndex_t aseFaces_getColorIndex(aseFace_t* faces, picoIndex_t index)
366 return faces[index / 3].indices[(index % 3) + 6];
369 int aseUniqueIndex_equal(aseFace_t* faces, picoIndex_t index, picoIndex_t other)
371 return aseFaces_getVertexIndex(faces, index) == aseFaces_getVertexIndex(faces, other)
372 && aseFaces_getTexCoordIndex(faces, index) == aseFaces_getTexCoordIndex(faces, other)
373 && aseFaces_getColorIndex(faces, index) == aseFaces_getColorIndex(faces, other);
376 picoIndex_t aseUniqueIndices_insertUniqueVertex(aseUniqueIndices_t* self, picoIndex_t index)
378 picoIndexIter_t i = self->data;
379 for(; i != self->last; ++i)
381 picoIndex_t other = (picoIndex_t)(i - self->data);
382 if(aseUniqueIndex_equal(self->faces, index, other))
388 aseUniqueIndices_pushBack(self, index);
389 return (picoIndex_t)(aseUniqueIndices_size(self) - 1);
392 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 )
394 aseFacesIter_t i = faces, end = faces + numFaces;
396 aseUniqueIndices_t indices;
397 aseUniqueIndices_t remap;
398 aseUniqueIndices_reserve(&indices, numFaces * 3);
399 aseUniqueIndices_reserve(&remap, numFaces * 3);
400 indices.faces = faces;
404 /* look up the shader for the material/submaterial pair */
405 aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, (*i).materialId, (*i).subMaterialId );
412 picoSurface_t* surface = PicoModelFindOrAddSurface(model, subMtl->shader);
414 /* we pull the data from the vertex, color and texcoord arrays using the face index data */
415 for ( j = 0 ; j < 3 ; j ++ )
417 picoIndex_t index = (picoIndex_t)(((i - faces) * 3) + j);
418 picoIndex_t size = (picoIndex_t)aseUniqueIndices_size(&indices);
419 picoIndex_t unique = aseUniqueIndices_insertUniqueVertex(&indices, index);
421 picoIndex_t numVertexes = PicoGetSurfaceNumVertexes(surface);
422 picoIndex_t numIndexes = PicoGetSurfaceNumIndexes(surface);
424 aseUniqueIndices_pushBack(&remap, numIndexes);
426 PicoSetSurfaceIndex(surface, numIndexes, remap.data[unique]);
430 PicoSetSurfaceXYZ(surface, numVertexes, vertices[(*i).indices[j]].xyz);
431 PicoSetSurfaceNormal(surface, numVertexes, vertices[(*i).indices[j]].normal);
432 PicoSetSurfaceST(surface, 0, numVertexes, texcoords[(*i).indices[j + 3]].texcoord);
434 if ( (*i).indices[j + 6] >= 0 )
436 PicoSetSurfaceColor(surface, 0, numVertexes, colors[(*i).indices[j + 6]].color);
440 PicoSetSurfaceColor(surface, 0, numVertexes, white);
443 PicoSetSurfaceSmoothingGroup(surface, numVertexes, (vertices[(*i).indices[j]].id * (1 << 16)) + (*i).smoothingGroup);
449 aseUniqueIndices_clear(&indices);
450 aseUniqueIndices_clear(&remap);
455 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 )
457 aseFacesIter_t i = faces, end = faces + numFaces;
460 /* look up the shader for the material/submaterial pair */
461 aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, (*i).materialId, (*i).subMaterialId );
469 picoVec3_t* normal[3];
471 picoColor_t* color[3];
472 picoIndex_t smooth[3];
474 /* we pull the data from the vertex, color and texcoord arrays using the face index data */
475 for ( j = 0 ; j < 3 ; j ++ )
477 xyz[j] = &vertices[(*i).indices[j]].xyz;
478 normal[j] = &vertices[(*i).indices[j]].normal;
479 st[j] = &texcoords[(*i).indices[j + 3]].texcoord;
481 if( colors != NULL && (*i).indices[j + 6] >= 0 )
483 color[j] = &colors[(*i).indices[j + 6]].color;
490 smooth[j] = (vertices[(*i).indices[j]].id * (1 << 16)) + (*i).smoothingGroup; /* don't merge vertices */
494 /* submit the triangle to the model */
495 PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader, name, smooth );
500 static void shadername_convert(char* shaderName)
502 /* unix-style path separators */
503 char* s = shaderName;
504 for(; *s != '\0'; ++s)
515 * loads a 3dsmax ase model file.
517 static picoModel_t *_ase_load( PM_PARAMS_LOAD )
521 char lastNodeName[ 1024 ];
523 aseVertex_t* vertices = NULL;
524 aseTexCoord_t* texcoords = NULL;
525 aseColor_t* colors = NULL;
526 aseFace_t* faces = NULL;
529 int numTextureVertices = 0;
530 int numTextureVertexFaces = 0;
531 int numColorVertices = 0;
532 int numColorVertexFaces = 0;
535 aseMaterial_t* materials = NULL;
538 clock_t start, finish;
544 #define _ase_error_return(m) \
546 _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine); \
547 _pico_free_parser( p ); \
548 PicoFreeModel( model ); \
551 /* create a new pico parser */
552 p = _pico_new_parser( (const picoByte_t *)buffer,bufSize );
553 if (p == NULL) return NULL;
555 /* create a new pico model */
556 model = PicoNewModel();
559 _pico_free_parser( p );
563 PicoSetModelFrameNum( model, frameNum );
564 PicoSetModelName( model, fileName );
565 PicoSetModelFileName( model, fileName );
567 /* initialize some stuff */
568 memset( lastNodeName,0,sizeof(lastNodeName) );
570 /* parse ase model file */
573 /* get first token on line */
574 if (_pico_parse_first( p ) == NULL)
577 /* we just skip empty lines */
578 if (p->token == NULL || !strlen( p->token ))
581 /* we skip invalid ase statements */
582 if (p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}')
584 _pico_parse_skip_rest( p );
587 /* remember node name */
588 if (!_pico_stricmp(p->token,"*node_name"))
591 char *ptr = _pico_parse( p,0 );
593 _ase_error_return("Node name parse error");
595 /* remember node name */
596 strncpy( lastNodeName,ptr,sizeof(lastNodeName) );
598 /* model mesh (originally contained within geomobject) */
599 else if (!_pico_stricmp(p->token,"*mesh"))
601 /* finish existing surface */
602 _ase_submit_triangles(model, materials, vertices, texcoords, colors, faces, numFaces, lastNodeName);
604 _pico_free(vertices);
605 _pico_free(texcoords);
608 else if (!_pico_stricmp(p->token,"*mesh_numvertex"))
610 if (!_pico_parse_int( p, &numVertices) )
611 _ase_error_return("Missing MESH_NUMVERTEX value");
613 vertices = _pico_calloc(numVertices, sizeof(aseVertex_t));
615 else if (!_pico_stricmp(p->token,"*mesh_numfaces"))
617 if (!_pico_parse_int( p, &numFaces) )
618 _ase_error_return("Missing MESH_NUMFACES value");
620 faces = _pico_calloc(numFaces, sizeof(aseFace_t));
622 else if (!_pico_stricmp(p->token,"*mesh_numtvertex"))
624 if (!_pico_parse_int( p, &numTextureVertices) )
625 _ase_error_return("Missing MESH_NUMTVERTEX value");
627 texcoords = _pico_calloc(numTextureVertices, sizeof(aseTexCoord_t));
629 else if (!_pico_stricmp(p->token,"*mesh_numtvfaces"))
631 if (!_pico_parse_int( p, &numTextureVertexFaces) )
632 _ase_error_return("Missing MESH_NUMTVFACES value");
634 else if (!_pico_stricmp(p->token,"*mesh_numcvertex"))
636 if (!_pico_parse_int( p, &numColorVertices) )
637 _ase_error_return("Missing MESH_NUMCVERTEX value");
639 colors = _pico_calloc(numColorVertices, sizeof(aseColor_t));
640 memset( colors, 255, numColorVertices * sizeof( aseColor_t ) ); /* ydnar: force colors to white initially */
642 else if (!_pico_stricmp(p->token,"*mesh_numcvfaces"))
644 if (!_pico_parse_int( p, &numColorVertexFaces) )
645 _ase_error_return("Missing MESH_NUMCVFACES value");
647 /* mesh material reference. this usually comes at the end of */
648 /* geomobjects after the mesh blocks. we must assume that the */
649 /* new mesh was already created so all we can do here is assign */
650 /* the material reference id (shader index) now. */
651 else if (!_pico_stricmp(p->token,"*material_ref"))
655 /* get the material ref (0..n) */
656 if (!_pico_parse_int( p,&mtlId) )
657 _ase_error_return("Missing material reference ID");
661 /* fix up all of the aseFaceList in the surface to point to the parent material */
662 /* we've already saved off their subMtl */
663 for(; i < numFaces; ++i)
665 faces[i].materialId = mtlId;
669 /* model mesh vertex */
670 else if (!_pico_stricmp(p->token,"*mesh_vertex"))
674 if( numVertices == 0 )
675 _ase_error_return("Vertex parse error");
677 /* get vertex data (orig: index +y -x +z) */
678 if (!_pico_parse_int( p,&index ))
679 _ase_error_return("Vertex parse error");
680 if (!_pico_parse_vec( p,vertices[index].xyz ))
681 _ase_error_return("Vertex parse error");
683 vertices[index].id = vertexId++;
685 /* model mesh vertex normal */
686 else if (!_pico_stricmp(p->token,"*mesh_vertexnormal"))
690 if( numVertices == 0 )
691 _ase_error_return("Vertex parse error");
693 /* get vertex data (orig: index +y -x +z) */
694 if (!_pico_parse_int( p,&index ))
695 _ase_error_return("Vertex parse error");
696 if (!_pico_parse_vec( p,vertices[index].normal ))
697 _ase_error_return("Vertex parse error");
699 /* model mesh face */
700 else if (!_pico_stricmp(p->token,"*mesh_face"))
702 picoIndex_t indexes[3];
706 _ase_error_return("Face parse error");
709 if (!_pico_parse_int( p,&index ))
710 _ase_error_return("Face parse error");
712 /* get 1st vertex index */
714 if (!_pico_parse_int( p,&indexes[0] ))
715 _ase_error_return("Face parse error");
717 /* get 2nd vertex index */
719 if (!_pico_parse_int( p,&indexes[1] ))
720 _ase_error_return("Face parse error");
722 /* get 3rd vertex index */
724 if (!_pico_parse_int( p,&indexes[2] ))
725 _ase_error_return("Face parse error");
727 /* parse to the subMaterial ID */
730 if (!_pico_parse (p,0)) /* EOL */
734 if (!_pico_stricmp (p->token,"*MESH_SMOOTHING" ))
736 _pico_parse_int ( p , &faces[index].smoothingGroup );
738 if (!_pico_stricmp (p->token,"*MESH_MTLID" ))
740 _pico_parse_int ( p , &faces[index].subMaterialId );
744 faces[index].materialId = 0;
745 faces[index].indices[0] = indexes[2];
746 faces[index].indices[1] = indexes[1];
747 faces[index].indices[2] = indexes[0];
749 /* model texture vertex */
750 else if (!_pico_stricmp(p->token,"*mesh_tvert"))
754 if( numVertices == 0 )
755 _ase_error_return("Texture Vertex parse error");
757 /* get uv vertex index */
758 if (!_pico_parse_int( p,&index ) || index >= numTextureVertices)
759 _ase_error_return("Texture vertex parse error");
761 /* get uv vertex s */
762 if (!_pico_parse_float( p,&texcoords[index].texcoord[0] ))
763 _ase_error_return("Texture vertex parse error");
765 /* get uv vertex t */
766 if (!_pico_parse_float( p,&texcoords[index].texcoord[1] ))
767 _ase_error_return("Texture vertex parse error");
769 /* ydnar: invert t */
770 texcoords[index].texcoord[ 1 ] = 1.0f - texcoords[index].texcoord[ 1 ];
772 /* ydnar: model mesh texture face */
773 else if( !_pico_stricmp( p->token, "*mesh_tface" ) )
775 picoIndex_t indexes[3];
779 _ase_error_return("Texture face parse error");
782 if (!_pico_parse_int( p,&index ))
783 _ase_error_return("Texture face parse error");
785 /* get 1st vertex index */
786 if (!_pico_parse_int( p,&indexes[0] ))
787 _ase_error_return("Texture face parse error");
789 /* get 2nd vertex index */
790 if (!_pico_parse_int( p,&indexes[1] ))
791 _ase_error_return("Texture face parse error");
793 /* get 3rd vertex index */
794 if (!_pico_parse_int( p,&indexes[2] ))
795 _ase_error_return("Texture face parse error");
797 faces[index].indices[3] = indexes[2];
798 faces[index].indices[4] = indexes[1];
799 faces[index].indices[5] = indexes[0];
801 /* model color vertex */
802 else if (!_pico_stricmp(p->token,"*mesh_vertcol"))
807 if( numVertices == 0 )
808 _ase_error_return("Color Vertex parse error");
810 /* get color vertex index */
811 if (!_pico_parse_int( p,&index ))
812 _ase_error_return("Color vertex parse error");
814 /* get R component */
815 if (!_pico_parse_float( p,&colorInput ))
816 _ase_error_return("Color vertex parse error");
817 colors[index].color[0] = (picoByte_t)(colorInput * 255);
819 /* get G component */
820 if (!_pico_parse_float( p,&colorInput ))
821 _ase_error_return("Color vertex parse error");
822 colors[index].color[1] = (picoByte_t)(colorInput * 255);
824 /* get B component */
825 if (!_pico_parse_float( p,&colorInput ))
826 _ase_error_return("Color vertex parse error");
827 colors[index].color[2] = (picoByte_t)(colorInput * 255);
829 /* leave alpha alone since we don't get any data from the ASE format */
830 colors[index].color[3] = 255;
832 /* model color face */
833 else if (!_pico_stricmp(p->token,"*mesh_cface"))
835 picoIndex_t indexes[3];
839 _ase_error_return("Face parse error");
842 if (!_pico_parse_int( p,&index ))
843 _ase_error_return("Face parse error");
845 /* get 1st cvertex index */
846 // _pico_parse( p,0 );
847 if (!_pico_parse_int( p,&indexes[0] ))
848 _ase_error_return("Face parse error");
850 /* get 2nd cvertex index */
851 // _pico_parse( p,0 );
852 if (!_pico_parse_int( p,&indexes[1] ))
853 _ase_error_return("Face parse error");
855 /* get 3rd cvertex index */
856 // _pico_parse( p,0 );
857 if (!_pico_parse_int( p,&indexes[2] ))
858 _ase_error_return("Face parse error");
860 faces[index].indices[6] = indexes[2];
861 faces[index].indices[7] = indexes[1];
862 faces[index].indices[8] = indexes[0];
865 else if( !_pico_stricmp( p->token, "*material" ) )
867 aseSubMaterial_t* subMaterial = NULL;
868 picoShader_t *shader = NULL;
869 int level = 1, index;
870 char materialName[ 1024 ];
871 float transValue = 0.0f, shineValue = 1.0f;
872 picoColor_t ambientColor, diffuseColor, specularColor;
873 char *mapname = NULL;
874 int subMtlId, subMaterialLevel = -1;
877 /* get material index */
878 _pico_parse_int( p,&index );
881 if (!_pico_parse_check(p,1,"{"))
882 _ase_error_return("Material missing opening brace");
884 /* parse material block */
888 if (_pico_parse(p,1) == NULL) break;
889 if (!strlen(p->token)) continue;
892 if (p->token[0] == '{') level++;
893 if (p->token[0] == '}') level--;
896 if( level == subMaterialLevel )
898 /* set material name */
899 _pico_first_token( materialName );
900 shadername_convert(materialName);
901 PicoSetShaderName( shader, materialName);
903 /* set shader's transparency */
904 PicoSetShaderTransparency( shader,transValue );
906 /* set shader's ambient color */
907 PicoSetShaderAmbientColor( shader,ambientColor );
909 /* set diffuse alpha to transparency */
910 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
912 /* set shader's diffuse color */
913 PicoSetShaderDiffuseColor( shader,diffuseColor );
915 /* set shader's specular color */
916 PicoSetShaderSpecularColor( shader,specularColor );
918 /* set shader's shininess */
919 PicoSetShaderShininess( shader,shineValue );
921 /* set material map name */
922 PicoSetShaderMapName( shader, mapname );
924 subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader );
925 subMaterialLevel = -1;
928 /* parse submaterial index */
929 if (!_pico_stricmp(p->token,"*submaterial"))
931 /* allocate new pico shader */
932 _pico_parse_int( p , &subMtlId );
934 shader = PicoNewShader( model );
937 PicoFreeModel( model );
940 subMaterialLevel = level;
942 /* parse material name */
943 else if (!_pico_stricmp(p->token,"*material_name"))
945 char* name = _pico_parse(p,0);
947 _ase_error_return("Missing material name");
949 strcpy ( materialName , name );
950 /* skip rest and continue with next token */
951 _pico_parse_skip_rest( p );
954 /* parse material transparency */
955 else if (!_pico_stricmp(p->token,"*material_transparency"))
957 /* get transparency value from ase */
958 if (!_pico_parse_float( p,&transValue ))
959 _ase_error_return("Material transparency parse error");
961 /* skip rest and continue with next token */
962 _pico_parse_skip_rest( p );
965 /* parse material shininess */
966 else if (!_pico_stricmp(p->token,"*material_shine"))
969 * - not sure but instead of '*material_shine' i might
970 * need to use '*material_shinestrength' */
972 /* get shine value from ase */
973 if (!_pico_parse_float( p,&shineValue ))
974 _ase_error_return("Material shine parse error");
976 /* scale ase shine range 0..1 to pico range 0..127 */
979 /* skip rest and continue with next token */
980 _pico_parse_skip_rest( p );
983 /* parse ambient material color */
984 else if (!_pico_stricmp(p->token,"*material_ambient"))
987 /* get r,g,b float values from ase */
988 if (!_pico_parse_vec( p,vec ))
989 _ase_error_return("Material color parse error");
991 /* setup 0..255 range color values */
992 ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
993 ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
994 ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
995 ambientColor[ 3 ] = (int)( 255 );
997 /* skip rest and continue with next token */
998 _pico_parse_skip_rest( p );
1001 /* parse diffuse material color */
1002 else if (!_pico_stricmp(p->token,"*material_diffuse"))
1006 /* get r,g,b float values from ase */
1007 if (!_pico_parse_vec( p,vec ))
1008 _ase_error_return("Material color parse error");
1010 /* setup 0..255 range color */
1011 diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 );
1012 diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 );
1013 diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 );
1014 diffuseColor[ 3 ] = (int)( 255 );
1016 /* skip rest and continue with next token */
1017 _pico_parse_skip_rest( p );
1020 /* parse specular material color */
1021 else if (!_pico_stricmp(p->token,"*material_specular"))
1025 /* get r,g,b float values from ase */
1026 if (!_pico_parse_vec( p,vec ))
1027 _ase_error_return("Material color parse error");
1029 /* setup 0..255 range color */
1030 specularColor[ 0 ] = (int)( vec[ 0 ] * 255 );
1031 specularColor[ 1 ] = (int)( vec[ 1 ] * 255 );
1032 specularColor[ 2 ] = (int)( vec[ 2 ] * 255 );
1033 specularColor[ 3 ] = (int)( 255 );
1035 /* skip rest and continue with next token */
1036 _pico_parse_skip_rest( p );
1039 /* material diffuse map */
1040 else if (!_pico_stricmp(p->token,"*map_diffuse") )
1044 /* parse material block */
1047 /* get next token */
1048 if (_pico_parse(p,1) == NULL) break;
1049 if (!strlen(p->token)) continue;
1052 if (p->token[0] == '{') sublevel++;
1053 if (p->token[0] == '}') sublevel--;
1054 if (!sublevel) break;
1056 /* parse diffuse map bitmap */
1057 if (!_pico_stricmp(p->token,"*bitmap"))
1059 char* name = _pico_parse(p,0);
1061 _ase_error_return("Missing material map bitmap name");
1062 mapname = _pico_alloc ( strlen ( name ) + 1 );
1063 strcpy ( mapname, name );
1064 /* skip rest and continue with next token */
1065 _pico_parse_skip_rest( p );
1070 /* end map_diffuse block */
1072 /* end material block */
1074 if( subMaterial == NULL )
1076 /* allocate new pico shader */
1077 shader = PicoNewShader( model );
1080 PicoFreeModel( model );
1084 /* set material name */
1085 shadername_convert(materialName);
1086 PicoSetShaderName( shader,materialName );
1088 /* set shader's transparency */
1089 PicoSetShaderTransparency( shader,transValue );
1091 /* set shader's ambient color */
1092 PicoSetShaderAmbientColor( shader,ambientColor );
1094 /* set diffuse alpha to transparency */
1095 diffuseColor[3] = (picoByte_t)( transValue * 255.0 );
1097 /* set shader's diffuse color */
1098 PicoSetShaderDiffuseColor( shader,diffuseColor );
1100 /* set shader's specular color */
1101 PicoSetShaderSpecularColor( shader,specularColor );
1103 /* set shader's shininess */
1104 PicoSetShaderShininess( shader,shineValue );
1106 /* set material map name */
1107 PicoSetShaderMapName( shader, mapname );
1109 /* extract shadername from bitmap path */
1114 /* convert to shader-name format */
1115 shadername_convert(mapname);
1117 /* remove extension */
1118 char* last_period = strrchr(p, '.');
1119 if(last_period != NULL)
1121 *last_period = '\0';
1125 /* find shader path */
1126 for(; *p != '\0'; ++p)
1128 if(_pico_strnicmp(p, "models/", 7) == 0 || _pico_strnicmp(p, "textures/", 9) == 0)
1136 /* set material name */
1137 PicoSetShaderName( shader,p );
1141 /* this is just a material with 1 submaterial */
1142 subMaterial = _ase_add_submaterial( &materials, index, 0, shader );
1145 /* ydnar: free mapname */
1146 if( mapname != NULL )
1147 _pico_free( mapname );
1148 } // !_pico_stricmp ( "*material" )
1150 /* skip unparsed rest of line and continue */
1151 _pico_parse_skip_rest( p );
1154 /* ydnar: finish existing surface */
1155 _ase_submit_triangles(model, materials, vertices, texcoords, colors, faces, numFaces, lastNodeName);
1157 _pico_free(vertices);
1158 _pico_free(texcoords);
1162 _ase_print_materials(materials);
1164 elapsed = (double)(finish - start) / CLOCKS_PER_SEC;
1165 _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed );
1166 #endif //DEBUG_PM_ASE
1168 _ase_free_materials(&materials);
1170 _pico_free_parser( p );
1172 /* return allocated pico model */
1176 /* pico file format module definition */
1177 const picoModule_t picoModuleASE =
1179 "1.0", /* module version string */
1180 "Autodesk 3DSMAX ASCII", /* module display name */
1181 "Jared Hefty, seaw0lf", /* author's name */
1182 "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */
1184 "ase",NULL,NULL,NULL /* default extensions to use */
1186 _ase_canload, /* validation routine */
1187 _ase_load, /* load routine */
1188 NULL, /* save validation routine */
1189 NULL /* save routine */