From: Garux Date: Sat, 29 Sep 2018 11:39:10 +0000 (+0300) Subject: * picomodel: do some guessings about shader paths to handle more cases out of the... X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=30171b846f490444ef059fa04974b0b5f8a191b8;p=xonotic%2Fnetradiant.git * picomodel: do some guessings about shader paths to handle more cases out of the box; ones are based on material and diffuse map names: name w/o path: assume textures are in the folder, where model file is absolute path or with ..: try to cut at "/models/" or "/textures/" (as if leading to game folders); do previous case, if not strip extensions and turn slashes to forward ones anytime * picomodel::obj: fix diffuse map paths loading from .mtl --- diff --git a/libs/picomodel/picointernal.c b/libs/picomodel/picointernal.c index 19950c1d..614d7c53 100644 --- a/libs/picomodel/picointernal.c +++ b/libs/picomodel/picointernal.c @@ -694,6 +694,60 @@ int _pico_getline( char *buf, int bufsize, char *dest, int destsize ){ return pos; } +/* expecting fileName to be relative vfs model path */ +void _pico_deduce_shadername( const char* fileName, const char* srcName, picoShader_t* shader ){ + if( srcName == NULL || fileName == NULL ) + return; + char name[strlen( srcName ) + 1]; + strcpy( name, srcName ); + _pico_unixify( name ); + _pico_setfext( name, NULL ); + + char path[strlen( fileName ) + strlen( name ) + 1]; + _pico_nofname( fileName, path, strlen( fileName ) + strlen( name ) + 1 ); + _pico_unixify( path ); + + if( !strchr( name , '/' ) ){ /* texture is likely in the folder, where model is */ + strcat( path, name ); + } + else if( name[0] == '/' || ( name[0] != '\0' && name[1] == ':' ) || strstr( name, ".." ) ){ /* absolute path or with .. */ + const char* p = name; + for (; *p != '\0'; ++p ) + if ( _pico_strnicmp( p, "/models/", 8 ) == 0 || _pico_strnicmp( p, "/textures/", 10 ) == 0 ) + break; + if( *p != '\0' ){ + strcpy( path, p + 1 ); + } + else{ + p = _pico_nopath( name ); + strcat( path, p ); + } + } + else{ + PicoSetShaderName( shader, name ); + return; + } + + _pico_printf( PICO_NORMAL, "PICO: substituting shader name: %s -> %s", srcName, path ); + PicoSetShaderName( shader, path ); +} + +/* deduce shadernames from bitmap or shadername paths */ +void _pico_deduce_shadernames( picoModel_t *model ){ + for ( int i = 0; i < model->numShaders; ++i ){ + /* skip null shaders */ + if ( model->shader[i] == NULL ) + continue; + + const char* mapname = model->shader[i]->mapName; + const char* shadername = model->shader[i]->name; + if( mapname && *mapname ) + _pico_deduce_shadername( model->fileName, mapname, model->shader[i] ); + else if( shadername && *shadername ) + _pico_deduce_shadername( model->fileName, shadername, model->shader[i] ); + } +} + /* _pico_parse_skip_white: * skips white spaces in current pico parser, sets *hasLFs * to 1 if linefeeds were skipped, and either returns the diff --git a/libs/picomodel/picointernal.h b/libs/picomodel/picointernal.h index 4ffae1b5..312cc643 100644 --- a/libs/picomodel/picointernal.h +++ b/libs/picomodel/picointernal.h @@ -136,10 +136,11 @@ void _pico_printf( int level, const char *format, ... ); const char *_pico_stristr( const char *str, const char *substr ); void _pico_unixify( char *path ); int _pico_nofname( const char *path, char *dest, int destSize ); -const char *_pico_nopath( const char *path ); +const char *_pico_nopath( const char *path ); char *_pico_setfext( char *path, const char *ext ); int _pico_getline( char *buf, int bufsize, char *dest, int destsize ); char *_pico_strlwr( char *str ); +void _pico_deduce_shadernames( picoModel_t *model ); /* vectors */ void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ); diff --git a/libs/picomodel/picomodel.c b/libs/picomodel/picomodel.c index 79655ce8..7d53683a 100644 --- a/libs/picomodel/picomodel.c +++ b/libs/picomodel/picomodel.c @@ -173,6 +173,8 @@ picoModel_t *PicoModuleLoadModel( const picoModule_t* pm, const char* fileName, } } + _pico_deduce_shadernames( model ); + return model; } @@ -484,16 +486,13 @@ void PicoFreeShader( picoShader_t *shader ){ */ picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ){ - int i; - - /* sanity checks */ if ( model == NULL || name == NULL ) { /* sea: null name fix */ return NULL; } /* walk list */ - for ( i = 0; i < model->numShaders; i++ ) + for ( int i = 0; i < model->numShaders; i++ ) { /* skip null shaders or shaders with null names */ if ( model->shader[ i ] == NULL || diff --git a/libs/picomodel/pm_3ds.c b/libs/picomodel/pm_3ds.c index b802814a..c6ac1531 100644 --- a/libs/picomodel/pm_3ds.c +++ b/libs/picomodel/pm_3ds.c @@ -400,17 +400,15 @@ static int GetMeshShader( T3dsLoaderPers *pers ){ /* we've found a matching shader */ if ( ( shader != NULL ) && pers->surface ) { - char mapName[1024 + 1]; - char *mapNamePtr; - memset( mapName,0,sizeof( mapName ) ); - /* get ptr to shader's map name */ - mapNamePtr = PicoGetShaderMapName( shader ); - + const char* mapNamePtr = PicoGetShaderMapName( shader ); /* we have a valid map name ptr */ if ( mapNamePtr != NULL ) { +#if 0 char temp[128]; const char *name; + char mapName[1024 + 1]; + memset( mapName,0,sizeof( mapName ) ); /* copy map name to local buffer */ strcpy( mapName,mapNamePtr ); @@ -420,7 +418,7 @@ static int GetMeshShader( T3dsLoaderPers *pers ){ strncpy( temp, name, sizeof( temp ) ); /* remove file extension */ - /* name = _pico_setfext( name,"" ); */ + /* name = _pico_setfext( name, NULL ); */ /* assign default name if no name available */ if ( strlen( temp ) < 1 ) { @@ -433,7 +431,7 @@ static int GetMeshShader( T3dsLoaderPers *pers ){ /* set shader name */ /* PicoSetShaderName( shader,mapName ); */ /* ydnar: this will screw up the named shader */ - +#endif /* set surface's shader index */ PicoSetSurfaceShader( pers->surface, shader ); @@ -726,7 +724,7 @@ static picoModel_t *_3ds_load( PM_PARAMS_LOAD ){ /* get model's base name (eg. jeep from c:\models\jeep.3ds) */ memset( basename,0,sizeof( basename ) ); strncpy( basename,_pico_nopath( fileName ),sizeof( basename ) ); - _pico_setfext( basename,"" ); + _pico_setfext( basename, NULL ); /* initialize persistant vars (formerly static) */ pers.model = model; diff --git a/libs/picomodel/pm_ase.c b/libs/picomodel/pm_ase.c index 21c8e080..1244eb35 100644 --- a/libs/picomodel/pm_ase.c +++ b/libs/picomodel/pm_ase.c @@ -456,17 +456,6 @@ static void _ase_submit_triangles( picoModel_t* model, aseMaterial_t* materials, } } -static void shadername_convert( char* shaderName ){ - /* unix-style path separators */ - char* s = shaderName; - for (; *s != '\0'; ++s ) - { - if ( *s == '\\' ) { - *s = '/'; - } - } -} - /* _ase_load: * loads a 3dsmax ase model file. @@ -883,7 +872,7 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){ if ( level == subMaterialLevel ) { /* set material name */ _pico_first_token( materialName ); - shadername_convert( materialName ); + _pico_unixify( materialName ); PicoSetShaderName( shader, materialName ); /* set shader's transparency */ @@ -1073,7 +1062,7 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){ } /* set material name */ - shadername_convert( materialName ); + _pico_unixify( materialName ); PicoSetShaderName( shader,materialName ); /* set shader's transparency */ @@ -1097,34 +1086,6 @@ static picoModel_t *_ase_load( PM_PARAMS_LOAD ){ /* set material map name */ 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 */ subMaterial = _ase_add_submaterial( &materials, index, 0, shader ); } diff --git a/libs/picomodel/pm_fm.c b/libs/picomodel/pm_fm.c index 0df82a25..79fff8b9 100644 --- a/libs/picomodel/pm_fm.c +++ b/libs/picomodel/pm_fm.c @@ -374,7 +374,7 @@ static picoModel_t *_fm_load( PM_PARAMS_LOAD ){ #endif // detox Skin name - _pico_setfext( skinname, "" ); + _pico_setfext( skinname, NULL ); _pico_unixify( skinname ); /* create new pico model */ diff --git a/libs/picomodel/pm_lwo.c b/libs/picomodel/pm_lwo.c index 6cbf0f4c..37f2b60b 100644 --- a/libs/picomodel/pm_lwo.c +++ b/libs/picomodel/pm_lwo.c @@ -233,7 +233,7 @@ static picoModel_t *_lwo_load( PM_PARAMS_LOAD ){ /* detox and set shader name */ strncpy( name, surface->name, sizeof( name ) ); _pico_first_token( name ); - _pico_setfext( name, "" ); + _pico_setfext( name, NULL ); _pico_unixify( name ); PicoSetShaderName( picoShader, name ); diff --git a/libs/picomodel/pm_md2.c b/libs/picomodel/pm_md2.c index 82975b88..c984e42e 100644 --- a/libs/picomodel/pm_md2.c +++ b/libs/picomodel/pm_md2.c @@ -424,7 +424,7 @@ static picoModel_t *_md2_load( PM_PARAMS_LOAD ){ _pico_printf( PICO_VERBOSE,"Skins: %d Verts: %d STs: %d Triangles: %d Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname ); // detox Skin name - _pico_setfext( skinname, "" ); + _pico_setfext( skinname, NULL ); _pico_unixify( skinname ); /* create new pico model */ diff --git a/libs/picomodel/pm_md3.c b/libs/picomodel/pm_md3.c index 86742d73..1b93c7b4 100644 --- a/libs/picomodel/pm_md3.c +++ b/libs/picomodel/pm_md3.c @@ -340,7 +340,7 @@ static picoModel_t *_md3_load( PM_PARAMS_LOAD ){ /* detox and set shader name */ shader = (md3Shader_t*) ( (picoByte_t*) surface + surface->ofsShaders ); - _pico_setfext( shader->name, "" ); + _pico_setfext( shader->name, NULL ); _pico_unixify( shader->name ); PicoSetShaderName( picoShader, shader->name ); diff --git a/libs/picomodel/pm_mdc.c b/libs/picomodel/pm_mdc.c index be93e338..ec40d5a9 100644 --- a/libs/picomodel/pm_mdc.c +++ b/libs/picomodel/pm_mdc.c @@ -640,7 +640,7 @@ static picoModel_t *_mdc_load( PM_PARAMS_LOAD ){ /* detox and set shader name */ shader = (mdcShader_t*) ( (picoByte_t*) surface + surface->ofsShaders ); - _pico_setfext( shader->name, "" ); + _pico_setfext( shader->name, NULL ); _pico_unixify( shader->name ); PicoSetShaderName( picoShader, shader->name ); diff --git a/libs/picomodel/pm_obj.c b/libs/picomodel/pm_obj.c index 6e11a1cd..7a0ebd5f 100644 --- a/libs/picomodel/pm_obj.c +++ b/libs/picomodel/pm_obj.c @@ -228,9 +228,12 @@ static int _obj_mtl_load( picoModel_t *model ){ return 0; } - /* helper */ + /* helpers */ + #define _obj_mtl_print_ok _pico_printf( PICO_NORMAL, "PICO: loading %s...OK\n", fileName ) + #define _obj_mtl_print_fail _pico_printf( PICO_WARNING, "PICO: loading %s...FAIL\n", fileName ) #define _obj_mtl_error_return \ { \ + _obj_mtl_print_fail; \ _pico_free_parser( p ); \ _pico_free_file( mtlBuffer ); \ _pico_free( fileName ); \ @@ -250,9 +253,11 @@ static int _obj_mtl_load( picoModel_t *model ){ /* check result */ if ( mtlBufSize == 0 ) { + _obj_mtl_print_fail; return 1; /* file is empty: no error */ } if ( mtlBufSize < 0 ) { + _obj_mtl_print_fail; return 0; /* load failed: error */ } @@ -269,7 +274,6 @@ static int _obj_mtl_load( picoModel_t *model ){ if ( _pico_parse( p,1 ) == NULL ) { break; } -#if 1 /* skip empty lines */ if ( p->token == NULL || !strlen( p->token ) ) { @@ -309,7 +313,6 @@ static int _obj_mtl_load( picoModel_t *model ){ /* diffuse map name */ else if ( !_pico_stricmp( p->token,"map_kd" ) ) { char *mapName; - picoShader_t *shader; /* pointer to current shader must be valid */ if ( curShader == NULL ) { @@ -324,13 +327,8 @@ static int _obj_mtl_load( picoModel_t *model ){ _pico_printf( PICO_ERROR,"Missing material map name in MTL %s, line %d.",fileName,p->curLine ); _obj_mtl_error_return; } - /* create a new pico shader */ - shader = PicoNewShader( model ); - if ( shader == NULL ) { - _obj_mtl_error_return; - } /* set shader map name */ - PicoSetShaderMapName( shader,mapName ); + PicoSetShaderMapName( curShader, mapName ); } /* dissolve factor (pseudo transparency 0..1) */ /* where 0 means 100% transparent and 1 means opaque */ @@ -482,12 +480,12 @@ static int _obj_mtl_load( picoModel_t *model ){ /* set specular color */ PicoSetShaderSpecularColor( curShader,color ); } -#endif /* skip rest of line */ _pico_parse_skip_rest( p ); } /* free parser, file buffer, and file name */ + _obj_mtl_print_ok; _pico_free_parser( p ); _pico_free_file( mtlBuffer ); _pico_free( fileName ); @@ -564,10 +562,8 @@ static picoModel_t *_obj_load( PM_PARAMS_LOAD ){ PicoSetModelName( model,fileName ); PicoSetModelFileName( model,fileName ); - /* try loading the materials; we don't handle the result */ -#if 1 + /* try loading the materials */ _obj_mtl_load( model ); -#endif /* parse obj line by line */ while ( 1 ) @@ -903,7 +899,7 @@ static picoModel_t *_obj_load( PM_PARAMS_LOAD ){ { shader = PicoFindShader( model, name, 1 ); if ( shader == NULL ) { - _pico_printf( PICO_WARNING,"Undefined material name \"%s\" in OBJ %s, line %d. Making a default shader.",name,model->fileName,p->curLine ); + _pico_printf( PICO_WARNING, "Undefined material name \"%s\" in OBJ, line %d. Making a default shader.", name, p->curLine ); /* create a new pico shader */ shader = PicoNewShader( model ); @@ -922,6 +918,7 @@ static picoModel_t *_obj_load( PM_PARAMS_LOAD ){ /* skip unparsed rest of line and continue */ _pico_parse_skip_rest( p ); } + /* free memory used by temporary vertexdata */ FreeObjVertexData( vertexData ); diff --git a/libs/picomodel/pm_terrain.c b/libs/picomodel/pm_terrain.c index 039af067..fb8cd89d 100644 --- a/libs/picomodel/pm_terrain.c +++ b/libs/picomodel/pm_terrain.c @@ -495,7 +495,7 @@ static picoModel_t *_terrain_load( PM_PARAMS_LOAD ) { } /* detox and set shader name */ - _pico_setfext( shader, "" ); + _pico_setfext( shader, NULL ); _pico_unixify( shader ); PicoSetShaderName( picoShader, shader ); _pico_free( shader );