summaryrefslogtreecommitdiff
path: root/src/renderer/tr_model.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/renderer/tr_model.c')
-rw-r--r--src/renderer/tr_model.c416
1 files changed, 291 insertions, 125 deletions
diff --git a/src/renderer/tr_model.c b/src/renderer/tr_model.c
index b02d52a4..2933e7e0 100644
--- a/src/renderer/tr_model.c
+++ b/src/renderer/tr_model.c
@@ -26,13 +26,194 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define LL(x) x=LittleLong(x)
-static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *name );
-static qboolean R_LoadMD4 (model_t *mod, void *buffer, const char *name );
+static qboolean R_LoadMD3(model_t *mod, int lod, void *buffer, const char *name );
+static qboolean R_LoadMD4(model_t *mod, void *buffer, const char *name );
#ifdef RAVENMD4
-static qboolean R_LoadMDR (model_t *mod, void *buffer, int filesize, const char *name );
+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)
+ loaded = R_LoadMD3(mod, lod, buf.u, name);
+ else
+ ri.Printf(PRINT_WARNING,"RE_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,"RE_RegisterMD3: couldn't load %s\n", name);
+#endif
+
+ 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
+
+/*
+====================
+R_RegisterIQM
+====================
+*/
+qhandle_t R_RegisterIQM(const char *name, model_t *mod)
+{
+ union {
+ unsigned *u;
+ void *v;
+ } buf;
+ qboolean loaded = qfalse;
+ int filesize;
+
+ filesize = ri.FS_ReadFile(name, (void **) &buf.v);
+ if(!buf.u)
+ {
+ mod->type = MOD_BAD;
+ return 0;
+ }
+
+ loaded = R_LoadIQM(mod, buf.u, filesize, name);
+
+ ri.FS_FreeFile (buf.v);
+
+ if(!loaded)
+ {
+ ri.Printf(PRINT_WARNING,"RE_RegisterIQM: couldn't load mdr file %s\n", name);
+ mod->type = MOD_BAD;
+ return 0;
+ }
+
+ return mod->index;
+}
+
+
+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 },
+ { "iqm", R_RegisterIQM }
+};
+
+static int numModelLoaders = ARRAY_LEN(modelLoaders);
+
+//===============================================================================
/*
** R_GetModelByHandle
@@ -84,16 +265,13 @@ asked for again.
*/
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" );
@@ -132,125 +310,75 @@ qhandle_t RE_RegisterModel( const char *name ) {
// 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;
-
- 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 ) {
+ // Try and find a suitable match using all
+ // the model formats supported
+ for( i = 0; i < numModelLoaders; i++ )
+ {
+ if (i == orgLoader)
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;
- }
- loaded = R_LoadMD3( mod, lod, buf.u, name );
- }
-
- ri.FS_FreeFile (buf.v);
+ altName = va( "%s.%s", localName, modelLoaders[ i ].ext );
- if ( !loaded ) {
- if ( lod == 0 ) {
- goto fail;
- } else {
- break;
+ // Load
+ hModel = modelLoaders[ i ].ModelLoader( altName, mod );
+
+ 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;
}
-
/*
=================
R_LoadMD3
@@ -780,7 +908,7 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) {
mod->type = MOD_MD4;
size = LittleLong(pinmodel->ofsEnd);
mod->dataSize += size;
- md4 = mod->md4 = ri.Hunk_Alloc( size, h_low );
+ mod->modelData = md4 = ri.Hunk_Alloc( size, h_low );
Com_Memcpy(md4, buffer, size);
@@ -1071,16 +1199,20 @@ int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFram
if ( !model->md3[0] )
{
#ifdef RAVENMD4
- if(model->md4)
+ if(model->type == MOD_MDR)
{
start = &start_space;
end = &end_space;
- R_GetAnimTag((mdrHeader_t *) model->md4, startFrame, tagName, start);
- R_GetAnimTag((mdrHeader_t *) model->md4, endFrame, tagName, end);
+ R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, start);
+ R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, end);
}
else
#endif
- {
+ if( model->type == MOD_IQM ) {
+ return R_IQMLerpTag( tag, model->modelData,
+ startFrame, endFrame,
+ frac, tagName );
+ } else {
AxisClear( tag->axis );
VectorClear( tag->origin );
@@ -1122,28 +1254,62 @@ R_ModelBounds
*/
void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) {
model_t *model;
- md3Header_t *header;
- md3Frame_t *frame;
model = R_GetModelByHandle( handle );
- if ( model->bmodel ) {
+ if(model->type == MOD_BRUSH) {
VectorCopy( model->bmodel->bounds[0], mins );
VectorCopy( model->bmodel->bounds[1], maxs );
+
return;
- }
+ } else if (model->type == MOD_MESH) {
+ md3Header_t *header;
+ md3Frame_t *frame;
+
+ header = model->md3[0];
+ frame = (md3Frame_t *) ((byte *)header + header->ofsFrames);
- if ( !model->md3[0] ) {
- VectorClear( mins );
- VectorClear( maxs );
+ VectorCopy( frame->bounds[0], mins );
+ VectorCopy( frame->bounds[1], maxs );
+
return;
- }
+ } else if (model->type == MOD_MD4) {
+ md4Header_t *header;
+ md4Frame_t *frame;
+
+ header = (md4Header_t *)model->modelData;
+ frame = (md4Frame_t *) ((byte *)header + header->ofsFrames);
+
+ VectorCopy( frame->bounds[0], mins );
+ VectorCopy( frame->bounds[1], maxs );
+
+ return;
+#ifdef RAVENMD4
+ } else if (model->type == MOD_MDR) {
+ mdrHeader_t *header;
+ mdrFrame_t *frame;
- header = model->md3[0];
+ header = (mdrHeader_t *)model->modelData;
+ frame = (mdrFrame_t *) ((byte *)header + header->ofsFrames);
- frame = (md3Frame_t *)( (byte *)header + header->ofsFrames );
+ VectorCopy( frame->bounds[0], mins );
+ VectorCopy( frame->bounds[1], maxs );
+
+ return;
+#endif
+ } else if(model->type == MOD_IQM) {
+ iqmData_t *iqmData;
+
+ iqmData = model->modelData;
- VectorCopy( frame->bounds[0], mins );
- VectorCopy( frame->bounds[1], maxs );
-}
+ if(iqmData->bounds)
+ {
+ VectorCopy(iqmData->bounds, mins);
+ VectorCopy(iqmData->bounds + 3, maxs);
+ return;
+ }
+ }
+ VectorClear( mins );
+ VectorClear( maxs );
+}