Merge pull request #387 from Mateos81/PicoModelExperiment

PicoModel lib backport from 1.5
This commit is contained in:
Timothee "TTimo" Besset 2016-12-10 11:16:48 -06:00 committed by GitHub
commit bcdcd58467
12 changed files with 1662 additions and 462 deletions

View file

@ -105,6 +105,7 @@ struct picoSurface_s
int numVertexes, maxVertexes; int numVertexes, maxVertexes;
picoVec3_t *xyz; picoVec3_t *xyz;
picoVec3_t *normal; picoVec3_t *normal;
picoIndex_t *smoothingGroup;
int numSTArrays, maxSTArrays; int numSTArrays, maxSTArrays;
picoVec2_t **st; picoVec2_t **st;
@ -216,6 +217,9 @@ const picoModule_t **PicoModuleList( int *numModules );
picoModel_t *PicoLoadModel( char *name, int frameNum ); picoModel_t *PicoLoadModel( char *name, int frameNum );
typedef size_t(*PicoInputStreamReadFunc)(void* inputStream, unsigned char* buffer, size_t length);
picoModel_t* PicoModuleLoadModelStream(const picoModule_t* module, void* inputStream, PicoInputStreamReadFunc inputStreamRead, size_t streamLength, int frameNum);
/* model functions */ /* model functions */
picoModel_t *PicoNewModel( void ); picoModel_t *PicoNewModel( void );
@ -330,12 +334,12 @@ picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCom
picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ); picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index );
/* specialized functions */ /* specialized functions */
int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ); int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color, picoIndex_t smoothingGroup );
void PicoFixSurfaceNormals( picoSurface_t *surface ); void PicoFixSurfaceNormals( picoSurface_t *surface );
int PicoRemapModel( picoModel_t *model, char *remapFile ); int PicoRemapModel( picoModel_t *model, char *remapFile );
void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors, picoShader_t* shader ); void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors, picoShader_t* shader, picoIndex_t* smoothingGroup );
/* end marker */ /* end marker */
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -22,6 +22,35 @@ void lwFreeClip( lwClip *clip ){
if ( clip ) { if ( clip ) {
lwListFree( (void*) clip->ifilter, (ListFreeFunc) lwFreePlugin ); lwListFree( (void*) clip->ifilter, (ListFreeFunc) lwFreePlugin );
lwListFree( (void*) clip->pfilter, (ListFreeFunc) lwFreePlugin ); lwListFree( (void*) clip->pfilter, (ListFreeFunc) lwFreePlugin );
switch ( clip->type ) {
case ID_STIL:
_pico_free( clip->source.still.name );
break;
case ID_ISEQ:
_pico_free( clip->source.seq.prefix );
_pico_free( clip->source.seq.suffix );
break;
case ID_ANIM:
_pico_free( clip->source.anim.name );
_pico_free( clip->source.anim.server );
_pico_free( clip->source.anim.data );
break;
case ID_XREF:
_pico_free( clip->source.xref.string );
break;
case ID_STCC:
_pico_free( clip->source.cycle.name );
break;
default:
break;
}
_pico_free( clip ); _pico_free( clip );
} }
} }

View file

