/* ==================== 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) loaded = R_LoadMD3(mod, lod, buf.u, name); else ri.Printf(PRINT_WARNING,"R_RegisterMD3: unknown fileid for %s\n", name); } ri.FS_FreeFile(buf.v); if(loaded) { mod->numLods++; numLoaded++; } else 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 ri.Printf(PRINT_WARNING,"R_RegisterMD3: couldn't load %s\n", name); #endif mod->type = MOD_BAD; return 0; }
/* ==================== RE_RegisterModel Loads in a model for the given name Zero will be returned if the model fails to load. An entry will be retained for failed models as an optimization to prevent disk rescanning if they are asked for again. ==================== */ qhandle_t RE_RegisterModel( const char *name ) { model_t *mod; unsigned *buf; int lod; int ident; qboolean loaded = qfalse; qhandle_t hModel; int numLoaded; char *fext, defex[] = "md3", filename[MAX_QPATH], namebuf[MAX_QPATH+20]; if ( !name || !name[0] ) { ri.Printf( PRINT_ALL, "RE_RegisterModel: NULL name\n" ); return 0; } if ( strlen( name ) >= MAX_QPATH ) { ri.Printf( PRINT_WARNING, "Model name exceeds MAX_QPATH\n" ); return 0; } // // search the currently loaded models // for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) { mod = tr.models[hModel]; if ( !strcmp( mod->name, name ) ) { if( mod->type == MOD_BAD ) { return 0; } return hModel; } } // allocate a new model_t if ( ( mod = R_AllocModel() ) == NULL ) { ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name); return 0; } // only set the name after the model has been successfully loaded strlcpy( mod->name, name, sizeof( mod->name ) ); // make sure the render thread is stopped R_SyncRenderThread(); mod->numLods = 0; // // load the files // numLoaded = 0; strcpy(filename, name); fext = strchr(filename, '.'); if(!fext) fext = defex; else { *fext = '\0'; fext++; } #ifdef RAVENMD4 if(!Q_stricmp(fext, "mdr")) { int filesize; filesize = ri.FS_ReadFile(name, (void **) &buf); if(!buf) { ri.Printf (PRINT_WARNING,"RE_RegisterModel: couldn't load %s\n", name); mod->type = MOD_BAD; return 0; } ident = LittleLong(*(unsigned *)buf); if(ident == MDR_IDENT) loaded = R_LoadMDR(mod, buf, filesize, name); ri.FS_FreeFile (buf); if(!loaded) { ri.Printf(PRINT_WARNING,"RE_RegisterModel: couldn't load mdr file %s\n", name); mod->type = MOD_BAD; return 0; } return mod->index; } #endif fext = defex; for ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) { if ( lod ) snprintf(namebuf, sizeof(namebuf), "%s_%d.%s", filename, lod, fext); else snprintf(namebuf, sizeof(namebuf), "%s.%s", filename, fext); ri.FS_ReadFile( namebuf, (void **)&buf ); if ( !buf ) { continue; } loadmodel = mod; ident = LittleLong(*(unsigned *)buf); if ( ident == MD4_IDENT ) { loaded = R_LoadMD4( mod, buf, name ); } else { if ( ident != MD3_IDENT ) { ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", name); goto fail; } loaded = R_LoadMD3( mod, lod, buf, name ); } ri.FS_FreeFile (buf); 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->value ) { // 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_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; }
/* ==================== RE_RegisterModel Loads in a model for the given name Zero will be returned if the model fails to load. An entry will be retained for failed models as an optimization to prevent disk rescanning if they are asked for again. ==================== */ static qhandle_t RE_RegisterModel_Actual( const char *name ) { model_t *mod; unsigned *buf; int lod; int ident; qboolean loaded; // qhandle_t hModel; int numLoaded; /* Ghoul2 Insert Start */ int hash; modelHash_t *mh; /* Ghoul2 Insert End */ if ( !name || !name[0] ) { ri.Printf( PRINT_WARNING, "RE_RegisterModel: NULL name\n" ); return 0; } if ( strlen( name ) >= MAX_QPATH ) { ri.Printf( PRINT_DEVELOPER, "Model name exceeds MAX_QPATH\n" ); return 0; } /* Ghoul2 Insert Start */ // if (!tr.registered) { // ri.Printf( PRINT_WARNING, "RE_RegisterModel (%s) called before ready!\n",name ); // return 0; // } // // search the currently loaded models // hash = generateHashValue(name, FILE_HASH_SIZE); // // see if the model is already loaded // for (mh=mhHashTable[hash]; mh; mh=mh->next) { if (Q_stricmp(mh->name, name) == 0) { if (tr.models[mh->handle]->type == MOD_BAD) { return 0; } return mh->handle; } } // for ( hModel = 1 ; hModel < tr.numModels; hModel++ ) { // mod = tr.models[hModel]; // if ( !strcmp( mod->name, name ) ) { // if( mod->type == MOD_BAD ) { // return 0; // } // return hModel; // } // } /* Ghoul2 Insert End */ // allocate a new model_t if ( ( mod = R_AllocModel() ) == NULL ) { ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name); return 0; } // only set the name after the model has been successfully loaded Q_strncpyz( mod->name, name, sizeof( mod->name ) ); #ifdef _NPATCH // Make sure we don't n-patch unless explicitly specified /* mod->npatchable = qfalse; for ( int i = 0; npatchableModels[i]; i++ ) { if ( stricmp(name, npatchableModels[i]) == 0 ) { mod->npatchable = qtrue; break; } } */ // new version, npatching is no controlled by the existance of a "*.npatch" file in the same place as *.glm extern cvar_t *r_ATI_NPATCH_available; if (r_ATI_NPATCH_available && r_ATI_NPATCH_available->integer && strstr(name,".glm")) { extern char *Filename_WithoutExt(const char *psFilename); fileHandle_t f; FS_FOpenFileRead( va("%s.npatch",Filename_WithoutExt(name)),&f, qtrue ); // qtrue = dup handle, so I can close it ok later mod->npatchable = !!f; if (f) { FS_FCloseFile(f); } } #endif // _NPATCH // make sure the render thread is stopped R_SyncRenderThread(); int iLODStart = 0; if (strstr (name, ".md3")) { iLODStart = MD3_MAX_LODS-1; //this loads the md3s in reverse so they can be biased } mod->numLods = 0; // // load the files // numLoaded = 0; for ( lod = iLODStart; lod >= 0 ; lod-- ) { char filename[1024]; strcpy( filename, name ); if ( lod != 0 ) { char namebuf[80]; if ( strrchr( filename, '.' ) ) { *strrchr( filename, '.' ) = 0; } sprintf( namebuf, "_%d.md3", lod ); strcat( filename, namebuf ); } qboolean bAlreadyCached = qfalse; if (!RE_RegisterModels_GetDiskFile(filename, (void **)&buf, &bAlreadyCached)) { continue; } //loadmodel = mod; // this seems to be fairly pointless // important that from now on we pass 'filename' instead of 'name' to all model load functions, // because 'filename' accounts for any LOD mangling etc so guarantees unique lookups for yet more // internal caching... // ident = *(unsigned *)buf; if (!bAlreadyCached) { ident = LittleLong(ident); } switch (ident) { // if you add any new types of model load in this switch-case, tell me, // or copy what I've done with the cache scheme (-ste). // case MD4_IDENT: loaded = R_LoadMD4( mod, buf, filename, bAlreadyCached ); break; case MDXA_IDENT: loaded = R_LoadMDXA( mod, buf, filename, bAlreadyCached ); break; case MDXM_IDENT: loaded = R_LoadMDXM( mod, buf, filename, bAlreadyCached ); break; case MD3_IDENT: loaded = R_LoadMD3( mod, lod, buf, filename, bAlreadyCached ); break; default: ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", filename); goto fail; } if (!bAlreadyCached){ // important to check!! ri.FS_FreeFile (buf); } 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]; } /* Ghoul2 Insert Start */ RE_InsertModelIntoHash(name, mod); return mod->index; /* Ghoul2 Insert End */ } 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; RE_InsertModelIntoHash(name, mod); return 0; }