Index: code/renderer/tr_model.c =================================================================== --- code/renderer/tr_model.c (revision 1951) +++ code/renderer/tr_model.c (working copy) @@ -31,9 +31,161 @@ static qboolean R_LoadMDR (model_t *mod, void *buffer, int filesize, const char *name ); #endif -model_t *loadmodel; +/* +==================== +R_RegisterMD3 +==================== +*/ +qhandle_t R_RegisterMD3(const char *name, model_t *mod) { + union { + unsigned *u; + void *v; + } buf; + int lod; + int ident; + qboolean loaded = qfalse; + int numLoaded; + char filename[MAX_QPATH], namebuf[MAX_QPATH+20]; + char *fext, defex[] = "md3"; + numLoaded = 0; + + strcpy(filename, name); + + fext = strchr(filename, '.'); + if(!fext) + fext = defex; + else + { + *fext = '\0'; + fext++; + } + + for ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) { + if ( lod ) + Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext); + else + Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext); + + ri.FS_ReadFile( namebuf, &buf.v ); + if ( !buf.u ) { + continue; + } + + ident = LittleLong(*(unsigned *)buf.u); + if ( ident == MD4_IDENT ) { + loaded = R_LoadMD4( mod, buf.u, name ); + } else { + if ( ident != MD3_IDENT ) { + ri.Printf (PRINT_WARNING,"RE_RegisterMD3: unknown fileid for %s\n", name); + goto fail; + } + + loaded = R_LoadMD3( mod, lod, buf.u, name ); + } + + ri.FS_FreeFile (buf.v); + + if ( !loaded ) { + if ( lod == 0 ) { + goto fail; + } else { + break; + } + } else { + mod->numLods++; + numLoaded++; + // if we have a valid model and are biased + // so that we won't see any higher detail ones, + // stop loading them +// if ( lod <= r_lodbias->integer ) { +// break; +// } + } + } + + if ( numLoaded ) { + // duplicate into higher lod spots that weren't + // loaded, in case the user changes r_lodbias on the fly + for ( lod-- ; lod >= 0 ; lod-- ) { + mod->numLods++; + mod->md3[lod] = mod->md3[lod+1]; + } + + return mod->index; + } +#ifdef _DEBUG + else { + ri.Printf (PRINT_WARNING,"RE_RegisterMD3: couldn't load %s\n", name); + } +#endif + +fail: + mod->type = MOD_BAD; + return 0; +} + +#ifdef RAVENMD4 /* +==================== +R_RegisterMDR +==================== +*/ +qhandle_t R_RegisterMDR(const char *name, model_t *mod) { + union { + unsigned *u; + void *v; + } buf; + int ident; + qboolean loaded = qfalse; + int filesize; + + filesize = ri.FS_ReadFile(name, (void **) &buf.v); + if(!buf.u) + { + mod->type = MOD_BAD; + return 0; + } + + ident = LittleLong(*(unsigned *)buf.u); + if(ident == MDR_IDENT) + loaded = R_LoadMDR(mod, buf.u, filesize, name); + + ri.FS_FreeFile (buf.v); + + if(!loaded) + { + ri.Printf(PRINT_WARNING,"RE_RegisterMDR: couldn't load mdr file %s\n", name); + mod->type = MOD_BAD; + return 0; + } + + return mod->index; +} +#endif + +typedef struct +{ + char *ext; + qhandle_t (*ModelLoader)( const char *, model_t * ); +} modelExtToLoaderMap_t; + +// Note that the ordering indicates the order of preference used +// when there are multiple models of different formats available +static modelExtToLoaderMap_t modelLoaders[ ] = +{ +#ifdef RAVENMD4 + { "mdr", R_RegisterMDR }, +#endif + { "md4", R_RegisterMD3 }, + { "md3", R_RegisterMD3 } +}; + +static int numModelLoaders = ARRAY_LEN(modelLoaders); + +//=============================================================================== + +/* ** R_GetModelByHandle */ model_t *R_GetModelByHandle( qhandle_t index ) { @@ -83,16 +235,13 @@ */ qhandle_t RE_RegisterModel( const char *name ) { model_t *mod; - union { - unsigned *u; - void *v; - } buf; - int lod; - int ident; - qboolean loaded = qfalse; qhandle_t hModel; - int numLoaded; - char *fext, defex[] = "md3", filename[MAX_QPATH], namebuf[MAX_QPATH+20]; + qboolean orgNameFailed = qfalse; + int orgLoader = -1; + int i; + char localName[ MAX_QPATH ]; + const char *ext; + char *altName; if ( !name || !name[0] ) { ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" ); @@ -131,122 +280,73 @@ // make sure the render thread is stopped R_SyncRenderThread(); + mod->type = MOD_BAD; mod->numLods = 0; // // load the files // - numLoaded = 0; + Q_strncpyz( localName, name, MAX_QPATH ); - strcpy(filename, name); + ext = COM_GetExtension( localName ); - fext = strchr(filename, '.'); - if(!fext) - fext = defex; - else + if( *ext ) { - *fext = '\0'; - fext++; - } - -#ifdef RAVENMD4 - if(!Q_stricmp(fext, "mdr")) - { - int filesize; - - filesize = ri.FS_ReadFile(name, (void **) &buf.v); - if(!buf.u) + // Look for the correct loader and use it + for( i = 0; i < numModelLoaders; i++ ) { - ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name); - mod->type = MOD_BAD; - return 0; + if( !Q_stricmp( ext, modelLoaders[ i ].ext ) ) + { + // Load + hModel = modelLoaders[ i ].ModelLoader( localName, mod ); + break; + } } - - ident = LittleLong(*(unsigned *)buf.u); - if(ident == MDR_IDENT) - loaded = R_LoadMDR(mod, buf.u, filesize, name); - ri.FS_FreeFile (buf.v); - - if(!loaded) + // A loader was found + if( i < numModelLoaders ) { - ri.Printf(PRINT_WARNING,"RE_RegisterModel: couldn't load mdr file %s\n", name); - mod->type = MOD_BAD; - return 0; + if( !hModel ) + { + // Loader failed, most likely because the file isn't there; + // try again without the extension + orgNameFailed = qtrue; + orgLoader = i; + COM_StripExtension( name, localName, MAX_QPATH ); + } + else + { + // Something loaded + return mod->index; + } } - - return mod->index; } -#endif - fext = defex; + // Try and find a suitable match using all + // the model formats supported + for( i = 0; i < numModelLoaders; i++ ) + { + if (i == orgLoader) + continue; - for ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) { - if ( lod ) - Com_sprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext); - else - Com_sprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext); + altName = va( "%s.%s", localName, modelLoaders[ i ].ext ); - ri.FS_ReadFile( namebuf, &buf.v ); - if ( !buf.u ) { - continue; - } - - loadmodel = mod; - - ident = LittleLong(*(unsigned *)buf.u); - if ( ident == MD4_IDENT ) { - loaded = R_LoadMD4( mod, buf.u, name ); - } else { - if ( ident != MD3_IDENT ) { - ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", name); - goto fail; - } + // Load + hModel = modelLoaders[ i ].ModelLoader( altName, mod ); - loaded = R_LoadMD3( mod, lod, buf.u, name ); - } - - ri.FS_FreeFile (buf.v); - - if ( !loaded ) { - if ( lod == 0 ) { - goto fail; - } else { - break; + if( hModel ) + { + if( orgNameFailed ) + { + ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n", + name, altName ); } - } else { - mod->numLods++; - numLoaded++; - // if we have a valid model and are biased - // so that we won't see any higher detail ones, - // stop loading them -// if ( lod <= r_lodbias->integer ) { -// break; -// } - } - } - if ( numLoaded ) { - // duplicate into higher lod spots that weren't - // loaded, in case the user changes r_lodbias on the fly - for ( lod-- ; lod >= 0 ; lod-- ) { - mod->numLods++; - mod->md3[lod] = mod->md3[lod+1]; + break; } - - return mod->index; } -#ifdef _DEBUG - else { - ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name); - } -#endif -fail: - // we still keep the model_t around, so if the model name is asked for - // again, we won't bother scanning the filesystem - mod->type = MOD_BAD; - return 0; + return hModel; }