]> 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 018ee3a130295869d9294409545e6ca6a7792cb6..0a8597f840416e107c87b2653da4e2765a561c0e 100644 (file)
@@ -462,6 +462,8 @@ picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVe
        return _pico_normalize_vec( plane );
 }
 
+const picoColor_t picoColor_white = { 255, 255, 255, 255 };
+
 /* separate from _pico_set_vec4 */
 void _pico_set_color( picoColor_t c, int r, int g, int b, int a ){
        c[ 0 ] = r;
@@ -470,7 +472,7 @@ void _pico_set_color( picoColor_t c, int r, int g, int b, int a ){
        c[ 3 ] = a;
 }
 
-void _pico_copy_color( picoColor_t src, picoColor_t dest ){
+void _pico_copy_color( const picoColor_t src, picoColor_t dest ){
        dest[ 0 ] = src[ 0 ];
        dest[ 1 ] = src[ 1 ];
        dest[ 2 ] = src[ 2 ];
@@ -692,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