@ -161,35 +161,23 @@ void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ){
* as custom clone size (the string is cropped to fit into mem * as custom clone size (the string is cropped to fit into mem
* if needed). -sea * if needed). -sea
*/ */
char *_pico_clone_alloc( char *str, int size ){ char *_pico_clone_alloc( const char *str ) {
char* cloned; char* cloned;
size_t cloneSize;
/* sanity check */ /* sanity check */
if ( str == NULL ) { if ( str == NULL ) {
return NULL; return NULL;
} }
/* set real size of cloned string */
cloneSize = ( size < 0 ) ? strlen( str ) : size;
/* allocate memory */ /* allocate memory */
cloned = _pico_alloc( cloneSize + 1 ); /* bugfix! */ cloned = _pico_alloc(strlen(str) + 1);
if ( cloned == NULL ) { if ( cloned == NULL ) {
return NULL; return NULL;
} }
/* zero out memory allocated by cloned string */
memset( cloned,0,cloneSize );
/* copy input string to cloned string */ /* copy input string to cloned string */
if ( cloneSize < strlen( str ) ) {
memcpy( cloned,str,cloneSize );
cloned[ cloneSize ] = '\0';
}
else {
strcpy(cloned, str); strcpy(cloned, str);
}
/* return ptr to cloned string */ /* return ptr to cloned string */
return cloned; return cloned;
} }
@ -275,6 +263,19 @@ void _pico_printf( int level, const char *format, ... ){
_pico_ptr_print( level,str ); _pico_ptr_print( level,str );
} }
/* _pico_first_token:
* trims everything after the first whitespace-delimited token
*/
void _pico_first_token( char *str ) {
if ( !str || ! * str ) {
return;
}
while (*str && !isspace(*str))
*str++;
*str = '\0';
}
/* _pico_strltrim: /* _pico_strltrim:
* left trims the given string -sea * left trims the given string -sea
*/ */
@ -542,7 +543,7 @@ float _pico_big_float( float src ){
* case-insensitive strstr. -sea * case-insensitive strstr. -sea
*/ */
char *_pico_stristr( char *str, const char *substr ){ char *_pico_stristr( char *str, const char *substr ){
const int sublen = strlen( substr ); const size_t sublen = strlen( substr );
while ( *str ) while ( *str )
{ {
if ( !_pico_strnicmp( str,substr,sublen ) ) { if ( !_pico_strnicmp( str,substr,sublen ) ) {
@ -604,24 +605,24 @@ int _pico_nofname( const char *path, char *dest, int destSize ){
* returns ptr to filename portion in given path or an empty * returns ptr to filename portion in given path or an empty
* string otherwise. given 'path' is not altered. -sea * string otherwise. given 'path' is not altered. -sea
*/ */
char *_pico_nopath( const char *path ){ const char *_pico_nopath( const char *path ){
char *src; const char *src;
src = (char *)path + ( strlen( path ) - 1 );
if ( path == NULL ) { if ( path == NULL ) {
return (char *)""; return "";
} }
if ( !strchr( (char *)path,'/' ) && !strchr( (char *)path,'\\' ) ) { if ( !strchr( path,'/' ) && !strchr( path,'\\' ) ) {
return ( (char *)path ); return ( path );
} }
src = path + ( strlen( path ) - 1 );
while ( ( src-- ) != path ) while ( ( src-- ) != path )
{ {
if ( *src == '/' || *src == '\\' ) { if ( *src == '/' || *src == '\\' ) {
return ( ++src ); return ( ++src );
} }
} }
return (char *)""; return "";
} }
/* _pico_setfext: /* _pico_setfext:

View file

@ -116,7 +116,7 @@ extern void ( *_pico_ptr_print )( int, const char* );
void *_pico_alloc( size_t size ); void *_pico_alloc( size_t size );
void *_pico_calloc( size_t num, size_t size ); void *_pico_calloc( size_t num, size_t size );
void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ); void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize );
char *_pico_clone_alloc( char *str, int size ); char *_pico_clone_alloc( const char *str );
void _pico_free( void *ptr ); void _pico_free( void *ptr );
/* files */ /* files */
@ -124,6 +124,7 @@ void _pico_load_file( char *name, unsigned char **buffer, int *bufSiz
void _pico_free_file( void *buffer ); void _pico_free_file( void *buffer );
/* strings */ /* strings */
void _pico_first_token(char *str);
char *_pico_strltrim( char *str ); char *_pico_strltrim( char *str );
char *_pico_strrtrim( char *str ); char *_pico_strrtrim( char *str );
int _pico_strchcount( char *str, int ch ); int _pico_strchcount( char *str, int ch );

View file

@ -143,7 +143,46 @@ void PicoSetPrintFunc( void ( *func )( int, const char* ) ){
} }
} }
picoModel_t *PicoModuleLoadModel( const picoModule_t* pm, char* fileName, picoByte_t* buffer, int bufSize, int frameNum ){
char *modelFileName, *remapFileName;
/* see whether this module can load the model file or not */
if ( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK ) {
/* use loader provided by module to read the model data */
picoModel_t* model = pm->load( fileName, frameNum, buffer, bufSize );
if ( model == NULL ) {
_pico_free_file( buffer );
return NULL;
}
/* assign pointer to file format module */
model->module = pm;
/* get model file name */
modelFileName = PicoGetModelFileName( model );
/* apply model remappings from <model>.remap */
if ( strlen( modelFileName ) ) {
/* alloc copy of model file name */
remapFileName = _pico_alloc( strlen( modelFileName ) + 20 );
if ( remapFileName != NULL ) {
/* copy model file name and change extension */
strcpy( remapFileName, modelFileName );
_pico_setfext( remapFileName, "remap" );
/* try to remap model; we don't handle the result */
PicoRemapModel( model, remapFileName );
/* free the remap file name string */
_pico_free( remapFileName );
}
}
return model;
}
return NULL;
}
/* /*
PicoLoadModel() PicoLoadModel()
@ -155,7 +194,6 @@ picoModel_t *PicoLoadModel( char *fileName, int frameNum ){
picoModel_t *model; picoModel_t *model;
picoByte_t *buffer; picoByte_t *buffer;
int bufSize; int bufSize;
char *modelFileName, *remapFileName;
/* init */ /* init */
@ -194,38 +232,8 @@ picoModel_t *PicoLoadModel( char *fileName, int frameNum ){
continue; continue;
} }
/* see whether this module can load the model file or not */ model = PicoModuleLoadModel( pm, fileName, buffer, bufSize, frameNum );
if ( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK ) { if ( model != NULL ) {
/* use loader provided by module to read the model data */
model = pm->load( fileName, frameNum, buffer, bufSize );
if ( model == NULL ) {
_pico_free_file( buffer );
return NULL;
}
/* assign pointer to file format module */
model->module = pm;
/* get model file name */
modelFileName = PicoGetModelFileName( model );
/* apply model remappings from <model>.remap */
if ( strlen( modelFileName ) ) {
/* alloc copy of model file name */
remapFileName = _pico_alloc( strlen( modelFileName ) + 20 );
if ( remapFileName != NULL ) {
/* copy model file name and change extension */
strcpy( remapFileName, modelFileName );
_pico_setfext( remapFileName, "remap" );
/* try to remap model; we don't handle the result */
PicoRemapModel( model, remapFileName );
/* free the remap file name string */
_pico_free( remapFileName );
}
}
/* model was loaded, so break out of loop */ /* model was loaded, so break out of loop */
break; break;
} }
@ -236,7 +244,50 @@ picoModel_t *PicoLoadModel( char *fileName, int frameNum ){
_pico_free_file( buffer ); _pico_free_file( buffer );
} }
/* return */ return model;
}
/*
FIXME: From 1.5; Unused yet
*/
picoModel_t *PicoModuleLoadModelStream( const picoModule_t* module, void* inputStream, PicoInputStreamReadFunc inputStreamRead, size_t streamLength, int frameNum ) {
picoModel_t *model;
picoByte_t *buffer;
int bufSize;
/* init */
model = NULL;
if ( inputStream == NULL ) {
_pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStream == NULL)" );
return NULL;
}
if ( inputStreamRead == NULL ) {
_pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStreamRead == NULL) ");
return NULL;
}
buffer = _pico_alloc( streamLength + 1 );
bufSize = (int)inputStreamRead( inputStream, buffer, streamLength );
buffer[ bufSize ] = '\0';
{
// dummy filename
char fileName[128];
fileName[0] = '.';
strncpy( fileName + 1, module->defaultExts[ 0 ], 126 );
fileName[127] = '\0';
model = PicoModuleLoadModel( module, fileName, buffer, bufSize, frameNum );
}
/* free memory used by file buffer */
if ( model != 0 ) {
_pico_free( buffer );
}
return model; return model;
} }
@ -274,7 +325,6 @@ picoModel_t *PicoNewModel( void ){
} }
/* /*
PicoFreeModel() PicoFreeModel()
frees a model and all associated data frees a model and all associated data
@ -283,7 +333,6 @@ picoModel_t *PicoNewModel( void ){
void PicoFreeModel( picoModel_t *model ){ void PicoFreeModel( picoModel_t *model ){
int i; int i;
/* sanity check */ /* sanity check */
if ( model == NULL ) { if ( model == NULL ) {
return; return;
@ -294,6 +343,10 @@ void PicoFreeModel( picoModel_t *model ){
_pico_free( model->name ); _pico_free( model->name );
} }
if ( model->fileName ) {
_pico_free( model->fileName );
}
/* free shaders */ /* free shaders */
for ( i = 0; i < model->numShaders; i++ ) for ( i = 0; i < model->numShaders; i++ )
PicoFreeShader( model->shader[ i ] ); PicoFreeShader( model->shader[ i ] );
@ -309,7 +362,6 @@ void PicoFreeModel( picoModel_t *model ){
} }
/* /*
PicoAdjustModel() PicoAdjustModel()
adjusts a models's memory allocations to handle the requested sizes. adjusts a models's memory allocations to handle the requested sizes.
@ -364,7 +416,6 @@ int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ){
} }
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
shaders shaders
---------------------------------------------------------------------------- */ ---------------------------------------------------------------------------- */
@ -377,7 +428,6 @@ int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ){
picoShader_t *PicoNewShader( picoModel_t *model ){ picoShader_t *PicoNewShader( picoModel_t *model ){
picoShader_t *shader; picoShader_t *shader;
/* allocate and clear */ /* allocate and clear */
shader = _pico_alloc( sizeof( picoShader_t ) ); shader = _pico_alloc( sizeof( picoShader_t ) );
if ( shader == NULL ) { if ( shader == NULL ) {
@ -410,7 +460,6 @@ picoShader_t *PicoNewShader( picoModel_t *model ){
} }
/* /*
PicoFreeShader() PicoFreeShader()
frees a shader and all associated data -sea frees a shader and all associated data -sea
@ -435,7 +484,6 @@ void PicoFreeShader( picoShader_t *shader ){
} }
/* /*
PicoFindShader() PicoFindShader()
finds a named shader in a model finds a named shader in a model
@ -444,7 +492,6 @@ void PicoFreeShader( picoShader_t *shader ){
picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ){ picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ){
int i; int i;
/* sanity checks */ /* sanity checks */
if ( model == NULL || name == NULL ) { /* sea: null name fix */ if ( model == NULL || name == NULL ) { /* sea: null name fix */
return NULL; return NULL;
@ -475,7 +522,6 @@ picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive
} }
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
surfaces surfaces
---------------------------------------------------------------------------- */ ---------------------------------------------------------------------------- */
@ -518,7 +564,6 @@ picoSurface_t *PicoNewSurface( picoModel_t *model ){
} }
/* /*
PicoFreeSurface() PicoFreeSurface()
frees a surface and all associated data frees a surface and all associated data
@ -526,7 +571,6 @@ picoSurface_t *PicoNewSurface( picoModel_t *model ){
void PicoFreeSurface( picoSurface_t *surface ){ void PicoFreeSurface( picoSurface_t *surface ){
int i; int i;
/* dummy check */ /* dummy check */
if ( surface == NULL ) { if ( surface == NULL ) {
return; return;
@ -535,9 +579,14 @@ void PicoFreeSurface( picoSurface_t *surface ){
/* free bits */ /* free bits */
_pico_free( surface->xyz ); _pico_free( surface->xyz );
_pico_free( surface->normal ); _pico_free( surface->normal );
_pico_free( surface->smoothingGroup );
_pico_free( surface->index ); _pico_free( surface->index );
_pico_free( surface->faceNormal ); _pico_free( surface->faceNormal );
if ( surface->name ) {
_pico_free( surface->name );
}
/* free arrays */ /* free arrays */
for ( i = 0; i < surface->numSTArrays; i++ ) for ( i = 0; i < surface->numSTArrays; i++ )
_pico_free( surface->st[ i ] ); _pico_free( surface->st[ i ] );
@ -551,7 +600,6 @@ void PicoFreeSurface( picoSurface_t *surface ){
} }
/* /*
PicoAdjustSurface() PicoAdjustSurface()
adjusts a surface's memory allocations to handle the requested sizes. adjusts a surface's memory allocations to handle the requested sizes.
@ -561,7 +609,6 @@ void PicoFreeSurface( picoSurface_t *surface ){
int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ){ int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ){
int i; int i;
/* dummy check */ /* dummy check */
if ( surface == NULL ) { if ( surface == NULL ) {
return 0; return 0;
@ -591,6 +638,9 @@ int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays,
if ( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) ) { if ( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) ) {
return 0; return 0;
} }
if ( !_pico_realloc( (void *) &surface->smoothingGroup, surface->numVertexes * sizeof( *surface->smoothingGroup ), surface->maxVertexes * sizeof( *surface->smoothingGroup ) ) ) {
return 0;
}
for ( i = 0; i < surface->numSTArrays; i++ ) for ( i = 0; i < surface->numSTArrays; i++ )
if ( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) ) { if ( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) ) {
return 0; return 0;
@ -720,7 +770,7 @@ void PicoSetModelName( picoModel_t *model, char *name ){
_pico_free( model->name ); _pico_free( model->name );
} }
model->name = _pico_clone_alloc( name,-1 ); model->name = _pico_clone_alloc( name );
} }
@ -733,7 +783,7 @@ void PicoSetModelFileName( picoModel_t *model, char *fileName ){
_pico_free( model->fileName ); _pico_free( model->fileName );
} }
model->fileName = _pico_clone_alloc( fileName,-1 ); model->fileName = _pico_clone_alloc( fileName );
} }
@ -773,7 +823,7 @@ void PicoSetShaderName( picoShader_t *shader, char *name ){
_pico_free( shader->name ); _pico_free( shader->name );
} }
shader->name = _pico_clone_alloc( name,-1 ); shader->name = _pico_clone_alloc( name );
} }
@ -786,7 +836,7 @@ void PicoSetShaderMapName( picoShader_t *shader, char *mapName ){
_pico_free( shader->mapName ); _pico_free( shader->mapName );
} }
shader->mapName = _pico_clone_alloc( mapName,-1 ); shader->mapName = _pico_clone_alloc( mapName );
} }
@ -887,7 +937,7 @@ void PicoSetSurfaceName( picoSurface_t *surface, char *name ){
_pico_free( surface->name ); _pico_free( surface->name );
} }
surface->name = _pico_clone_alloc( name,-1 ); surface->name = _pico_clone_alloc( name );
} }
@ -990,6 +1040,15 @@ void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ){
_pico_copy_vec( normal, surface->faceNormal[ num ] ); _pico_copy_vec( normal, surface->faceNormal[ num ] );
} }
void PicoSetSurfaceSmoothingGroup( picoSurface_t *surface, int num, picoIndex_t smoothingGroup ){
if ( num < 0 ) {
return;
}
if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
return;
}
surface->smoothingGroup[ num ] = smoothingGroup;
}
void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ){ void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ){
if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) { if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
@ -1335,6 +1394,12 @@ picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ){
return surface->faceNormal[ num ]; return surface->faceNormal[ num ];
} }
picoIndex_t PicoGetSurfaceSmoothingGroup( picoSurface_t *surface, int num ){
if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
return -1;
}
return surface->smoothingGroup[ num ];
}
int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ){ int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ){
if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) { if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
@ -1535,7 +1600,7 @@ picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexComb
fixme: needs non-naive algorithm fixme: needs non-naive algorithm
*/ */
int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ){ int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color, picoIndex_t smoothingGroup ){
int i, j; int i, j;
@ -1557,6 +1622,11 @@ int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t
continue; continue;
} }
/* check normal */
if ( surface->smoothingGroup[ i ] != smoothingGroup ) {
continue;
}
/* check st */ /* check st */
if ( numSTs > 0 && st != NULL ) { if ( numSTs > 0 && st != NULL ) {
for ( j = 0; j < numSTs; j++ ) for ( j = 0; j < numSTs; j++ )
@ -1598,126 +1668,420 @@ int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t
fixes broken normals (certain formats bork normals) fixes broken normals (certain formats bork normals)
*/ */
#define MAX_NORMAL_VOTES 128 //#define MAX_NORMAL_VOTES 128
#define EQUAL_NORMAL_EPSILON 0.01 //#define EQUAL_NORMAL_EPSILON 0.01
#define BAD_NORMAL_EPSILON 0.5 //#define BAD_NORMAL_EPSILON 0.5
//
//void PicoFixSurfaceNormals( picoSurface_t *surface ){
// int i, j, k, a, b, c, numVotes, faceIndex;
// picoVec3_t votes[ MAX_NORMAL_VOTES ];
// picoVec3_t *normals, diff;
// picoVec4_t plane;
//
//
// /* dummy check */
// if ( surface == NULL || surface->numVertexes == 0 ) {
// return;
// }
//
// /* fixme: handle other surface types */
// if ( surface->type != PICO_TRIANGLES ) {
// return;
// }
//
// /* allocate normal storage */
// normals = _pico_alloc( surface->numVertexes * sizeof( *normals ) );
// if ( normals == NULL ) {
// _pico_printf( PICO_ERROR, "PicoFixSurfaceNormals: Unable to allocate memory for temporary normal storage" );
// return;
// }
//
// /* zero it out */
// memset( normals, 0, surface->numVertexes * sizeof( *normals ) );
//
// /* walk vertex list */
// for ( i = 0; i < surface->numVertexes; i++ )
// {
// /* zero out votes */
// numVotes = 0;
//
// /* find all the triangles that reference this vertex */
// for ( j = 0, faceIndex = 0; j < surface->numIndexes; j += 3, faceIndex++ )
// {
// /* get triangle */
// a = surface->index[ j ];
// b = surface->index[ j + 1 ];
// c = surface->index[ j + 2 ];
//
// /* ignore degenerate triangles */
// if ( a == b || b == c || c == a ) {
// continue;
// }
//
// /* ignore indexes out of range */
// if ( a < 0 || a >= surface->numVertexes ||
// b < 0 || b >= surface->numVertexes ||
// c < 0 || c >= surface->numVertexes ) {
// continue;
// }
//
// /* test triangle */
// if ( a == i || b == i || c == i ) {
// /* if this surface has face normals */
// if ( surface->numFaceNormals && faceIndex < surface->numFaceNormals ) {
// _pico_copy_vec( surface->faceNormal[ faceIndex ], plane );
// if ( plane[ 0 ] == 0.f && plane[ 1 ] == 0.f && plane[ 2 ] == 0.f ) {
// /* if null normal, make plane from the 3 points */
// if ( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) {
// continue;
// }
// }
// }
// /* make a plane from the 3 points */
// else if ( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) {
// continue;
// }
//
// /* see if this normal has already been voted */
// for ( k = 0; k < numVotes; k++ )
// {
// _pico_subtract_vec( plane, votes[ k ], diff );
// if ( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
// fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
// fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON ) {
// break;
// }
// }
//
// /* add a new vote? */
// if ( k == numVotes && numVotes < MAX_NORMAL_VOTES ) {
// _pico_copy_vec( plane, votes[ numVotes ] );
// numVotes++;
// }
// }
// }
//
// /* tally votes */
// if ( numVotes > 0 ) {
// /* create average normal */
// _pico_zero_vec( normals[ i ] );
// for ( k = 0; k < numVotes; k++ )
// _pico_add_vec( normals[ i ], votes[ k ], normals[ i ] );
//
// /* normalize it */
// if ( _pico_normalize_vec( normals[ i ] ) ) {
// /* test against actual normal */
// if ( fabs( _pico_dot_vec( normals[ i ], surface->normal[ i ] ) - 1 ) > BAD_NORMAL_EPSILON ) {
// //% printf( "Normal %8d: (%f %f %f) -> (%f %f %f)\n", i,
// //% surface->normal[ i ][ 0 ], surface->normal[ i ][ 1 ], surface->normal[ i ][ 2 ],
// //% normals[ i ][ 0 ], normals[ i ][ 1 ], normals[ i ][ 2 ] );
// _pico_copy_vec( normals[ i ], surface->normal[ i ] );
// }
// }
// }
// }
//
// /* free normal storage */
// _pico_free( normals );
//}
typedef struct _IndexArray IndexArray;
struct _IndexArray
{
picoIndex_t* data;
picoIndex_t* last;
};
void indexarray_push_back(IndexArray* self, picoIndex_t value) {
*self->last++ = value;
}
size_t indexarray_size(IndexArray* self) {
return self->last - self->data;
}
void indexarray_reserve(IndexArray* self, size_t size) {
self->data = self->last = _pico_calloc(size, sizeof(picoIndex_t));
}
void indexarray_clear(IndexArray* self) {
_pico_free(self->data);
}
typedef struct _BinaryTreeNode BinaryTreeNode;
struct _BinaryTreeNode
{
picoIndex_t left;
picoIndex_t right;
};
typedef struct _BinaryTree BinaryTree;
struct _BinaryTree
{
BinaryTreeNode* data;
BinaryTreeNode* last;
};
void binarytree_extend(BinaryTree* self) {
self->last->left = 0;
self->last->right = 0;
++self->last;
}
size_t binarytree_size(BinaryTree* self) {
return self->last - self->data;
}
void binarytree_reserve(BinaryTree* self, size_t size) {
self->data = self->last = _pico_calloc(size, sizeof(BinaryTreeNode));
}
void binarytree_clear(BinaryTree* self) {
_pico_free(self->data);
}
typedef int(*LessFunc)(void*, picoIndex_t, picoIndex_t);
typedef struct _UniqueIndices UniqueIndices;
struct _UniqueIndices
{
BinaryTree tree;
IndexArray indices;
LessFunc lessFunc;
void* lessData;
};
size_t UniqueIndices_size(UniqueIndices* self) {
return binarytree_size(&self->tree);
}
void UniqueIndices_reserve(UniqueIndices* self, size_t size) {
binarytree_reserve(&self->tree, size);
indexarray_reserve(&self->indices, size);
}
void UniqueIndices_init(UniqueIndices* self, LessFunc lessFunc, void* lessData) {
self->lessFunc = lessFunc;
self->lessData = lessData;
}
void UniqueIndices_destroy(UniqueIndices* self) {
binarytree_clear(&self->tree);
indexarray_clear(&self->indices);
}
picoIndex_t UniqueIndices_find_or_insert(UniqueIndices* self, picoIndex_t value) {
picoIndex_t index = 0;
for (;; )
{
if (self->lessFunc(self->lessData, value, self->indices.data[index])) {
BinaryTreeNode* node = self->tree.data + index;
if (node->left != 0) {
index = node->left;
continue;
}
else
{
node->left = (picoIndex_t)binarytree_size(&self->tree);
binarytree_extend(&self->tree);
indexarray_push_back(&self->indices, value);
return node->left;
}
}
if (self->lessFunc(self->lessData, self->indices.data[index], value)) {
BinaryTreeNode* node = self->tree.data + index;
if (node->right != 0) {
index = node->right;
continue;
}
else
{
node->right = (picoIndex_t)binarytree_size(&self->tree);
binarytree_extend(&self->tree);
indexarray_push_back(&self->indices, value);
return node->right;
}
}
return index;
}
}
picoIndex_t UniqueIndices_insert(UniqueIndices* self, picoIndex_t value) {
if (self->tree.data == self->tree.last) {
binarytree_extend(&self->tree);
indexarray_push_back(&self->indices, value);
return 0;
}
else
{
return UniqueIndices_find_or_insert(self, value);
}
}
typedef struct picoSmoothVertices_s picoSmoothVertices_t;
struct picoSmoothVertices_s
{
picoVec3_t* xyz;
picoIndex_t* smoothingGroups;
};
int lessSmoothVertex(void* data, picoIndex_t first, picoIndex_t second) {
picoSmoothVertices_t* smoothVertices = data;
if (smoothVertices->xyz[first][0] != smoothVertices->xyz[second][0]) {
return smoothVertices->xyz[first][0] < smoothVertices->xyz[second][0];
}
if (smoothVertices->xyz[first][1] != smoothVertices->xyz[second][1]) {
return smoothVertices->xyz[first][1] < smoothVertices->xyz[second][1];
}
if (smoothVertices->xyz[first][2] != smoothVertices->xyz[second][2]) {
return smoothVertices->xyz[first][2] < smoothVertices->xyz[second][2];
}
if (smoothVertices->smoothingGroups[first] != smoothVertices->smoothingGroups[second]) {
return smoothVertices->smoothingGroups[first] < smoothVertices->smoothingGroups[second];
}
return 0;
}
void _pico_vertices_combine_shared_normals(picoVec3_t* xyz, picoIndex_t* smoothingGroups, picoVec3_t* normals, picoIndex_t numVertices) {
UniqueIndices vertices;
IndexArray indices;
picoSmoothVertices_t smoothVertices = { xyz, smoothingGroups };
UniqueIndices_init(&vertices, lessSmoothVertex, &smoothVertices);
UniqueIndices_reserve(&vertices, numVertices);
indexarray_reserve(&indices, numVertices);
{
picoIndex_t i = 0;
for (; i < numVertices; ++i)
{
size_t size = UniqueIndices_size(&vertices);
picoIndex_t index = UniqueIndices_insert(&vertices, i);
if ((size_t)index != size) {
float* normal = normals[vertices.indices.data[index]];
_pico_add_vec(normal, normals[i], normal);
}
indexarray_push_back(&indices, index);
}
}
{
picoIndex_t maxIndex = 0;
picoIndex_t* i = indices.data;
for (; i != indices.last; ++i)
{
if (*i <= maxIndex) {
_pico_copy_vec(normals[vertices.indices.data[*i]], normals[i - indices.data]);
}
else
{
maxIndex = *i;
}
}
}
UniqueIndices_destroy(&vertices);
indexarray_clear(&indices);
}
typedef picoVec3_t* picoNormalIter_t;
typedef picoIndex_t* picoIndexIter_t;
#define THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL 1
void _pico_triangles_generate_weighted_normals(picoIndexIter_t first, picoIndexIter_t end, picoVec3_t* xyz, picoVec3_t* normals) {
for (; first != end; first += 3)
{
#if (THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL)
picoVec3_t weightedNormal;
{
float* a = xyz[*(first + 0)];
float* b = xyz[*(first + 1)];
float* c = xyz[*(first + 2)];
picoVec3_t ba, ca;
_pico_subtract_vec(b, a, ba);
_pico_subtract_vec(c, a, ca);
_pico_cross_vec(ca, ba, weightedNormal);
}
#endif
{
int j = 0;
for (; j < 3; ++j)
{
float* normal = normals[*(first + j)];
#if ( !THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL )
picoVec3_t weightedNormal;
{
float* a = xyz[*(first + ((j + 0) % 3))];
float* b = xyz[*(first + ((j + 1) % 3))];
float* c = xyz[*(first + ((j + 2) % 3))];
picoVec3_t ba, ca;
_pico_subtract_vec(b, a, ba);
_pico_subtract_vec(c, a, ca);
_pico_cross_vec(ca, ba, weightedNormal);
}
#endif
_pico_add_vec(weightedNormal, normal, normal);
}
}
}
}
void _pico_normals_zero(picoNormalIter_t first, picoNormalIter_t last) {
for (; first != last; ++first)
{
_pico_zero_vec(*first);
}
}
void _pico_normals_normalize(picoNormalIter_t first, picoNormalIter_t last) {
for (; first != last; ++first)
{
_pico_normalize_vec(*first);
}
}
double _pico_length_vec(picoVec3_t vec) {
return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
}
#define NORMAL_UNIT_LENGTH_EPSILON 0.01
#define FLOAT_EQUAL_EPSILON( f, other, epsilon ) ( fabs( f - other ) < epsilon )
int _pico_normal_is_unit_length(picoVec3_t normal) {
return FLOAT_EQUAL_EPSILON(_pico_length_vec(normal), 1.0, NORMAL_UNIT_LENGTH_EPSILON);
}
int _pico_normal_within_tolerance(picoVec3_t normal, picoVec3_t other) {
return _pico_dot_vec(normal, other) > 0.0f;
}
void _pico_normals_assign_generated_normals(picoNormalIter_t first, picoNormalIter_t last, picoNormalIter_t generated) {
for (; first != last; ++first, ++generated)
{
if (!_pico_normal_is_unit_length(*first) || !_pico_normal_within_tolerance(*first, *generated)) {
_pico_copy_vec(*generated, *first);
}
}
}
void PicoFixSurfaceNormals(picoSurface_t* surface) { void PicoFixSurfaceNormals(picoSurface_t* surface) {
int i, j, k, a, b, c, numVotes, faceIndex; picoVec3_t* normals = (picoVec3_t*)_pico_calloc(surface->numVertexes, sizeof(picoVec3_t));
picoVec3_t votes[ MAX_NORMAL_VOTES ];
picoVec3_t *normals, diff;
picoVec4_t plane;
_pico_normals_zero(normals, normals + surface->numVertexes);
/* dummy check */ _pico_triangles_generate_weighted_normals(surface->index, surface->index + surface->numIndexes, surface->xyz, normals);
if ( surface == NULL || surface->numVertexes == 0 ) { _pico_vertices_combine_shared_normals(surface->xyz, surface->smoothingGroup, normals, surface->numVertexes);
return;
}
/* fixme: handle other surface types */ _pico_normals_normalize(normals, normals + surface->numVertexes);
if ( surface->type != PICO_TRIANGLES ) {
return;
}
/* allocate normal storage */ _pico_normals_assign_generated_normals(surface->normal, surface->normal + surface->numVertexes, normals);
normals = _pico_alloc( surface->numVertexes * sizeof( *normals ) );
if ( normals == NULL ) {
_pico_printf( PICO_ERROR, "PicoFixSurfaceNormals: Unable to allocate memory for temporary normal storage" );
return;
}
/* zero it out */
memset( normals, 0, surface->numVertexes * sizeof( *normals ) );
/* walk vertex list */
for ( i = 0; i < surface->numVertexes; i++ )
{
/* zero out votes */
numVotes = 0;
/* find all the triangles that reference this vertex */
for ( j = 0, faceIndex = 0; j < surface->numIndexes; j += 3, faceIndex++ )
{
/* get triangle */
a = surface->index[ j ];
b = surface->index[ j + 1 ];
c = surface->index[ j + 2 ];
/* ignore degenerate triangles */
if ( a == b || b == c || c == a ) {
continue;
}
/* ignore indexes out of range */
if ( a < 0 || a >= surface->numVertexes ||
b < 0 || b >= surface->numVertexes ||
c < 0 || c >= surface->numVertexes ) {
continue;
}
/* test triangle */
if ( a == i || b == i || c == i ) {
/* if this surface has face normals */
if ( surface->numFaceNormals && faceIndex < surface->numFaceNormals ) {
_pico_copy_vec( surface->faceNormal[ faceIndex ], plane );
if ( plane[ 0 ] == 0.f && plane[ 1 ] == 0.f && plane[ 2 ] == 0.f ) {
/* if null normal, make plane from the 3 points */
if ( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) {
continue;
}
}
}
/* make a plane from the 3 points */
else if ( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) {
continue;
}
/* see if this normal has already been voted */
for ( k = 0; k < numVotes; k++ )
{
_pico_subtract_vec( plane, votes[ k ], diff );
if ( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON ) {
break;
}
}
/* add a new vote? */
if ( k == numVotes && numVotes < MAX_NORMAL_VOTES ) {
_pico_copy_vec( plane, votes[ numVotes ] );
numVotes++;
}
}
}
/* tally votes */
if ( numVotes > 0 ) {
/* create average normal */
_pico_zero_vec( normals[ i ] );
for ( k = 0; k < numVotes; k++ )
_pico_add_vec( normals[ i ], votes[ k ], normals[ i ] );
/* normalize it */
if ( _pico_normalize_vec( normals[ i ] ) ) {
/* test against actual normal */
if ( fabs( _pico_dot_vec( normals[ i ], surface->normal[ i ] ) - 1 ) > BAD_NORMAL_EPSILON ) {
//% printf( "Normal %8d: (%f %f %f) -> (%f %f %f)\n", i,
//% surface->normal[ i ][ 0 ], surface->normal[ i ][ 1 ], surface->normal[ i ][ 2 ],
//% normals[ i ][ 0 ], normals[ i ][ 1 ], normals[ i ][ 2 ] );
_pico_copy_vec( normals[ i ], surface->normal[ i ] );
}
}
}
}
/* free normal storage */
_pico_free(normals); _pico_free(normals);
} }
/* /*
PicoRemapModel() - sea PicoRemapModel() - sea
remaps model material/etc. information using the remappings remaps model material/etc. information using the remappings
@ -1791,7 +2155,6 @@ int PicoRemapModel( picoModel_t *model, char *remapFile ){
picoShader_t *shader; picoShader_t *shader;
char *materialName; char *materialName;
/* get material name */ /* get material name */
if ( _pico_parse( p, 1 ) == NULL ) { if ( _pico_parse( p, 1 ) == NULL ) {
break; break;
@ -1799,7 +2162,7 @@ int PicoRemapModel( picoModel_t *model, char *remapFile ){
if ( !strlen( p->token ) ) { if ( !strlen( p->token ) ) {
continue; continue;
} }
materialName = _pico_clone_alloc( p->token,-1 ); materialName = _pico_clone_alloc( p->token );
if ( materialName == NULL ) { if ( materialName == NULL ) {
_prm_error_return; _prm_error_return;
} }
@ -1857,7 +2220,7 @@ int PicoRemapModel( picoModel_t *model, char *remapFile ){
} }
/* temporary copy of material name */ /* temporary copy of material name */
tempMaterialName = _pico_clone_alloc( p->token,-1 ); tempMaterialName = _pico_clone_alloc( p->token );
if ( tempMaterialName == NULL ) { if ( tempMaterialName == NULL ) {
_prm_error_return; _prm_error_return;
} }
@ -2002,7 +2365,7 @@ int PicoRemapModel( picoModel_t *model, char *remapFile ){
void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals,
int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors, int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors,
picoShader_t* shader ){ picoShader_t* shader, picoIndex_t* smoothingGroup ){
int i, j; int i, j;
int vertDataIndex; int vertDataIndex;
picoSurface_t* workSurface = NULL; picoSurface_t* workSurface = NULL;
@ -2038,7 +2401,7 @@ void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t**
int newVertIndex = PicoGetSurfaceNumIndexes( workSurface ); int newVertIndex = PicoGetSurfaceNumIndexes( workSurface );
/* get the index of the vertex that we're going to store at newVertIndex */ /* get the index of the vertex that we're going to store at newVertIndex */
vertDataIndex = PicoFindSurfaceVertexNum( workSurface, *xyz[i], *normals[i], numSTs, st[i], numColors, colors[i] ); vertDataIndex = PicoFindSurfaceVertexNum( workSurface, *xyz[i], *normals[i], numSTs, st[i], numColors, colors[i], smoothingGroup[i] );
/* the vertex wasn't found, so create a new vertex in the pool from the data we have */ /* the vertex wasn't found, so create a new vertex in the pool from the data we have */
if ( vertDataIndex == -1 ) { if ( vertDataIndex == -1 ) {
@ -2058,6 +2421,8 @@ void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t**
{ {
PicoSetSurfaceST( workSurface, j, vertDataIndex, st[i][j] ); PicoSetSurfaceST( workSurface, j, vertDataIndex, st[i][j] );
} }
PicoSetSurfaceSmoothingGroup( workSurface, vertDataIndex, smoothingGroup[ i ] );
} }
/* add this vertex to the triangle */ /* add this vertex to the triangle */

View file

@ -54,6 +54,7 @@ extern const picoModule_t picoModuleMDC;
extern const picoModule_t picoModuleMD2; extern const picoModule_t picoModuleMD2;
extern const picoModule_t picoModuleFM; extern const picoModule_t picoModuleFM;
extern const picoModule_t picoModuleLWO; extern const picoModule_t picoModuleLWO;
extern const picoModule_t picoModuleTerrain;
@ -68,6 +69,7 @@ const picoModule_t *picoModules[] =
&picoModuleMD2, /* quake2 md2 */ &picoModuleMD2, /* quake2 md2 */
&picoModuleFM, /* heretic2 fm */ &picoModuleFM, /* heretic2 fm */
&picoModuleLWO, /* lightwave object */ &picoModuleLWO, /* lightwave object */
&picoModuleTerrain, /* picoterrain object */
&picoModuleOBJ, /* wavefront object */ &picoModuleOBJ, /* wavefront object */
NULL /* arnold */ NULL /* arnold */
}; };

View file

@ -397,6 +397,9 @@ static int GetMeshShader( T3dsLoaderPers *pers ){
return 0; return 0;
} }
/* ydnar: trim to first whitespace */
_pico_first_token( shaderName );
/* now that we have the shader name we need to go through all of */ /* now that we have the shader name we need to go through all of */
/* the shaders and check the name against each shader. when we */ /* the shaders and check the name against each shader. when we */
/* find a shader in our shader list that matches this name we */ /* find a shader in our shader list that matches this name we */
@ -418,7 +421,7 @@ static int GetMeshShader( T3dsLoaderPers *pers ){
/* we have a valid map name ptr */ /* we have a valid map name ptr */
if ( mapNamePtr != NULL ) { if ( mapNamePtr != NULL ) {
char temp[128]; char temp[128];
char *name; const char *name;
/* copy map name to local buffer */ /* copy map name to local buffer */
strcpy( mapName,mapNamePtr ); strcpy( mapName,mapNamePtr );
@ -523,7 +526,6 @@ static int DoNextEditorDataChunk( T3dsLoaderPers *pers, long endofs ){
/* read in surface name */ /* read in surface name */
if ( !GetASCIIZ( pers,surfaceName,sizeof( surfaceName ) ) ) { if ( !GetASCIIZ( pers,surfaceName,sizeof( surfaceName ) ) ) {
return 0; /* this is bad */ return 0; /* this is bad */
} }
//PicoGetSurfaceName //PicoGetSurfaceName
/* ignore NULL name surfaces */ /* ignore NULL name surfaces */
@ -606,10 +608,13 @@ static int DoNextEditorDataChunk( T3dsLoaderPers *pers, long endofs ){
/* but for now we skip the new material's name ... */ /* but for now we skip the new material's name ... */
if ( pers->shader ) { if ( pers->shader ) {
char *name = (char *)( pers->bufptr + pers->cofs ); char *name = (char *)( pers->bufptr + pers->cofs );
PicoSetShaderName( pers->shader,name ); char *cleanedName = _pico_clone_alloc( name );
_pico_first_token( cleanedName );
PicoSetShaderName( pers->shader, cleanedName );
#ifdef DEBUG_PM_3DS #ifdef DEBUG_PM_3DS
printf( "NewShader: '%s'\n",name ); printf( "NewShader: '%s'\n", cleanedName );
#endif #endif
_pico_free( cleanedName );
} }
} }
if ( chunk->id == CHUNK_MATDIFFUSE ) { if ( chunk->id == CHUNK_MATDIFFUSE ) {

View file

@ -105,6 +105,25 @@ static aseSubMaterial_t* _ase_get_submaterial( aseMaterial_t* list, int mtlIdPar
return subMtl; 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 ){ static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent ){
aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) ); aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) );
mtl->mtlId = mtlIdParent; mtl->mtlId = mtlIdParent;
@ -173,64 +192,6 @@ static void _ase_print_materials( aseMaterial_t *list ){
} }
#endif //DEBUG_PM_ASE #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 ){
/* 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: /* todo:
* - apply material specific uv offsets to uv coordinates * - apply material specific uv offsets to uv coordinates
*/ */
@ -274,7 +235,65 @@ static int _ase_canload( PM_PARAMS_CANLOAD ){
return PICO_PMV_OK; return PICO_PMV_OK;
} }
typedef struct aseVertex_s aseVertex_t;
struct aseVertex_s
{
picoVec3_t xyz;
picoVec3_t normal;
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;
};
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 /* _ase_submit_triangles - jhefty
use the surface and the current face list to look up material/submaterial IDs use the surface and the current face list to look up material/submaterial IDs
@ -286,65 +305,199 @@ static int _ase_canload( PM_PARAMS_CANLOAD ){
indexes 6 7 8 = color indexes (new) indexes 6 7 8 = color indexes (new)
*/ */
static void _ase_submit_triangles( picoSurface_t* surface, picoModel_t* model, aseMaterial_t* materials, aseFace_t* faces ){ #if 0
aseFace_t* face; typedef picoIndex_t* picoIndexIter_t;
aseSubMaterial_t* subMtl;
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 void _ase_submit_triangles( picoModel_t* model, aseMaterial_t* materials, aseVertex_t* vertices, aseTexCoord_t* texcoords, aseColor_t* colors, aseFace_t* faces, int numFaces ){
aseFacesIter_t i = faces, end = faces + numFaces;
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;
}
{
picoVec3_t* xyz[3]; picoVec3_t* xyz[3];
picoVec3_t* normal[3]; picoVec3_t* normal[3];
picoVec2_t* st[3]; picoVec2_t* st[3];
picoColor_t* color[3]; picoColor_t* color[3];
int i; picoIndex_t smooth[3];
int j;
face = faces; /* we pull the data from the vertex, color and texcoord arrays using the face index data */
while ( face != NULL ) for ( j = 0 ; j < 3 ; j++ )
{ {
/* look up the shader for the material/submaterial pair */ xyz[j] = &vertices[( *i ).indices[j]].xyz;
subMtl = _ase_get_submaterial( materials, face->mtlId, face->subMtlId ); normal[j] = &vertices[( *i ).indices[j]].normal;
if ( subMtl == NULL ) { st[j] = &texcoords[( *i ).indices[j + 3]].texcoord;
/* 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 */ if ( colors != NULL && ( *i ).indices[j + 6] >= 0 ) {
for ( i = 0 ; i < 3 ; i++ ) color[j] = &colors[( *i ).indices[j + 6]].color;
{
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 else
{ {
color[i] = &white; color[j] = &white;
} }
smooth[j] = ( vertices[( *i ).indices[j]].id * ( 1 << 16 ) ) + ( *i ).smoothingGroup; /* don't merge vertices */
} }
/* submit the triangle to the model */ /* submit the triangle to the model */
PicoAddTriangleToModel( model, xyz, normal, 1, st, 1, color, subMtl->shader ); PicoAddTriangleToModel( model, xyz, normal, 1, st, 1, color, subMtl->shader, smooth );
}
}
}
/* advance to the next face */ static void shadername_convert( char* shaderName ){
face = face->next; /* unix-style path separators */
char* s = shaderName;
for (; *s != '\0'; ++s )
{
if ( *s == '\\' ) {
*s = '/';
} }
} }
}
/* _ase_load: /* _ase_load:
* loads a 3dsmax ase model file. * loads a 3dsmax ase model file.
*/ */
static picoModel_t *_ase_load( PM_PARAMS_LOAD ){ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
picoModel_t *model; picoModel_t *model;
picoSurface_t *surface = NULL;
picoParser_t *p; picoParser_t *p;
char lastNodeName[ 1024 ]; char lastNodeName[ 1024 ];
aseVertex_t* vertices = NULL;
aseTexCoord_t* texcoords = NULL;
aseColor_t* colors = NULL;
aseFace_t* faces = NULL; aseFace_t* faces = NULL;
aseFace_t* facesTail = NULL; int numVertices = 0;
int numFaces = 0;
int numTextureVertices = 0;
int numTextureVertexFaces = 0;
int numColorVertices = 0;
int numColorVertexFaces = 0;
int vertexId = 0;
aseMaterial_t* materials = NULL; aseMaterial_t* materials = NULL;
#ifdef DEBUG_PM_ASE #ifdef DEBUG_PM_ASE
@ -413,15 +566,49 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
/* model mesh (originally contained within geomobject) */ /* model mesh (originally contained within geomobject) */
else if ( !_pico_stricmp( p->token,"*mesh" ) ) { else if ( !_pico_stricmp( p->token,"*mesh" ) ) {
/* finish existing surface */ /* finish existing surface */
//_ase_make_surface( model, &surface ); _ase_submit_triangles( model, materials, vertices, texcoords, colors, faces, numFaces );
_ase_submit_triangles( surface, model,materials,faces ); _pico_free( faces );
_ase_free_faces( &faces,&facesTail ); _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" );
}
/* allocate new pico surface */ vertices = _pico_calloc( numVertices, sizeof( aseVertex_t ) );
surface = PicoNewSurface( NULL ); }
if ( surface == NULL ) { else if ( !_pico_stricmp( p->token,"*mesh_numfaces" ) ) {
PicoFreeModel( model ); if ( !_pico_parse_int( p, &numFaces ) ) {
return NULL; _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 */ /* mesh material reference. this usually comes at the end of */
@ -430,77 +617,63 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
/* the material reference id (shader index) now. */ /* the material reference id (shader index) now. */
else if ( !_pico_stricmp( p->token,"*material_ref" ) ) { else if ( !_pico_stricmp( p->token,"*material_ref" ) ) {
int mtlId; 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) */ /* get the material ref (0..n) */
if ( !_pico_parse_int( p,&mtlId ) ) { if ( !_pico_parse_int( p,&mtlId ) ) {
_ase_error_return( "Missing material reference ID" ); _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 */ /* fix up all of the aseFaceList in the surface to point to the parent material */
/* we've already saved off their subMtl */ /* we've already saved off their subMtl */
face = faces; for (; i < numFaces; ++i )
while ( face != NULL )
{ {
face->mtlId = mtlId; faces[i].materialId = mtlId;
face = face->next; }
} }
} }
/* model mesh vertex */ /* model mesh vertex */
else if ( !_pico_stricmp( p->token,"*mesh_vertex" ) ) { else if ( !_pico_stricmp( p->token,"*mesh_vertex" ) ) {
picoVec3_t v;
int index; int index;
/* we must have a valid surface */ if ( numVertices == 0 ) {
if ( surface == NULL ) { _ase_error_return( "Vertex parse error" );
continue;
} }
/* get vertex data (orig: index +y -x +z) */ /* get vertex data (orig: index +y -x +z) */
if ( !_pico_parse_int( p,&index ) ) { if ( !_pico_parse_int( p,&index ) ) {
_ase_error_return( "Vertex parse error" ); _ase_error_return( "Vertex parse error" );
} }
if ( !_pico_parse_vec( p,v ) ) { if ( !_pico_parse_vec( p,vertices[index].xyz ) ) {
_ase_error_return( "Vertex parse error" ); _ase_error_return( "Vertex parse error" );
} }
/* set vertex */ vertices[index].id = vertexId++;
PicoSetSurfaceXYZ( surface,index,v );
} }
/* model mesh vertex normal */ /* model mesh vertex normal */
else if ( !_pico_stricmp( p->token,"*mesh_vertexnormal" ) ) { else if ( !_pico_stricmp( p->token,"*mesh_vertexnormal" ) ) {
picoVec3_t v;
int index; int index;
/* we must have a valid surface */ if ( numVertices == 0 ) {
if ( surface == NULL ) { _ase_error_return( "Vertex parse error" );
continue;
} }
/* get vertex data (orig: index +y -x +z) */ /* get vertex data (orig: index +y -x +z) */
if ( !_pico_parse_int( p,&index ) ) { if ( !_pico_parse_int( p,&index ) ) {
_ase_error_return( "Vertex parse error" ); _ase_error_return( "Vertex parse error" );
} }
if ( !_pico_parse_vec( p,v ) ) { if ( !_pico_parse_vec( p,vertices[index].normal ) ) {
_ase_error_return( "Vertex parse error" ); _ase_error_return( "Vertex parse error" );
} }
/* set vertex */
PicoSetSurfaceNormal( surface,index,v );
} }
/* model mesh face */ /* model mesh face */
else if ( !_pico_stricmp( p->token,"*mesh_face" ) ) { else if ( !_pico_stricmp( p->token,"*mesh_face" ) ) {
picoIndex_t indexes[3]; picoIndex_t indexes[3];
int index; int index;
/* we must have a valid surface */ if ( numFaces == 0 ) {
if ( surface == NULL ) { _ase_error_return( "Face parse error" );
continue;
} }
/* get face index */ /* get face index */
@ -526,75 +699,58 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
_ase_error_return( "Face parse error" ); _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 */ /* parse to the subMaterial ID */
while ( 1 ) while ( 1 )
{ {
_pico_parse( p,0 ); if ( !_pico_parse( p,0 ) ) { /* EOL */
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; break;
} }
if ( !_pico_stricmp( p->token,"*MESH_SMOOTHING" ) ) {
_pico_parse_int( p, &faces[index].smoothingGroup );
}
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 */ /* model texture vertex */
else if ( !_pico_stricmp( p->token,"*mesh_tvert" ) ) { else if ( !_pico_stricmp( p->token,"*mesh_tvert" ) ) {
picoVec2_t uv;
int index; int index;
/* we must have a valid surface */ if ( numVertices == 0 ) {
if ( surface == NULL ) { _ase_error_return( "Texture Vertex parse error" );
continue;
} }
/* get uv vertex index */ /* get uv vertex index */
if ( !_pico_parse_int( p,&index ) ) { if ( !_pico_parse_int( p,&index ) || index >= numTextureVertices ) {
_ase_error_return( "UV vertex parse error" ); _ase_error_return( "Texture vertex parse error" );
} }
/* get uv vertex s */ /* get uv vertex s */
if ( !_pico_parse_float( p,&uv[0] ) ) { if ( !_pico_parse_float( p,&texcoords[index].texcoord[0] ) ) {
_ase_error_return( "UV vertex parse error" ); _ase_error_return( "Texture vertex parse error" );
} }
/* get uv vertex t */ /* get uv vertex t */
if ( !_pico_parse_float( p,&uv[1] ) ) { if ( !_pico_parse_float( p,&texcoords[index].texcoord[1] ) ) {
_ase_error_return( "UV vertex parse error" ); _ase_error_return( "Texture vertex parse error" );
} }
/* ydnar: invert t */ /* ydnar: invert t */
uv[ 1 ] = 1.0f - uv[ 1 ]; texcoords[index].texcoord[ 1 ] = 1.0f - texcoords[index].texcoord[ 1 ];
/* set texture vertex */
PicoSetSurfaceST( surface,0,index,uv );
} }
/* ydnar: model mesh texture face */ /* ydnar: model mesh texture face */
else if ( !_pico_stricmp( p->token, "*mesh_tface" ) ) { else if ( !_pico_stricmp( p->token, "*mesh_tface" ) ) {
picoIndex_t indexes[3]; picoIndex_t indexes[3];
int index; int index;
aseFace_t* face;
/* we must have a valid surface */ if ( numFaces == 0 ) {
if ( surface == NULL ) { _ase_error_return( "Texture face parse error" );
continue;
} }
/* get face index */ /* get face index */
@ -617,65 +773,52 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
_ase_error_return( "Texture face parse error" ); _ase_error_return( "Texture face parse error" );
} }
/* set face indexes (note interleaved offset!) */ faces[index].indices[3] = indexes[2];
PicoSetSurfaceIndex( surface, ( index * 9 + 3 ), indexes[2] ); faces[index].indices[4] = indexes[1];
PicoSetSurfaceIndex( surface, ( index * 9 + 4 ), indexes[1] ); faces[index].indices[5] = indexes[0];
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 */ /* model color vertex */
else if ( !_pico_stricmp( p->token,"*mesh_vertcol" ) ) { else if ( !_pico_stricmp( p->token,"*mesh_vertcol" ) ) {
picoColor_t color;
int index; int index;
float colorInput; float colorInput;
/* we must have a valid surface */ if ( numVertices == 0 ) {
if ( surface == NULL ) { _ase_error_return( "Color Vertex parse error" );
continue;
} }
/* get color vertex index */ /* get color vertex index */
if ( !_pico_parse_int( p,&index ) ) { if ( !_pico_parse_int( p,&index ) ) {
_ase_error_return( "UV vertex parse error" ); _ase_error_return( "Color vertex parse error" );
} }
/* get R component */ /* get R component */
if ( !_pico_parse_float( p,&colorInput ) ) { if ( !_pico_parse_float( p,&colorInput ) ) {
_ase_error_return( "color vertex parse error" ); _ase_error_return( "Color vertex parse error" );
} }
color[0] = (picoByte_t)( colorInput * 255 ); colors[index].color[0] = (picoByte_t)( colorInput * 255 );
/* get G component */ /* get G component */
if ( !_pico_parse_float( p,&colorInput ) ) { if ( !_pico_parse_float( p,&colorInput ) ) {
_ase_error_return( "color vertex parse error" ); _ase_error_return( "Color vertex parse error" );
} }
color[1] = (picoByte_t)( colorInput * 255 ); colors[index].color[1] = (picoByte_t)( colorInput * 255 );
/* get B component */ /* get B component */
if ( !_pico_parse_float( p,&colorInput ) ) { if ( !_pico_parse_float( p,&colorInput ) ) {
_ase_error_return( "color vertex parse error" ); _ase_error_return( "Color vertex parse error" );
} }
color[2] = (picoByte_t)( colorInput * 255 ); colors[index].color[2] = (picoByte_t)( colorInput * 255 );
/* leave alpha alone since we don't get any data from the ASE format */ /* leave alpha alone since we don't get any data from the ASE format */
color[3] = 255; colors[index].color[3] = 255;
/* set texture vertex */
PicoSetSurfaceColor( surface,0,index,color );
} }
/* model color face */ /* model color face */
else if ( !_pico_stricmp( p->token,"*mesh_cface" ) ) { else if ( !_pico_stricmp( p->token,"*mesh_cface" ) ) {
picoIndex_t indexes[3]; picoIndex_t indexes[3];
int index; int index;
aseFace_t* face;
/* we must have a valid surface */ if ( numFaces == 0 ) {
if ( surface == NULL ) { _ase_error_return( "Face parse error" );
continue;
} }
/* get face index */ /* get face index */
@ -701,20 +844,14 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
_ase_error_return( "Face parse error" ); _ase_error_return( "Face parse error" );
} }
/* set face indexes (note interleaved offset!) */ faces[index].indices[6] = indexes[2];
PicoSetSurfaceIndex( surface, ( index * 9 + 6 ), indexes[2] ); faces[index].indices[7] = indexes[1];
PicoSetSurfaceIndex( surface, ( index * 9 + 7 ), indexes[1] ); faces[index].indices[8] = indexes[0];
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 */ /* model material */
else if ( !_pico_stricmp( p->token, "*material" ) ) { else if ( !_pico_stricmp( p->token, "*material" ) ) {
aseSubMaterial_t* subMaterial = NULL; aseSubMaterial_t* subMaterial = NULL;
picoShader_t *shader = NULL; picoShader_t *shader;
int level = 1, index; int level = 1, index;
char materialName[ 1024 ]; char materialName[ 1024 ];
float transValue = 0.0f, shineValue = 1.0f; float transValue = 0.0f, shineValue = 1.0f;
@ -755,6 +892,8 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
if ( level == subMaterialLevel ) { if ( level == subMaterialLevel ) {
/* set material name */ /* set material name */
_pico_first_token( materialName );
shadername_convert( materialName );
PicoSetShaderName( shader, materialName ); PicoSetShaderName( shader, materialName );
/* set shader's transparency */ /* set shader's transparency */
@ -944,6 +1083,7 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
} }
/* set material name */ /* set material name */
shadername_convert( materialName );
PicoSetShaderName( shader,materialName ); PicoSetShaderName( shader,materialName );
/* set shader's transparency */ /* set shader's transparency */
@ -967,6 +1107,34 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
/* set material map name */ /* set material map name */
PicoSetShaderMapName( shader, mapname ); PicoSetShaderMapName( shader, mapname );
/* extract shadername from bitmap path */
if ( mapname != NULL ) {
char* p = mapname;
/* convert to shader-name format */
shadername_convert( mapname );
{
/* remove extension */
char* last_period = strrchr( p, '.' );
if ( last_period != NULL ) {
*last_period = '\0';
}
}
/* find shader path */
for (; *p != '\0'; ++p )
{
if ( _pico_strnicmp( p, "models/", 7 ) == 0 || _pico_strnicmp( p, "textures/", 9 ) == 0 ) {
break;
}
}
if ( *p != '\0' ) {
/* set material name */
PicoSetShaderName( shader,p );
}
}
/* this is just a material with 1 submaterial */ /* this is just a material with 1 submaterial */
subMaterial = _ase_add_submaterial( &materials, index, 0, shader ); subMaterial = _ase_add_submaterial( &materials, index, 0, shader );
} }
@ -982,9 +1150,11 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
} }
/* ydnar: finish existing surface */ /* ydnar: finish existing surface */
// _ase_make_surface( model, &surface ); _ase_submit_triangles( model, materials, vertices, texcoords, colors, faces, numFaces );
_ase_submit_triangles( surface, model,materials,faces ); _pico_free( faces );
_ase_free_faces( &faces,&facesTail ); _pico_free( vertices );
_pico_free( texcoords );
_pico_free( colors );
#ifdef DEBUG_PM_ASE #ifdef DEBUG_PM_ASE
_ase_print_materials( materials ); _ase_print_materials( materials );
@ -995,6 +1165,8 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){
_ase_free_materials( &materials ); _ase_free_materials( &materials );
_pico_free_parser( p );
/* return allocated pico model */ /* return allocated pico model */
return model; return model;
} }

View file

@ -350,7 +350,7 @@ static picoModel_t *_fm_load( PM_PARAMS_LOAD ){
texCoord->t = _pico_little_short( texCoord[i].t ); texCoord->t = _pico_little_short( texCoord[i].t );
} }
// set Skin Name // set Skin Name
strncpy( skinname, (char *) fm.fm_skin, FM_SKINPATHSIZE ); strncpy( skinname, (unsigned char *) fm.fm_skin, FM_SKINPATHSIZE );
#ifdef FM_VERBOSE_DBG #ifdef FM_VERBOSE_DBG
// Print out md2 values // Print out md2 values

View file

@ -103,7 +103,7 @@ static picoModel_t *_lwo_load( PM_PARAMS_LOAD ){
lwPolygon *pol; lwPolygon *pol;
lwPolVert *v; lwPolVert *v;
lwVMapPt *vm; lwVMapPt *vm;
char name[ 64 ]; char name[ 256 ];
int i, j, k, numverts; int i, j, k, numverts;
picoModel_t *picoModel; picoModel_t *picoModel;
@ -235,6 +235,7 @@ static picoModel_t *_lwo_load( PM_PARAMS_LOAD ){
/* detox and set shader name */ /* detox and set shader name */
strncpy( name, surface->name, sizeof( name ) ); strncpy( name, surface->name, sizeof( name ) );
_pico_first_token( name );
_pico_setfext( name, "" ); _pico_setfext( name, "" );
_pico_unixify( name ); _pico_unixify( name );
PicoSetShaderName( picoShader, name ); PicoSetShaderName( picoShader, name );
@ -282,9 +283,22 @@ static picoModel_t *_lwo_load( PM_PARAMS_LOAD ){
xyz[ 1 ] = pt->pos[ 2 ]; xyz[ 1 ] = pt->pos[ 2 ];
xyz[ 2 ] = pt->pos[ 1 ]; xyz[ 2 ] = pt->pos[ 1 ];
///* doom3 lwo data doesn't seem to have smoothing-angle information */
//#if 0
// if ( surface->smooth <= 0 ) {
// /* use face normals */
normal[ 0 ] = v->norm[ 0 ]; normal[ 0 ] = v->norm[ 0 ];
normal[ 1 ] = v->norm[ 2 ]; normal[ 1 ] = v->norm[ 2 ];
normal[ 2 ] = v->norm[ 1 ]; normal[ 2 ] = v->norm[ 1 ];
}
else
//#endif
{
/* smooth normals later */
normal[ 0 ] = 0;
normal[ 1 ] = 0;
normal[ 2 ] = 0;
}
st[ 0 ] = xyz[ defaultSTAxis[ 0 ] ] * defaultXYZtoSTScale[ 0 ]; st[ 0 ] = xyz[ defaultSTAxis[ 0 ] ] * defaultXYZtoSTScale[ 0 ];
st[ 1 ] = xyz[ defaultSTAxis[ 1 ] ] * defaultXYZtoSTScale[ 1 ]; st[ 1 ] = xyz[ defaultSTAxis[ 1 ] ] * defaultXYZtoSTScale[ 1 ];

View file

@ -241,7 +241,7 @@ static int _obj_mtl_load( picoModel_t *model ){
return 0; \ return 0; \
} }
/* alloc copy of model file name */ /* alloc copy of model file name */
fileName = _pico_clone_alloc( model->fileName,-1 ); fileName = _pico_clone_alloc( model->fileName );
if ( fileName == NULL ) { if ( fileName == NULL ) {
return 0; return 0;
} }

607
libs/picomodel/pm_terrain.c Normal file
View file

@ -0,0 +1,607 @@
/* -----------------------------------------------------------------------------
PicoModel Library
Copyright (c) 2003, 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 materials 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_TERRAIN_C
/* dependencies */
#include "picointernal.h"
typedef struct tga_s
{
unsigned char id_length, colormap_type, image_type;
unsigned short colormap_index, colormap_length;
unsigned char colormap_size;
unsigned short x_origin, y_origin, width, height;
unsigned char pixel_size, attributes;
}
tga_t;
/*
_terrain_load_tga_buffer()
loads a tga image into a newly allocated image buffer
fixme: replace/clean this function
*/
void _terrain_load_tga_buffer( unsigned char *buffer, unsigned char **pic, int *width, int *height ) {
int row, column;
int columns, rows, numPixels;
unsigned char *pixbuf;
unsigned char *buf_p;
tga_t targa_header;
unsigned char *targa_rgba;
*pic = NULL;
if ( buffer == NULL ) {
return;
}
buf_p = buffer;
targa_header.id_length = *buf_p++;
targa_header.colormap_type = *buf_p++;
targa_header.image_type = *buf_p++;
targa_header.colormap_index = _pico_little_short( *(short*)buf_p );
buf_p += 2;
targa_header.colormap_length = _pico_little_short( *(short*) buf_p );
buf_p += 2;
targa_header.colormap_size = *buf_p++;
targa_header.x_origin = _pico_little_short( *(short*) buf_p );
buf_p += 2;
targa_header.y_origin = _pico_little_short( *(short*) buf_p );
buf_p += 2;
targa_header.width = _pico_little_short( *(short*) buf_p );
buf_p += 2;
targa_header.height = _pico_little_short( *(short*) buf_p );
buf_p += 2;
targa_header.pixel_size = *buf_p++;
targa_header.attributes = *buf_p++;
if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 ) {
_pico_printf( PICO_ERROR, "Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n" );
pic = NULL;
return;
}
if ( targa_header.colormap_type != 0 ) {
_pico_printf( PICO_ERROR, "Indexed color TGA images not supported\n" );
return;
}
if ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 && targa_header.image_type != 3 ) {
_pico_printf( PICO_ERROR, "Only 32 or 24 bit TGA images supported (not indexed color)\n" );
pic = NULL;
return;
}
columns = targa_header.width;
rows = targa_header.height;
numPixels = columns * rows;
if ( width ) {
*width = columns;
}
if ( height ) {
*height = rows;
}
targa_rgba = _pico_alloc( numPixels * 4 );
*pic = targa_rgba;
if ( targa_header.id_length != 0 ) {
buf_p += targa_header.id_length; // skip TARGA image comment
}
if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) {
// Uncompressed RGB or gray scale image
for ( row = rows - 1; row >= 0; row-- )
{
pixbuf = targa_rgba + row * columns * 4;
for ( column = 0; column < columns; column++ )
{
unsigned char red,green,blue,alphabyte;
switch ( targa_header.pixel_size )
{
case 8:
blue = *buf_p++;
green = blue;
red = blue;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
break;
default:
break;
}
}
}
}
/* rle encoded pixels */
else if ( targa_header.image_type == 10 ) {
unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
red = 0;
green = 0;
blue = 0;
alphabyte = 0xff;
for ( row = rows - 1; row >= 0; row-- ) {
pixbuf = targa_rgba + row * columns * 4;
for ( column = 0; column < columns; ) {
packetHeader = *buf_p++;
packetSize = 1 + ( packetHeader & 0x7f );
if ( packetHeader & 0x80 ) { // run-length packet
switch ( targa_header.pixel_size ) {
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
break;
default:
//Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
break;
}
for ( j = 0; j < packetSize; j++ ) {
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
column++;
if ( column == columns ) { // run spans across rows
column = 0;
if ( row > 0 ) {
row--;
}
else{
goto breakOut;
}
pixbuf = targa_rgba + row * columns * 4;
}
}
}
else { // non run-length packet
for ( j = 0; j < packetSize; j++ ) {
switch ( targa_header.pixel_size ) {
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
break;
default:
//Sysprintf("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
break;
}
column++;
if ( column == columns ) { // pixel packet run spans across rows
column = 0;
if ( row > 0 ) {
row--;
}
else{
goto breakOut;
}
pixbuf = targa_rgba + row * columns * 4;
}
}
}
}
breakOut:;
}
}
/* fix vertically flipped image */
if ( ( targa_header.attributes & ( 1 << 5 ) ) ) {
int flip;
for ( row = 0; row < .5f * rows; row++ )
{
for ( column = 0; column < columns; column++ )
{
flip = *( (int*)targa_rgba + row * columns + column );
*( (int*)targa_rgba + row * columns + column ) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
*( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;
}
}
}
}
/*
_terrain_canload()
validates a picoterrain file
*/
static int _terrain_canload( PM_PARAMS_CANLOAD ) {
picoParser_t *p;
/* 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, "picoterrain" ) ) {
_pico_free_parser( p );
return PICO_PMV_ERROR_IDENT;
}
/* free the pico parser object */
_pico_free_parser( p );
/* file seems to be a valid picoterrain file */
return PICO_PMV_OK;
}
/*
_terrain_load()
loads a picoterrain file
*/
static picoModel_t *_terrain_load( PM_PARAMS_LOAD ) {
int i, j, v, pw[ 5 ], r;
picoParser_t *p;
char *shader, *heightmapFile, *colormapFile;
picoVec3_t scale, origin;
unsigned char *imageBuffer;
int imageBufSize, w, h, cw, ch;
unsigned char *heightmap, *colormap, *heightPixel, *colorPixel;
picoModel_t *picoModel;
picoSurface_t *picoSurface;
picoShader_t *picoShader;
picoVec3_t xyz, normal;
picoVec2_t st;
picoColor_t color;
/* keep the friggin compiler happy */
*fileName = *fileName;
/* create pico parser */
p = _pico_new_parser( (picoByte_t*) buffer, bufSize );
if ( p == NULL ) {
return NULL;
}
/* get first token */
if ( _pico_parse_first( p ) == NULL ) {
return NULL;
}
/* check first token */
if ( _pico_stricmp( p->token, "picoterrain" ) ) {
_pico_printf( PICO_ERROR, "Invalid PicoTerrain model" );
_pico_free_parser( p );
return NULL;
}
/* setup */
shader = heightmapFile = colormapFile = NULL;
_pico_set_vec( scale, 512, 512, 32 );
/* parse ase model file */
while ( 1 )
{
/* get first token on line */
if ( !_pico_parse_first( p ) ) {
break;
}
/* skip empty lines */
if ( !p->token || !p->token[ 0 ] ) {
continue;
}
/* shader */
if ( !_pico_stricmp( p->token, "shader" ) ) {
if ( _pico_parse( p, 0 ) && p->token[ 0 ] ) {
if ( shader != NULL ) {
_pico_free( shader );
}
shader = _pico_clone_alloc( p->token );
}
}
/* heightmap */
else if ( !_pico_stricmp( p->token, "heightmap" ) ) {
if ( _pico_parse( p, 0 ) && p->token[ 0 ] ) {
if ( heightmapFile != NULL ) {
_pico_free( heightmapFile );
}
heightmapFile = _pico_clone_alloc( p->token );
}
}
/* colormap */
else if ( !_pico_stricmp( p->token, "colormap" ) ) {
if ( _pico_parse( p, 0 ) && p->token[ 0 ] ) {
if ( colormapFile != NULL ) {
_pico_free( colormapFile );
}
colormapFile = _pico_clone_alloc( p->token );
}
}
/* scale */
else if ( !_pico_stricmp( p->token, "scale" ) ) {
_pico_parse_vec( p, scale );
}
/* skip unparsed rest of line and continue */
_pico_parse_skip_rest( p );
}
/* ----------------------------------------------------------------- */
/* load heightmap */
heightmap = imageBuffer = NULL;
_pico_load_file( heightmapFile, &imageBuffer, &imageBufSize );
_terrain_load_tga_buffer( imageBuffer, &heightmap, &w, &h );
_pico_free( heightmapFile );
_pico_free_file( imageBuffer );
if ( heightmap == NULL || w < 2 || h < 2 ) {
_pico_printf( PICO_ERROR, "PicoTerrain model with invalid heightmap" );
if ( shader != NULL ) {
_pico_free( shader );
}
if ( colormapFile != NULL ) {
_pico_free( colormapFile );
}
_pico_free_parser( p );
return NULL;
}
/* set origin (bottom lowest corner of terrain mesh) */
_pico_set_vec( origin, ( w / -2 ) * scale[ 0 ], ( h / -2 ) * scale[ 1 ], -128 * scale[ 2 ] );
/* load colormap */
colormap = imageBuffer = NULL;
_pico_load_file( colormapFile, &imageBuffer, &imageBufSize );
_terrain_load_tga_buffer( imageBuffer, &colormap, &cw, &ch );
_pico_free( colormapFile );
_pico_free_file( imageBuffer );
if ( cw != w || ch != h ) {
_pico_printf( PICO_WARNING, "PicoTerrain colormap/heightmap size mismatch" );
_pico_free( colormap );
colormap = NULL;
}
/* ----------------------------------------------------------------- */
/* create new pico model */
picoModel = PicoNewModel();
if ( picoModel == NULL ) {
_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
return NULL;
}
/* do model setup */
PicoSetModelFrameNum( picoModel, frameNum );
PicoSetModelNumFrames( picoModel, 1 ); /* sea */
PicoSetModelName( picoModel, fileName );
PicoSetModelFileName( picoModel, fileName );
/* allocate new pico surface */
picoSurface = PicoNewSurface( picoModel );
if ( picoSurface == NULL ) {
_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
PicoFreeModel( picoModel ); /* sea */
return NULL;
}
/* terrain surfaces are triangle meshes */
PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
/* set surface name */
PicoSetSurfaceName( picoSurface, "picoterrain" );
/* create new pico shader */
picoShader = PicoNewShader( picoModel );
if ( picoShader == NULL ) {
_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
PicoFreeModel( picoModel );
_pico_free( shader );
return NULL;
}
/* detox and set shader name */
_pico_setfext( shader, "" );
_pico_unixify( shader );
PicoSetShaderName( picoShader, shader );
_pico_free( shader );
/* associate current surface with newly created shader */
PicoSetSurfaceShader( picoSurface, picoShader );
/* make bogus normal */
_pico_set_vec( normal, 0.0f, 0.0f, 0.0f );
/* create mesh */
for ( j = 0; j < h; j++ )
{
for ( i = 0; i < w; i++ )
{
/* get pointers */
v = i + ( j * w );
heightPixel = heightmap + v * 4;
colorPixel = colormap
? colormap + v * 4
: NULL;
/* set xyz */
_pico_set_vec( xyz, origin[ 0 ] + scale[ 0 ] * i,
origin[ 1 ] + scale[ 1 ] * j,
origin[ 2 ] + scale[ 2 ] * heightPixel[ 0 ] );
PicoSetSurfaceXYZ( picoSurface, v, xyz );
/* set normal */
PicoSetSurfaceNormal( picoSurface, v, normal );
/* set st */
st[ 0 ] = (float) i;
st[ 1 ] = (float) j;
PicoSetSurfaceST( picoSurface, 0, v, st );
/* set color */
if ( colorPixel != NULL ) {
_pico_set_color( color, colorPixel[ 0 ], colorPixel[ 1 ], colorPixel[ 2 ], colorPixel[ 3 ] );
}
else{
_pico_set_color( color, 255, 255, 255, 255 );
}
PicoSetSurfaceColor( picoSurface, 0, v, color );
/* set triangles (zero alpha in heightmap suppresses this quad) */
if ( i < ( w - 1 ) && j < ( h - 1 ) && heightPixel[ 3 ] >= 128 ) {
/* set indexes */
pw[ 0 ] = i + ( j * w );
pw[ 1 ] = i + ( ( j + 1 ) * w );
pw[ 2 ] = i + 1 + ( ( j + 1 ) * w );
pw[ 3 ] = i + 1 + ( j * w );
pw[ 4 ] = i + ( j * w ); /* same as pw[ 0 ] */
/* set radix */
r = ( i + j ) & 1;
/* make first triangle */
PicoSetSurfaceIndex( picoSurface, ( v * 6 + 0 ), (picoIndex_t) pw[ r + 0 ] );
PicoSetSurfaceIndex( picoSurface, ( v * 6 + 1 ), (picoIndex_t) pw[ r + 1 ] );
PicoSetSurfaceIndex( picoSurface, ( v * 6 + 2 ), (picoIndex_t) pw[ r + 2 ] );
/* make second triangle */
PicoSetSurfaceIndex( picoSurface, ( v * 6 + 3 ), (picoIndex_t) pw[ r + 0 ] );
PicoSetSurfaceIndex( picoSurface, ( v * 6 + 4 ), (picoIndex_t) pw[ r + 2 ] );
PicoSetSurfaceIndex( picoSurface, ( v * 6 + 5 ), (picoIndex_t) pw[ r + 3 ] );
}
}
}
/* free stuff */
_pico_free_parser( p );
_pico_free( heightmap );
_pico_free( colormap );
/* return the new pico model */
return picoModel;
}
/* pico file format module definition */
const picoModule_t picoModuleTerrain =
{
"1.3", /* module version string */
"PicoTerrain", /* module display name */
"Randy Reddig", /* author's name */
"2003 Randy Reddig", /* module copyright */
{
"picoterrain", NULL, NULL, NULL /* default extensions to use */
},
_terrain_canload, /* validation routine */
_terrain_load, /* load routine */
NULL, /* save validation routine */
NULL /* save routine */
};