]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - libs/picomodel/picointernal.c
pico: detect intentional material name and do not replace them with texture
[xonotic/netradiant.git] / libs / picomodel / picointernal.c
index 19950c1deeaae55300de80e05580a04cbd8092d9..0a8597f840416e107c87b2653da4e2765a561c0e 100644 (file)
@@ -694,6 +694,81 @@ 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;
+
+               /* Detect intentional material name to not replace it with texture name.
+
+               Reimplement commits by Garux:
+               https://github.com/Garux/netradiant-custom/commit/1bd3e7ae186b55fb61e3738d2493432c0b1f5a7b
+               https://github.com/Garux/netradiant-custom/commit/ea21eee2254fb2e667732d8f1b0f83c439a89bfa
+
+               This attempts to restore proper material behaviour when the mapper knows what he is doing,
+               also called Julius' case or correct case because Julius is always correctâ„¢
+               while keeping the fallback for other situations, also called newbie's case
+               which may be compatible with third-party tools not following Quake 3 conventions.
+
+               See: https://gitlab.com/xonotic/netradiant/-/merge_requests/179#note_777324051 */
+               if ( shadername && *shadername &&
+                       ( _pico_strnicmp( shadername, "models/", 7 ) == 0
+                       || _pico_strnicmp( shadername, "models\\", 7 ) == 0
+                       || _pico_strnicmp( shadername, "textures/", 9 ) == 0
+                       || _pico_strnicmp( shadername, "textures\\", 9 ) == 0 ) )
+               {
+                       _pico_deduce_shadername( model->fileName, shadername, model->shader[i] );
+               }
+               else 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