2012-05-28 03:33:41 +00:00
/* -----------------------------------------------------------------------------
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 .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void Sys_Printf ( const char * format , . . . ) ;
/* 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 ;
}
aseSubMaterial_t * _ase_get_submaterial_or_default ( aseMaterial_t * materials , int mtlIdParent , int subMtlId ) {
aseSubMaterial_t * subMtl = _ase_get_submaterial ( materials , mtlIdParent , subMtlId ) ;
if ( subMtl ! = NULL ) {
return subMtl ;
}
/* ydnar: trying default submaterial */
subMtl = _ase_get_submaterial ( materials , mtlIdParent , 0 ) ;
if ( subMtl ! = NULL ) {
return subMtl ;
}
_pico_printf ( PICO_ERROR , " Could not find material/submaterial for id %d/%d \n " , mtlIdParent , subMtlId ) ;
return NULL ;
}
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
/* todo:
* - apply material specific uv offsets to uv coordinates
*/
/* _ase_canload:
* validates a 3 dsmax 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 ;
}
typedef struct aseVertex_s aseVertex_t ;
struct aseVertex_s
{
picoVec3_t xyz ;
picoIndex_t id ;
} ;
typedef struct aseTexCoord_s aseTexCoord_t ;
struct aseTexCoord_s
{
picoVec2_t texcoord ;
} ;
typedef struct aseColor_s aseColor_t ;
struct aseColor_s
{
picoColor_t color ;
} ;
typedef struct aseFace_s aseFace_t ;
struct aseFace_s
{
picoIndex_t indices [ 9 ] ;
picoIndex_t smoothingGroup ;
picoIndex_t materialId ;
picoIndex_t subMaterialId ;
picoVec3_t facenormal ;
picoVec3_t vertexnormal [ 3 ] ;
} ;
typedef aseFace_t * aseFacesIter_t ;
picoSurface_t * PicoModelFindOrAddSurface ( picoModel_t * model , picoShader_t * shader ) {
/* see if a surface already has the shader */
int i = 0 ;
for ( ; i < model - > numSurfaces ; i + + )
{
picoSurface_t * workSurface = model - > surface [ i ] ;
if ( workSurface - > shader = = shader ) {
return workSurface ;
}
}
/* no surface uses this shader yet, so create a new surface */
{
/* create a new surface in the model for the unique shader */
picoSurface_t * workSurface = PicoNewSurface ( model ) ;
if ( ! workSurface ) {
_pico_printf ( PICO_ERROR , " Could not allocate a new surface! \n " ) ;
return 0 ;
}
/* do surface setup */
PicoSetSurfaceType ( workSurface , PICO_TRIANGLES ) ;
PicoSetSurfaceName ( workSurface , shader - > name ) ;
PicoSetSurfaceShader ( workSurface , shader ) ;
return workSurface ;
}
}
/* _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 )
*/
#if 0
typedef picoIndex_t * picoIndexIter_t ;
typedef struct aseUniqueIndices_s aseUniqueIndices_t ;
struct aseUniqueIndices_s
{
picoIndex_t * data ;
picoIndex_t * last ;
aseFace_t * faces ;
} ;
size_t aseUniqueIndices_size ( aseUniqueIndices_t * self ) {
return self - > last - self - > data ;
}
void aseUniqueIndices_reserve ( aseUniqueIndices_t * self , picoIndex_t size ) {
self - > data = self - > last = ( picoIndex_t * ) _pico_calloc ( size , sizeof ( picoIndex_t ) ) ;
}
void aseUniqueIndices_clear ( aseUniqueIndices_t * self ) {
_pico_free ( self - > data ) ;
}
void aseUniqueIndices_pushBack ( aseUniqueIndices_t * self , picoIndex_t index ) {
* self - > last + + = index ;
}
picoIndex_t aseFaces_getVertexIndex ( aseFace_t * faces , picoIndex_t index ) {
return faces [ index / 3 ] . indices [ index % 3 ] ;
}
picoIndex_t aseFaces_getTexCoordIndex ( aseFace_t * faces , picoIndex_t index ) {
return faces [ index / 3 ] . indices [ ( index % 3 ) + 3 ] ;
}
picoIndex_t aseFaces_getColorIndex ( aseFace_t * faces , picoIndex_t index ) {
return faces [ index / 3 ] . indices [ ( index % 3 ) + 6 ] ;
}
int aseUniqueIndex_equal ( aseFace_t * faces , picoIndex_t index , picoIndex_t other ) {
return aseFaces_getVertexIndex ( faces , index ) = = aseFaces_getVertexIndex ( faces , other )
& & aseFaces_getTexCoordIndex ( faces , index ) = = aseFaces_getTexCoordIndex ( faces , other )
& & aseFaces_getColorIndex ( faces , index ) = = aseFaces_getColorIndex ( faces , other ) ;
}
picoIndex_t aseUniqueIndices_insertUniqueVertex ( aseUniqueIndices_t * self , picoIndex_t index ) {
picoIndexIter_t i = self - > data ;
for ( ; i ! = self - > last ; + + i )
{
picoIndex_t other = ( picoIndex_t ) ( i - self - > data ) ;
if ( aseUniqueIndex_equal ( self - > faces , index , other ) ) {
return other ;
}
}
aseUniqueIndices_pushBack ( self , index ) ;
return ( picoIndex_t ) ( aseUniqueIndices_size ( self ) - 1 ) ;
}
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 ) {
aseFacesIter_t i = faces , end = faces + numFaces ;
aseUniqueIndices_t indices ;
aseUniqueIndices_t remap ;
aseUniqueIndices_reserve ( & indices , numFaces * 3 ) ;
aseUniqueIndices_reserve ( & remap , numFaces * 3 ) ;
indices . faces = faces ;
for ( ; i ! = end ; + + i )
{
/* look up the shader for the material/submaterial pair */
aseSubMaterial_t * subMtl = _ase_get_submaterial_or_default ( materials , ( * i ) . materialId , ( * i ) . subMaterialId ) ;
if ( subMtl = = NULL ) {
return ;
}
{
picoSurface_t * surface = PicoModelFindOrAddSurface ( model , subMtl - > shader ) ;
int j ;
/* we pull the data from the vertex, color and texcoord arrays using the face index data */
for ( j = 0 ; j < 3 ; j + + )
{
picoIndex_t index = ( picoIndex_t ) ( ( ( i - faces ) * 3 ) + j ) ;
picoIndex_t size = ( picoIndex_t ) aseUniqueIndices_size ( & indices ) ;
picoIndex_t unique = aseUniqueIndices_insertUniqueVertex ( & indices , index ) ;
picoIndex_t numVertexes = PicoGetSurfaceNumVertexes ( surface ) ;
picoIndex_t numIndexes = PicoGetSurfaceNumIndexes ( surface ) ;
aseUniqueIndices_pushBack ( & remap , numIndexes ) ;
PicoSetSurfaceIndex ( surface , numIndexes , remap . data [ unique ] ) ;
if ( unique = = size ) {
PicoSetSurfaceXYZ ( surface , numVertexes , vertices [ ( * i ) . indices [ j ] ] . xyz ) ;
PicoSetSurfaceNormal ( surface , numVertexes , vertices [ ( * i ) . indices [ j ] ] . normal ) ;
PicoSetSurfaceST ( surface , 0 , numVertexes , texcoords [ ( * i ) . indices [ j + 3 ] ] . texcoord ) ;
if ( ( * i ) . indices [ j + 6 ] > = 0 ) {
PicoSetSurfaceColor ( surface , 0 , numVertexes , colors [ ( * i ) . indices [ j + 6 ] ] . color ) ;
}
else
{
PicoSetSurfaceColor ( surface , 0 , numVertexes , white ) ;
}
PicoSetSurfaceSmoothingGroup ( surface , numVertexes , ( vertices [ ( * i ) . indices [ j ] ] . id * ( 1 < < 16 ) ) + ( * i ) . smoothingGroup ) ;
}
}
}
}
aseUniqueIndices_clear ( & indices ) ;
aseUniqueIndices_clear ( & remap ) ;
}
# endif
static int VectorCompareExtn ( picoVec3_t n1 , picoVec3_t n2 , float epsilon ) {
int i ;
/* test */
for ( i = 0 ; i < 3 ; i + + )
if ( fabs ( n1 [ i ] - n2 [ i ] ) > epsilon ) {
return - 1 ;
}
return 1 ;
}
# define CrossProductTemp( a,b,c ) ( ( c )[0] = ( a )[1] * ( b )[2] - ( a )[2] * ( b )[1],( c )[1] = ( a )[2] * ( b )[0] - ( a )[0] * ( b )[2],( c )[2] = ( a )[0] * ( b )[1] - ( a )[1] * ( b )[0] )
# define MAX_FACEREFS 64
//maximum number of faces that can share a vert. likely 1-4, but who knows.
typedef struct
{
int count ;
aseFace_t * faces [ MAX_FACEREFS ] ;
} faceref_t ;
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 , int numVerts , int submodel ) {
picoVec3_t accum ;
int index ;
int counter ;
faceref_t * faceref ;
int * normalsC ;
int fc = 0 ;
aseFacesIter_t i = faces , end = faces + numFaces ;
counter = 0 ;
//allocate room for sg optimization
faceref = ( faceref_t * ) malloc ( numVerts * sizeof ( faceref_t ) ) ;
memset ( faceref , 0 , numVerts * sizeof ( faceref_t ) ) ;
//rebuild face normals
for ( i = faces ; i ! = end ; + + i )
{
picoVec3_t a , b , c ;
picoVec3_t v1 , v2 , v3 ;
int j ;
counter + + ;
for ( j = 0 ; j < 3 ; j + + )
{
a [ j ] = vertices [ ( * i ) . indices [ 0 ] ] . xyz [ j ] ;
b [ j ] = vertices [ ( * i ) . indices [ 1 ] ] . xyz [ j ] ;
c [ j ] = vertices [ ( * i ) . indices [ 2 ] ] . xyz [ j ] ;
}
for ( j = 0 ; j < 3 ; j + + )
{
v1 [ j ] = a [ j ] - b [ j ] ;
v2 [ j ] = c [ j ] - b [ j ] ;
}
CrossProductTemp ( v1 , v2 , v3 ) ;
_pico_normalize_vec ( v3 ) ;
( * i ) . facenormal [ 0 ] = v3 [ 0 ] ;
( * i ) . facenormal [ 1 ] = v3 [ 1 ] ;
( * i ) . facenormal [ 2 ] = v3 [ 2 ] ;
//throw this face into the index pools
for ( j = 0 ; j < 3 ; j + + )
{
index = ( * i ) . indices [ j ] ;
if ( faceref [ index ] . count > = MAX_FACEREFS - 1 ) {
}
else
{
faceref [ index ] . faces [ faceref [ index ] . count + + ] = i ;
}
}
}
//if (counter>0) Sys_Printf( "Rebuilding %d Normals\n", counter * 3 );
for ( i = faces ; i ! = end ; + + i )
{
/* look up the shader for the material/submaterial pair */
aseSubMaterial_t * subMtl = _ase_get_submaterial_or_default ( materials , ( * i ) . materialId , ( * i ) . subMaterialId ) ;
if ( subMtl = = NULL ) {
continue ;
}
{
picoVec3_t * xyz [ 3 ] ;
picoVec3_t * a [ 3 ] ;
picoVec3_t * normal [ 3 ] ;
picoVec2_t * st [ 3 ] ;
picoColor_t * color [ 3 ] ;
picoIndex_t smooth [ 3 ] ;
int j , z ;
/* we pull the data from the vertex, color and texcoord arrays using the face index data */
for ( j = 0 ; j < 3 ; j + + )
{
aseFacesIter_t q = faces ;
aseFacesIter_t qend = faces + numFaces ;
xyz [ j ] = & vertices [ ( * i ) . indices [ j ] ] . xyz ;
// Use Face normal
normal [ j ] = & ( * i ) . facenormal ;
//Oooor we can use the smoothing group
//Slow method, but testing
//Find All faces that use this vertex, average their facenormals.
// skip where smoothgroups both equal 0, or don't have any shared bits (x & y)
index = ( * i ) . indices [ j ] ;
accum [ 0 ] = ( * i ) . facenormal [ 0 ] ;
accum [ 1 ] = ( * i ) . facenormal [ 1 ] ;
accum [ 2 ] = ( * i ) . facenormal [ 2 ] ;
counter = 1 ;
z = 0 ;
for ( fc = 0 ; fc < faceref [ index ] . count ; fc + + )
{
z + + ;
q = faceref [ index ] . faces [ fc ] ;
if ( q = = i ) {
continue ; //skip us.
}
// if ( (*q).indices[0]==index || (*q).indices[1]==index || (*q).indices[2]==index)
a [ 0 ] = & vertices [ ( * q ) . indices [ 0 ] ] . xyz ;
a [ 1 ] = & vertices [ ( * q ) . indices [ 1 ] ] . xyz ;
a [ 2 ] = & vertices [ ( * q ) . indices [ 2 ] ] . xyz ;
if ( VectorCompareExtn ( * a [ 0 ] , * xyz [ j ] , 0.01f ) > 0 | |
VectorCompareExtn ( * a [ 1 ] , * xyz [ j ] , 0.01f ) > 0 | |
VectorCompareExtn ( * a [ 2 ] , * xyz [ j ] , 0.01f ) > 0
) {
if ( ( * i ) . smoothingGroup = = 0 & & ( * q ) . smoothingGroup = = 0 ) {
continue ;
}
if ( ( * i ) . smoothingGroup & ( * q ) . smoothingGroup ) {
accum [ 0 ] + = ( * q ) . facenormal [ 0 ] ;
accum [ 1 ] + = ( * q ) . facenormal [ 1 ] ;
accum [ 2 ] + = ( * q ) . facenormal [ 2 ] ;
counter + + ;
}
}
}
_pico_normalize_vec ( accum ) ;
( * i ) . vertexnormal [ j ] [ 0 ] = accum [ 0 ] ;
( * i ) . vertexnormal [ j ] [ 1 ] = accum [ 1 ] ;
( * i ) . vertexnormal [ j ] [ 2 ] = accum [ 2 ] ;
normal [ j ] = & ( * i ) . vertexnormal [ j ] ;
st [ j ] = & texcoords [ ( * i ) . indices [ j + 3 ] ] . texcoord ;
if ( colors ! = NULL & & ( * i ) . indices [ j + 6 ] > = 0 ) {
color [ j ] = & colors [ ( * i ) . indices [ j + 6 ] ] . color ;
}
else
{
color [ j ] = & white ;
}
smooth [ j ] = 0 ; // (vertices[(*i).indices[j]].id * (1 << 16)) + (*i).smoothingGroup; /* don't merge vertices */
}
/* submit the triangle to the model */
PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl - > shader , smooth , submodel ) ;
}
}
free ( faceref ) ;
}
/* _ase_load:
* loads a 3 dsmax ase model file .
*/
static picoModel_t * _ase_load ( PM_PARAMS_LOAD ) {
picoModel_t * model ;
picoParser_t * p ;
char lastNodeName [ 1024 ] ;
aseVertex_t * vertices = NULL ;
aseTexCoord_t * texcoords = NULL ;
aseColor_t * colors = NULL ;
aseFace_t * faces = NULL ;
int numVertices = 0 ;
int numFaces = 0 ;
int numTextureVertices = 0 ;
int numTextureVertexFaces = 0 ;
int numColorVertices = 0 ;
int numColorVertexFaces = 0 ;
int vertexId = 0 ;
int currentVertexFace = 0 ;
int currentVertexIndex = 0 ;
int counter = 0 ;
int submodel = 0 ;
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_submit_triangles ( model , materials , vertices , texcoords , colors , faces , numFaces , numVertices , submodel + + ) ;
_pico_free ( faces ) ;
_pico_free ( vertices ) ;
_pico_free ( texcoords ) ;
_pico_free ( colors ) ;
}
else if ( ! _pico_stricmp ( p - > token , " *mesh_numvertex " ) ) {
if ( ! _pico_parse_int ( p , & numVertices ) ) {
_ase_error_return ( " Missing MESH_NUMVERTEX value " ) ;
}
vertices = _pico_calloc ( numVertices , sizeof ( aseVertex_t ) ) ;
currentVertexIndex = 0 ;
}
else if ( ! _pico_stricmp ( p - > token , " *mesh_numfaces " ) ) {
if ( ! _pico_parse_int ( p , & numFaces ) ) {
_ase_error_return ( " Missing MESH_NUMFACES value " ) ;
}
faces = _pico_calloc ( numFaces , sizeof ( aseFace_t ) ) ;
}
else if ( ! _pico_stricmp ( p - > token , " *mesh_numtvertex " ) ) {
if ( ! _pico_parse_int ( p , & numTextureVertices ) ) {
_ase_error_return ( " Missing MESH_NUMTVERTEX value " ) ;
}
texcoords = _pico_calloc ( numTextureVertices , sizeof ( aseTexCoord_t ) ) ;
}
else if ( ! _pico_stricmp ( p - > token , " *mesh_numtvfaces " ) ) {
if ( ! _pico_parse_int ( p , & numTextureVertexFaces ) ) {
_ase_error_return ( " Missing MESH_NUMTVFACES value " ) ;
}
}
else if ( ! _pico_stricmp ( p - > token , " *mesh_numcvertex " ) ) {
if ( ! _pico_parse_int ( p , & numColorVertices ) ) {
_ase_error_return ( " Missing MESH_NUMCVERTEX value " ) ;
}
colors = _pico_calloc ( numColorVertices , sizeof ( aseColor_t ) ) ;
memset ( colors , 255 , numColorVertices * sizeof ( aseColor_t ) ) ; /* ydnar: force colors to white initially */
}
else if ( ! _pico_stricmp ( p - > token , " *mesh_numcvfaces " ) ) {
if ( ! _pico_parse_int ( p , & numColorVertexFaces ) ) {
_ase_error_return ( " Missing MESH_NUMCVFACES value " ) ;
}
}
/* 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 ;
/* get the material ref (0..n) */
if ( ! _pico_parse_int ( p , & mtlId ) ) {
_ase_error_return ( " Missing material reference ID " ) ;
}
{
int i = 0 ;
/* fix up all of the aseFaceList in the surface to point to the parent material */
/* we've already saved off their subMtl */
for ( ; i < numFaces ; + + i )
{
faces [ i ] . materialId = mtlId ;
}
}
}
/* model mesh vertex */
else if ( ! _pico_stricmp ( p - > token , " *mesh_vertex " ) ) {
int index ;
if ( numVertices = = 0 ) {
_ase_error_return ( " Vertex parse error " ) ;
}
/* 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 , vertices [ index ] . xyz ) ) {
_ase_error_return ( " Vertex parse error " ) ;
}
vertices [ index ] . id = vertexId + + ;
}
else if ( ! _pico_stricmp ( p - > token , " *mesh_facenormal " ) ) {
//Grab the faceindex for the next vertex normals.
if ( numVertices = = 0 ) {
_ase_error_return ( " Vertex parse error (facenormals) " ) ;
}
if ( ! _pico_parse_int ( p , & currentVertexFace ) ) {
_ase_error_return ( " Vertex parse error " ) ;
}
if ( ! _pico_parse_vec ( p , faces [ currentVertexFace ] . facenormal ) ) {
_ase_error_return ( " Vertex parse error " ) ;
}
}
/* model mesh vertex normal */
else if ( ! _pico_stricmp ( p - > token , " *mesh_vertexnormal " ) ) {
int index ;
if ( numVertices = = 0 ) {
_ase_error_return ( " Vertex parse error " ) ;
}
/* get vertex data (orig: index +y -x +z) */
if ( ! _pico_parse_int ( p , & index ) ) {
_ase_error_return ( " Vertex parse error " ) ;
}
//^^ Index is 'wrong' in .ase models. they reference the same vert index with multiple normals..
// I've tried, this is a lost cause. Use the SG's
//
/*
if ( ! _pico_parse_vec ( p , vertices [ counter ] . normal ) )
_ase_error_return ( " Vertex parse error " ) ;
vertices [ counter ] . faceid = index ;
counter + + ;
*/
}
/* model mesh face */
else if ( ! _pico_stricmp ( p - > token , " *mesh_normals " ) ) {
// counter=0; //part of the above vertex normals fix
}
/* model mesh face */
else if ( ! _pico_stricmp ( p - > token , " *mesh_face " ) ) {
picoIndex_t indexes [ 3 ] ;
int index ;
if ( numFaces = = 0 ) {
_ase_error_return ( " Face parse error " ) ;
}
/* 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 " ) ;
}
/* parse to the subMaterial ID */
while ( 1 )
{
if ( ! _pico_parse ( p , 0 ) ) { /* EOL */
break ;
}
if ( ! _pico_stricmp ( p - > token , " *MESH_SMOOTHING " ) ) {
int total = 0 ;
char * point ;
char * start ;
_pico_parse ( p , 0 ) ;
point = p - > token ;
start = point ;
faces [ index ] . smoothingGroup = 0 ;
//Super dodgy comma delimited string parse
while ( * point < ' A ' )
{
if ( * point < = 32 | | * point = = ' , ' ) {
total = atoi ( start ) ;
if ( total ! = 0 ) {
faces [ index ] . smoothingGroup + = 1 < < total ;
}
start = point + 1 ;
}
point + + ;
}
}
if ( ! _pico_stricmp ( p - > token , " *MESH_MTLID " ) ) {
_pico_parse_int ( p , & faces [ index ] . subMaterialId ) ;
}
}
faces [ index ] . materialId = 0 ;
faces [ index ] . indices [ 0 ] = indexes [ 2 ] ;
faces [ index ] . indices [ 1 ] = indexes [ 1 ] ;
faces [ index ] . indices [ 2 ] = indexes [ 0 ] ;
}
/* model texture vertex */
else if ( ! _pico_stricmp ( p - > token , " *mesh_tvert " ) ) {
int index ;
if ( numVertices = = 0 ) {
_ase_error_return ( " Vertex parse error " ) ;
}
/* 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 , & texcoords [ index ] . texcoord [ 0 ] ) ) {
_ase_error_return ( " UV vertex parse error " ) ;
}
/* get uv vertex t */
if ( ! _pico_parse_float ( p , & texcoords [ index ] . texcoord [ 1 ] ) ) {
_ase_error_return ( " UV vertex parse error " ) ;
}
/* ydnar: invert t */
texcoords [ index ] . texcoord [ 1 ] = 1.0f - texcoords [ index ] . texcoord [ 1 ] ;
}
/* ydnar: model mesh texture face */
else if ( ! _pico_stricmp ( p - > token , " *mesh_tface " ) ) {
picoIndex_t indexes [ 3 ] ;
int index ;
if ( numFaces = = 0 ) {
_ase_error_return ( " Texture face parse error " ) ;
}
/* 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 " ) ;
}
faces [ index ] . indices [ 3 ] = indexes [ 2 ] ;
faces [ index ] . indices [ 4 ] = indexes [ 1 ] ;
faces [ index ] . indices [ 5 ] = indexes [ 0 ] ;
}
/* model color vertex */
else if ( ! _pico_stricmp ( p - > token , " *mesh_vertcol " ) ) {
int index ;
float colorInput ;
if ( numVertices = = 0 ) {
_ase_error_return ( " Color Vertex parse error " ) ;
}
/* get color vertex index */
if ( ! _pico_parse_int ( p , & index ) ) {
_ase_error_return ( " Color vertex parse error " ) ;
}
/* get R component */
if ( ! _pico_parse_float ( p , & colorInput ) ) {
_ase_error_return ( " Color vertex parse error " ) ;
}
colors [ index ] . color [ 0 ] = ( picoByte_t ) ( colorInput * 255 ) ;
/* get G component */
if ( ! _pico_parse_float ( p , & colorInput ) ) {
_ase_error_return ( " Color vertex parse error " ) ;
}
colors [ index ] . color [ 1 ] = ( picoByte_t ) ( colorInput * 255 ) ;
/* get B component */
if ( ! _pico_parse_float ( p , & colorInput ) ) {
_ase_error_return ( " Color vertex parse error " ) ;
}
colors [ index ] . color [ 2 ] = ( picoByte_t ) ( colorInput * 255 ) ;
/* leave alpha alone since we don't get any data from the ASE format */
colors [ index ] . color [ 3 ] = 255 ;
/* 27 hack, red as alpha */
colors [ index ] . color [ 3 ] = colors [ index ] . color [ 0 ] ;
colors [ index ] . color [ 0 ] = 255 ;
colors [ index ] . color [ 1 ] = 255 ;
colors [ index ] . color [ 2 ] = 255 ;
}
/* model color face */
else if ( ! _pico_stricmp ( p - > token , " *mesh_cface " ) ) {
picoIndex_t indexes [ 3 ] ;
int index ;
if ( numFaces = = 0 ) {
_ase_error_return ( " Face parse error " ) ;
}
/* 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 " ) ;
}
faces [ index ] . indices [ 6 ] = indexes [ 2 ] ;
faces [ index ] . indices [ 7 ] = indexes [ 1 ] ;
faces [ index ] . indices [ 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 */
_pico_first_token ( materialName ) ;
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 ) ;
/* extract shadername from bitmap path */
if ( mapname ! = NULL ) {
char * p = mapname ;
/* convert to shader-name format */
{
/* unix-style path separators */
char * s = mapname ;
for ( ; * s ! = ' \0 ' ; + + s )
{
if ( * s = = ' \\ ' ) {
* s = ' / ' ;
}
}
}
{
/* remove extension */
char * last_period = strrchr ( p , ' . ' ) ;
if ( last_period ! = NULL ) {
* last_period = ' \0 ' ;
}
}
/* find game root */
for ( ; * p ! = ' \0 ' ; + + p )
{
if ( _pico_strnicmp ( p , " quake " , 5 ) = = 0 | | _pico_strnicmp ( p , " doom " , 4 ) = = 0 ) {
break ;
}
}
/* root-relative */
for ( ; * p ! = ' \0 ' ; + + p )
{
if ( * p = = ' / ' ) {
+ + p ;
break ;
}
}
/* game-relative */
for ( ; * p ! = ' \0 ' ; + + p )
{
if ( * p = = ' / ' ) {
+ + p ;
break ;
}
}
if ( * p ! = ' \0 ' ) {
/* set material name */
PicoSetShaderName ( shader , p ) ;
}
}
/* 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_submit_triangles ( model , materials , vertices , texcoords , colors , faces , numFaces , numVertices , submodel + + ) ;
_pico_free ( faces ) ;
_pico_free ( vertices ) ;
_pico_free ( texcoords ) ;
_pico_free ( colors ) ;
# 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 ) ;
_pico_free_parser ( p ) ;
/* 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 */
} ;