r100 - in trunk/code: qcommon renderer

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Fri Sep 23 13:08:27 EDT 2005


Author: tma
Date: 2005-09-23 13:08:25 -0400 (Fri, 23 Sep 2005)
New Revision: 100

Modified:
   trunk/code/qcommon/qfiles.h
   trunk/code/renderer/tr_animation.c
   trunk/code/renderer/tr_image.c
   trunk/code/renderer/tr_local.h
   trunk/code/renderer/tr_main.c
   trunk/code/renderer/tr_mesh.c
   trunk/code/renderer/tr_model.c
   trunk/code/renderer/tr_shader.c
   trunk/code/renderer/tr_surface.c
Log:
* Applied Thilo Schulz's MDR patch


Modified: trunk/code/qcommon/qfiles.h
===================================================================
--- trunk/code/qcommon/qfiles.h	2005-09-23 02:59:15 UTC (rev 99)
+++ trunk/code/qcommon/qfiles.h	2005-09-23 17:08:25 UTC (rev 100)
@@ -299,7 +299,131 @@
 	int			ofsEnd;				// end of file
 } md4Header_t;
 
+/*
+ * Here are the definitions for Ravensoft's model format of md4. Raven stores their
+ * playermodels in .mdr files, in some games, which are pretty much like the md4
+ * format implemented by ID soft. It seems like ID's original md4 stuff is not used at all.
+ * MDR is being used in EliteForce, JediKnight2 and Soldiers of Fortune2 (I think).
+ * So this comes in handy for anyone who wants to make it possible to load player
+ * models from these games.
+ * This format has bone tags, which is similar to the thing you have in md3 I suppose.
+ * Raven has released their version of md3view under GPL enabling me to add support
+ * to this codebase. Thanks to Steven Howes aka Skinner for helping with example
+ * source code.
+ *
+ * - Thilo Schulz (arny at ats.s.bawue.de)
+ */
 
+// If you want to enable support for Raven's .mdr / md4 format, uncomment the next
+// line.
+//#define RAVENMD4
+
+#ifdef RAVENMD4
+
+#define MDR_IDENT	(('5'<<24)+('M'<<16)+('D'<<8)+'R')
+#define MDR_VERSION	2
+#define	MDR_MAX_BONES	128
+
+typedef struct {
+	int			boneIndex;	// these are indexes into the boneReferences,
+	float		   boneWeight;		// not the global per-frame bone list
+	vec3_t		offset;
+} mdrWeight_t;
+
+typedef struct {
+	vec3_t		normal;
+	vec2_t		texCoords;
+	int			numWeights;
+	mdrWeight_t	weights[1];		// variable sized
+} mdrVertex_t;
+
+typedef struct {
+	int			indexes[3];
+} mdrTriangle_t;
+
+typedef struct {
+	int			ident;
+
+	char		name[MAX_QPATH];	// polyset name
+	char		shader[MAX_QPATH];
+	int			shaderIndex;	// for in-game use
+
+	int			ofsHeader;	// this will be a negative number
+
+	int			numVerts;
+	int			ofsVerts;
+
+	int			numTriangles;
+	int			ofsTriangles;
+
+	// Bone references are a set of ints representing all the bones
+	// present in any vertex weights for this surface.  This is
+	// needed because a model may have surfaces that need to be
+	// drawn at different sort times, and we don't want to have
+	// to re-interpolate all the bones for each surface.
+	int			numBoneReferences;
+	int			ofsBoneReferences;
+
+	int			ofsEnd;		// next surface follows
+} mdrSurface_t;
+
+typedef struct {
+	float		matrix[3][4];
+} mdrBone_t;
+
+typedef struct {
+	vec3_t		bounds[2];		// bounds of all surfaces of all LOD's for this frame
+	vec3_t		localOrigin;		// midpoint of bounds, used for sphere cull
+	float		radius;			// dist from localOrigin to corner
+	char		name[16];
+	mdrBone_t	bones[1];		// [numBones]
+} mdrFrame_t;
+
+typedef struct {
+        unsigned char Comp[24]; // MC_COMP_BYTES is in MatComp.h, but don't want to couple
+} mdrCompBone_t;
+
+typedef struct {
+        vec3_t          bounds[2];		// bounds of all surfaces of all LOD's for this frame
+        vec3_t          localOrigin;		// midpoint of bounds, used for sphere cull
+        float           radius;			// dist from localOrigin to corner
+        mdrCompBone_t   bones[1];		// [numBones]
+} mdrCompFrame_t;
+
+typedef struct {
+	int			numSurfaces;
+	int			ofsSurfaces;		// first surface, others follow
+	int			ofsEnd;				// next lod follows
+} mdrLOD_t;
+
+typedef struct {
+        int                     boneIndex;
+        char            name[32];
+} mdrTag_t;
+
+typedef struct {
+	int			ident;
+	int			version;
+
+	char		name[MAX_QPATH];	// model name
+
+	// frames and bones are shared by all levels of detail
+	int			numFrames;
+	int			numBones;
+	int			ofsFrames;			// mdrFrame_t[numFrames]
+
+	// each level of detail has completely separate sets of surfaces
+	int			numLODs;
+	int			ofsLODs;
+
+        int                     numTags;
+        int                     ofsTags;
+
+	int			ofsEnd;				// end of file
+} mdrHeader_t;
+
+#endif
+
 /*
 ==============================================================================
 

Modified: trunk/code/renderer/tr_animation.c
===================================================================
--- trunk/code/renderer/tr_animation.c	2005-09-23 02:59:15 UTC (rev 99)
+++ trunk/code/renderer/tr_animation.c	2005-09-23 17:08:25 UTC (rev 100)
@@ -45,7 +45,7 @@
 	shader_t		*shader;
 	int				i;
 
-	header = tr.currentModel->md4;
+	header = (md4Header_t *) tr.currentModel->md4;
 	lod = (md4LOD_t *)( (byte *)header + header->ofsLODs );
 
 	surface = (md4Surface_t *)( (byte *)lod + lod->ofsSurfaces );
@@ -56,7 +56,6 @@
 	}
 }
 
-
 /*
 ==============
 RB_SurfaceAnim
@@ -90,9 +89,9 @@
 	frameSize = (size_t)( &((md4Frame_t *)0)->bones[ header->numBones ] );
 
 	frame = (md4Frame_t *)((byte *)header + header->ofsFrames + 
-		backEnd.currentEntity->e.frame * frameSize );
+			backEnd.currentEntity->e.frame * frameSize );
 	oldFrame = (md4Frame_t *)((byte *)header + header->ofsFrames + 
-		backEnd.currentEntity->e.oldframe * frameSize );
+			backEnd.currentEntity->e.oldframe * frameSize );
 
 	RB_CheckOverflow( surface->numVerts, surface->numTriangles * 3 );
 
@@ -115,7 +114,7 @@
 		bonePtr = bones;
 		for ( i = 0 ; i < header->numBones*12 ; i++ ) {
 			((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i]
-				+ backlerp * ((float *)oldFrame->bones)[i];
+					+ backlerp * ((float *)oldFrame->bones)[i];
 		}
 	}
 
@@ -169,3 +168,491 @@
 }
 
 
+#ifdef RAVENMD4
+
+// copied and adapted from tr_mesh.c
+
+/*
+=============
+R_MDRCullModel
+=============
+*/
+
+static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent ) {
+	vec3_t		bounds[2];
+	mdrFrame_t	*oldFrame, *newFrame;
+	int			i, frameSize;
+
+	frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
+	
+	// compute frame pointers
+	newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
+	oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe);
+
+	// cull bounding sphere ONLY if this is not an upscaled entity
+	if ( !ent->e.nonNormalizedAxes )
+	{
+		if ( ent->e.frame == ent->e.oldframe )
+		{
+			switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
+			{
+				// Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend
+				// we do. After all, the purpose of md4s are not that different, are they?
+				
+				case CULL_OUT:
+					tr.pc.c_sphere_cull_md3_out++;
+					return CULL_OUT;
+
+				case CULL_IN:
+					tr.pc.c_sphere_cull_md3_in++;
+					return CULL_IN;
+
+				case CULL_CLIP:
+					tr.pc.c_sphere_cull_md3_clip++;
+					break;
+			}
+		}
+		else
+		{
+			int sphereCull, sphereCullB;
+
+			sphereCull  = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
+			if ( newFrame == oldFrame ) {
+				sphereCullB = sphereCull;
+			} else {
+				sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
+			}
+
+			if ( sphereCull == sphereCullB )
+			{
+				if ( sphereCull == CULL_OUT )
+				{
+					tr.pc.c_sphere_cull_md3_out++;
+					return CULL_OUT;
+				}
+				else if ( sphereCull == CULL_IN )
+				{
+					tr.pc.c_sphere_cull_md3_in++;
+					return CULL_IN;
+				}
+				else
+				{
+					tr.pc.c_sphere_cull_md3_clip++;
+				}
+			}
+		}
+	}
+	
+	// calculate a bounding box in the current coordinate system
+	for (i = 0 ; i < 3 ; i++) {
+		bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
+		bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
+	}
+
+	switch ( R_CullLocalBox( bounds ) )
+	{
+		case CULL_IN:
+			tr.pc.c_box_cull_md3_in++;
+			return CULL_IN;
+		case CULL_CLIP:
+			tr.pc.c_box_cull_md3_clip++;
+			return CULL_CLIP;
+		case CULL_OUT:
+		default:
+			tr.pc.c_box_cull_md3_out++;
+			return CULL_OUT;
+	}
+}
+
+/*
+=================
+R_MDRComputeFogNum
+
+=================
+*/
+
+int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent ) {
+	int				i, j;
+	fog_t			*fog;
+	mdrFrame_t		*mdrFrame;
+	vec3_t			localOrigin;
+	int frameSize;
+
+	if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
+		return 0;
+	}
+	
+	frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
+
+	// FIXME: non-normalized axis issues
+	mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
+	VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin );
+	for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
+		fog = &tr.world->fogs[i];
+		for ( j = 0 ; j < 3 ; j++ ) {
+			if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] ) {
+				break;
+			}
+			if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] ) {
+				break;
+			}
+		}
+		if ( j == 3 ) {
+			return i;
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+==============
+R_MDRAddAnimSurfaces
+==============
+*/
+
+// much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c
+
+void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
+	mdrHeader_t		*header;
+	mdrSurface_t	*surface;
+	mdrLOD_t		*lod;
+	shader_t		*shader;
+	skin_t		*skin;
+	int				i, j;
+	int				lodnum = 0;
+	int				fogNum = 0;
+	int				cull;
+	qboolean	personalModel;
+
+	header = (mdrHeader_t *) tr.currentModel->md4;
+	
+	personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
+	
+	if ( ent->e.renderfx & RF_WRAP_FRAMES )
+	{
+		ent->e.frame %= header->numFrames;
+		ent->e.oldframe %= header->numFrames;
+	}	
+	
+	//
+	// Validate the frames so there is no chance of a crash.
+	// This will write directly into the entity structure, so
+	// when the surfaces are rendered, they don't need to be
+	// range checked again.
+	//
+	if ((ent->e.frame >= header->numFrames) 
+		|| (ent->e.frame < 0)
+		|| (ent->e.oldframe >= header->numFrames)
+		|| (ent->e.oldframe < 0) )
+	{
+		ri.Printf( PRINT_DEVELOPER, "R_MDRAddAnimSurfaces: no such frame %d to %d for '%s'\n",
+			   ent->e.oldframe, ent->e.frame, tr.currentModel->name );
+		ent->e.frame = 0;
+		ent->e.oldframe = 0;
+	}
+
+	//
+	// cull the entire model if merged bounding box of both frames
+	// is outside the view frustum.
+	//
+	cull = R_MDRCullModel (header, ent);
+	if ( cull == CULL_OUT ) {
+		return;
+	}	
+
+	// figure out the current LOD of the model we're rendering, and set the lod pointer respectively.
+	lodnum = R_ComputeLOD(ent);
+	// check whether this model has as that many LODs at all. If not, try the closest thing we got.
+	if(header->numLODs <= 0)
+		return;
+	if(header->numLODs <= lodnum)
+		lodnum = header->numLODs - 1;
+
+	lod = (mdrLOD_t *)( (byte *)header + header->ofsLODs);
+	for(i = 0; i < lodnum; i++)
+	{
+		lod = (mdrLOD_t *) ((byte *) lod + lod->ofsEnd);
+	}
+	
+	// set up lighting
+	if ( !personalModel || r_shadows->integer > 1 )
+	{
+		R_SetupEntityLighting( &tr.refdef, ent );
+	}
+
+	// fogNum?
+	fogNum = R_MDRComputeFogNum( header, ent );
+
+	surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces );
+
+	for ( i = 0 ; i < lod->numSurfaces ; i++ )
+	{
+		
+		if(ent->e.customShader)
+			shader = R_GetShaderByHandle(ent->e.customShader);
+		else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins)
+		{
+			skin = R_GetSkinByHandle(ent->e.customSkin);
+			shader = tr.defaultShader;
+			
+			for(j = 0; j < skin->numSurfaces; j++)
+			{
+				if (!strcmp(skin->surfaces[j]->name, surface->name))
+				{
+					shader = skin->surfaces[j]->shader;
+					break;
+				}
+			}
+		}
+		else if(surface->shaderIndex > 0)
+			shader = R_GetShaderByHandle( surface->shaderIndex );
+		else
+			shader = tr.defaultShader;
+
+		// we will add shadows even if the main object isn't visible in the view
+
+		// stencil shadows can't do personal models unless I polyhedron clip
+		if ( !personalModel
+		        && r_shadows->integer == 2
+			&& fogNum == 0
+			&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
+			&& shader->sort == SS_OPAQUE )
+		{
+			R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse );
+		}
+
+		// projection shadows work fine with personal models
+		if ( r_shadows->integer == 3
+			&& fogNum == 0
+			&& (ent->e.renderfx & RF_SHADOW_PLANE )
+			&& shader->sort == SS_OPAQUE )
+		{
+			R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
+		}
+
+		if (!personalModel)
+			R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse );
+
+		surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
+	}
+}
+
+/*
+==============
+RB_MDRSurfaceAnim
+==============
+*/
+void RB_MDRSurfaceAnim( md4Surface_t *surface )
+{
+	int				i, j, k;
+	float			frontlerp, backlerp;
+	int				*triangles;
+	int				indexes;
+	int				baseIndex, baseVertex;
+	int				numVerts;
+	mdrVertex_t		*v;
+	mdrHeader_t		*header;
+	mdrFrame_t		*frame;
+	mdrFrame_t		*oldFrame;
+	mdrBone_t		bones[MD4_MAX_BONES], *bonePtr, *bone;
+
+	int			frameSize;
+
+	// don't lerp if lerping off, or this is the only frame, or the last frame...
+	//
+	if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame) 
+	{
+		backlerp	= 0;	// if backlerp is 0, lerping is off and frontlerp is never used
+		frontlerp	= 1;
+	} 
+	else  
+	{
+		backlerp	= backEnd.currentEntity->e.backlerp;
+		frontlerp	= 1.0f - backlerp;
+	}
+
+	header = (mdrHeader_t *)((byte *)surface + surface->ofsHeader);
+
+	frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
+
+	frame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
+		backEnd.currentEntity->e.frame * frameSize );
+	oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames +
+		backEnd.currentEntity->e.oldframe * frameSize );
+
+	RB_CheckOverflow( surface->numVerts, surface->numTriangles );
+
+	triangles	= (int *) ((byte *)surface + surface->ofsTriangles);
+	indexes		= surface->numTriangles * 3;
+	baseIndex	= tess.numIndexes;
+	baseVertex	= tess.numVertexes;
+	
+	// Set up all triangles.
+	for (j = 0 ; j < indexes ; j++) 
+	{
+		tess.indexes[baseIndex + j] = baseVertex + triangles[j];
+	}
+	tess.numIndexes += indexes;
+
+	//
+	// lerp all the needed bones
+	//
+	if ( !backlerp ) 
+	{
+		// no lerping needed
+		bonePtr = frame->bones;
+	} 
+	else 
+	{
+		bonePtr = bones;
+		
+		for ( i = 0 ; i < header->numBones*12 ; i++ ) 
+		{
+			((float *)bonePtr)[i] = frontlerp * ((float *)frame->bones)[i] + backlerp * ((float *)oldFrame->bones)[i];
+		}
+	}
+
+	//
+	// deform the vertexes by the lerped bones
+	//
+	numVerts = surface->numVerts;
+	v = (mdrVertex_t *) ((byte *)surface + surface->ofsVerts);
+	for ( j = 0; j < numVerts; j++ ) 
+	{
+		vec3_t	tempVert, tempNormal;
+		mdrWeight_t	*w;
+
+		VectorClear( tempVert );
+		VectorClear( tempNormal );
+		w = v->weights;
+		for ( k = 0 ; k < v->numWeights ; k++, w++ ) 
+		{
+			bone = bonePtr + w->boneIndex;
+			
+			tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] );
+			tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] );
+			tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] );
+			
+			tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal );
+			tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal );
+			tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal );
+		}
+
+		tess.xyz[baseVertex + j][0] = tempVert[0];
+		tess.xyz[baseVertex + j][1] = tempVert[1];
+		tess.xyz[baseVertex + j][2] = tempVert[2];
+
+		tess.normal[baseVertex + j][0] = tempNormal[0];
+		tess.normal[baseVertex + j][1] = tempNormal[1];
+		tess.normal[baseVertex + j][2] = tempNormal[2];
+
+		tess.texCoords[baseVertex + j][0][0] = v->texCoords[0];
+		tess.texCoords[baseVertex + j][0][1] = v->texCoords[1];
+
+		v = (mdrVertex_t *)&v->weights[v->numWeights];
+	}
+
+	tess.numVertexes += surface->numVerts;
+}
+
+
+#define MC_MASK_X ((1<<(MC_BITS_X))-1)
+#define MC_MASK_Y ((1<<(MC_BITS_Y))-1)
+#define MC_MASK_Z ((1<<(MC_BITS_Z))-1)
+#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1)
+
+#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2))
+
+#define MC_POS_X (0)
+#define MC_SHIFT_X (0)
+
+#define MC_POS_Y ((((MC_BITS_X))/8))
+#define MC_SHIFT_Y ((((MC_BITS_X)%8)))
+
+#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8))
+#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8)))
+
+#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8))
+#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8)))
+
+#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8))
+#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8)))
+
+#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8))
+#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8)))
+
+#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8))
+#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8)))
+
+#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8))
+#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8)))
+
+#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8))
+#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8)))
+
+#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8))
+#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8)))
+
+#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8))
+#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8)))
+
+#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8))
+#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8)))
+
+void MC_UnCompress(float mat[3][4],const unsigned char * comp)
+{
+	int val;
+
+	val=(int)((unsigned short *)(comp))[0];
+	val-=1<<(MC_BITS_X-1);
+	mat[0][3]=((float)(val))*MC_SCALE_X;
+
+	val=(int)((unsigned short *)(comp))[1];
+	val-=1<<(MC_BITS_Y-1);
+	mat[1][3]=((float)(val))*MC_SCALE_Y;
+
+	val=(int)((unsigned short *)(comp))[2];
+	val-=1<<(MC_BITS_Z-1);
+	mat[2][3]=((float)(val))*MC_SCALE_Z;
+
+	val=(int)((unsigned short *)(comp))[3];
+	val-=1<<(MC_BITS_VECT-1);
+	mat[0][0]=((float)(val))*MC_SCALE_VECT;
+
+	val=(int)((unsigned short *)(comp))[4];
+	val-=1<<(MC_BITS_VECT-1);
+	mat[0][1]=((float)(val))*MC_SCALE_VECT;
+
+	val=(int)((unsigned short *)(comp))[5];
+	val-=1<<(MC_BITS_VECT-1);
+	mat[0][2]=((float)(val))*MC_SCALE_VECT;
+
+
+	val=(int)((unsigned short *)(comp))[6];
+	val-=1<<(MC_BITS_VECT-1);
+	mat[1][0]=((float)(val))*MC_SCALE_VECT;
+
+	val=(int)((unsigned short *)(comp))[7];
+	val-=1<<(MC_BITS_VECT-1);
+	mat[1][1]=((float)(val))*MC_SCALE_VECT;
+
+	val=(int)((unsigned short *)(comp))[8];
+	val-=1<<(MC_BITS_VECT-1);
+	mat[1][2]=((float)(val))*MC_SCALE_VECT;
+
+
+	val=(int)((unsigned short *)(comp))[9];
+	val-=1<<(MC_BITS_VECT-1);
+	mat[2][0]=((float)(val))*MC_SCALE_VECT;
+
+	val=(int)((unsigned short *)(comp))[10];
+	val-=1<<(MC_BITS_VECT-1);
+	mat[2][1]=((float)(val))*MC_SCALE_VECT;
+
+	val=(int)((unsigned short *)(comp))[11];
+	val-=1<<(MC_BITS_VECT-1);
+	mat[2][2]=((float)(val))*MC_SCALE_VECT;
+}
+#endif

Modified: trunk/code/renderer/tr_image.c
===================================================================
--- trunk/code/renderer/tr_image.c	2005-09-23 02:59:15 UTC (rev 99)
+++ trunk/code/renderer/tr_image.c	2005-09-23 17:08:25 UTC (rev 100)
@@ -1391,10 +1391,10 @@
   /* More stuff */
   JSAMPARRAY buffer;		/* Output row buffer */
   unsigned row_stride;		/* physical row width in output buffer */
-  unsigned pixelcount;
-  unsigned char *out, *out_converted;
+  unsigned pixelcount, memcount;
+  unsigned char *out;
   byte	*fbuffer;
-  byte  *bbuf;
+  byte  *buf;
 
   /* In this example we want to open the input file before doing anything else,
    * so that the setjmp() error recovery below can assume the file is open.
@@ -1454,9 +1454,7 @@
   /* JSAMPLEs per row in output buffer */
 
   pixelcount = cinfo.output_width * cinfo.output_height;
-  row_stride = cinfo.output_width * cinfo.output_components;
 
-
   if(!cinfo.output_width || !cinfo.output_height
       || ((pixelcount * 4) / cinfo.output_width) / 4 != cinfo.output_height
       || pixelcount > 0x1FFFFFFF || cinfo.output_components > 4) // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF
@@ -1465,8 +1463,11 @@
 		    cinfo.output_width, cinfo.output_height, pixelcount * 4, cinfo.output_components);
   }
 
-  out = ri.Malloc(pixelcount * 4);
+  memcount = pixelcount * 4;
+  row_stride = cinfo.output_width * cinfo.output_components;
 
+  out = ri.Malloc(memcount);
+
   *width = cinfo.output_width;
   *height = cinfo.output_height;
 
@@ -1481,45 +1482,42 @@
      * Here the array is only one element long, but you could ask for
      * more than one scanline at a time if that's more convenient.
      */
-	bbuf = ((out+(row_stride*cinfo.output_scanline)));
-	buffer = &bbuf;
+	buf = ((out+(row_stride*cinfo.output_scanline)));
+	buffer = &buf;
     (void) jpeg_read_scanlines(&cinfo, buffer, 1);
   }
   
+  buf = out;
+
   // If we are processing an 8-bit JPEG (greyscale), we'll have to convert
   // the greyscale values to RGBA.
   if(cinfo.output_components == 1)
   {
-  	int sindex, dindex = 0;
+  	int sindex = pixelcount, dindex = memcount;
 	unsigned char greyshade;
 
-	// allocate a new buffer for the transformed image
-  	out_converted = ri.Malloc(pixelcount*4);
-
-	for(sindex = 0; sindex < pixelcount; sindex++)
+	// Only pixelcount number of bytes have been written.
+	// Expand the color values over the rest of the buffer, starting
+	// from the end.
+	do
 	{
-		greyshade = out[sindex];
-		out_converted[dindex++] = greyshade;
-		out_converted[dindex++] = greyshade;
-		out_converted[dindex++] = greyshade;
-		out_converted[dindex++] = 255;		
-	}
-	
-	ri.Free(out);
-	out = out_converted;
+		greyshade = buf[--sindex];
+
+		buf[--dindex] = 255;
+		buf[--dindex] = greyshade;
+		buf[--dindex] = greyshade;
+		buf[--dindex] = greyshade;
+	} while(sindex);
   }
   else
   {
-	  // clear all the alphas to 255
-	  int	i, j;
-		byte	*buf;
+	// clear all the alphas to 255
+	int	i;
 
-		buf = out;
-
-	  j = cinfo.output_width * cinfo.output_height * 4;
-	  for ( i = 3 ; i < j ; i+=4 ) {
-		  buf[i] = 255;
-	  }
+	for ( i = 3 ; i < memcount ; i+=4 )
+	{
+		buf[i] = 255;
+	}
   }
 
   *pic = out;

Modified: trunk/code/renderer/tr_local.h
===================================================================
--- trunk/code/renderer/tr_local.h	2005-09-23 02:59:15 UTC (rev 99)
+++ trunk/code/renderer/tr_local.h	2005-09-23 17:08:25 UTC (rev 100)
@@ -525,6 +525,9 @@
 	SF_POLY,
 	SF_MD3,
 	SF_MD4,
+#ifdef RAVENMD4
+	SF_MDR,
+#endif
 	SF_FLARE,
 	SF_ENTITY,				// beams, rails, lightning, etc that can be determined by entity
 	SF_DISPLAY_LIST,
@@ -737,7 +740,10 @@
 	MOD_BAD,
 	MOD_BRUSH,
 	MOD_MESH,
-	MOD_MD4
+	MOD_MD4,
+#ifdef RAVENMD4
+	MOD_MDR
+#endif
 } modtype_t;
 
 typedef struct model_s {
@@ -748,7 +754,7 @@
 	int			dataSize;			// just for listing purposes
 	bmodel_t	*bmodel;			// only if type == MOD_BRUSH
 	md3Header_t	*md3[MD3_MAX_LODS];	// only if type == MOD_MESH
-	md4Header_t	*md4;				// only if type == MOD_MD4
+	void	*md4;				// only if type == (MOD_MD4 | MOD_MDR)
 
 	int			 numLods;
 } model_t;
@@ -1205,7 +1211,9 @@
 void	R_InitSkins( void );
 skin_t	*R_GetSkinByHandle( qhandle_t hSkin );
 
+int R_ComputeLOD( trRefEntity_t *ent );
 
+
 //
 // tr_shader.c
 //
@@ -1421,17 +1429,42 @@
 void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b );
 void RE_RenderScene( const refdef_t *fd );
 
+#ifdef RAVENMD4
 /*
 =============================================================
 
+UNCOMPRESSING BONES
+
+=============================================================
+*/
+
+#define MC_BITS_X (16)
+#define MC_BITS_Y (16)
+#define MC_BITS_Z (16)
+#define MC_BITS_VECT (16)
+
+#define MC_SCALE_X (1.0f/64)
+#define MC_SCALE_Y (1.0f/64)
+#define MC_SCALE_Z (1.0f/64)
+
+void MC_UnCompress(float mat[3][4],const unsigned char * comp);
+#endif
+
+/*
+=============================================================
+
 ANIMATED MODELS
 
 =============================================================
 */
 
-void R_MakeAnimModel( model_t *model );
+// void R_MakeAnimModel( model_t *model );      haven't seen this one really, so not needed I guess.
 void R_AddAnimSurfaces( trRefEntity_t *ent );
 void RB_SurfaceAnim( md4Surface_t *surfType );
+#ifdef RAVENMD4
+void R_MDRAddAnimSurfaces( trRefEntity_t *ent );
+void RB_MDRSurfaceAnim( md4Surface_t *surface );
+#endif
 
 /*
 =============================================================

Modified: trunk/code/renderer/tr_main.c
===================================================================
--- trunk/code/renderer/tr_main.c	2005-09-23 02:59:15 UTC (rev 99)
+++ trunk/code/renderer/tr_main.c	2005-09-23 17:08:25 UTC (rev 100)
@@ -1356,6 +1356,11 @@
 				case MOD_MD4:
 					R_AddAnimSurfaces( ent );
 					break;
+#ifdef RAVENMD4
+				case MOD_MDR:
+					R_MDRAddAnimSurfaces( ent );
+					break;
+#endif
 				case MOD_BRUSH:
 					R_AddBrushModelSurfaces( ent );
 					break;

Modified: trunk/code/renderer/tr_mesh.c
===================================================================
--- trunk/code/renderer/tr_mesh.c	2005-09-23 02:59:15 UTC (rev 99)
+++ trunk/code/renderer/tr_mesh.c	2005-09-23 17:08:25 UTC (rev 100)
@@ -168,6 +168,10 @@
 	float flod, lodscale;
 	float projectedRadius;
 	md3Frame_t *frame;
+#ifdef RAVENMD4
+	mdrHeader_t *mdr;
+	mdrFrame_t *mdrframe;
+#endif
 	int lod;
 
 	if ( tr.currentModel->numLods < 2 )
@@ -180,11 +184,28 @@
 		// multiple LODs exist, so compute projected bounding sphere
 		// and use that as a criteria for selecting LOD
 
-		frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
+#ifdef RAVENMD4
+		// This is an MDR model.
+		
+		if(tr.currentModel->md4)
+		{
+			int frameSize;
+			mdr = (mdrHeader_t *) tr.currentModel->md4;
+			frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]);
+			
+			mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame);
+			
+			radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]);
+		}
+		else
+#endif
+		{
+			frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
 
-		frame += ent->e.frame;
+			frame += ent->e.frame;
 
-		radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] );
+			radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] );
+		}
 
 		if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 )
 		{

Modified: trunk/code/renderer/tr_model.c
===================================================================
--- trunk/code/renderer/tr_model.c	2005-09-23 02:59:15 UTC (rev 99)
+++ trunk/code/renderer/tr_model.c	2005-09-23 17:08:25 UTC (rev 100)
@@ -27,6 +27,9 @@
 
 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 );
+#endif
 
 model_t	*loadmodel;
 
@@ -83,9 +86,10 @@
 	unsigned	*buf;
 	int			lod;
 	int			ident;
-	qboolean	loaded;
+	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" );
@@ -131,22 +135,56 @@
 	//
 	numLoaded = 0;
 
-	for ( lod = MD3_MAX_LODS - 1 ; lod >= 0 ; lod-- ) {
-		char filename[1024];
+	strcpy(filename, name);
 
-		strcpy( filename, name );
+	fext = strchr(filename, '.');
+	if(!fext)
+		fext = defex;
+	else
+	{
+		*fext = '\0';
+		fext++;
+	}
 
-		if ( lod != 0 ) {
-			char namebuf[80];
+#ifdef RAVENMD4
+	if(!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);
 
-			if ( strrchr( filename, '.' ) ) {
-				*strrchr( filename, '.' ) = 0;
-			}
-			sprintf( namebuf, "_%d.md3", lod );
-			strcat( filename, namebuf );
+		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
 
-		ri.FS_ReadFile( filename, (void **)&buf );
+	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;
 		}
@@ -369,9 +407,303 @@
 
 /*
 =================
+R_LoadMDR
+=================
+*/
+#ifdef RAVENMD4
+static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name ) 
+{
+	int					i, j, k, l;
+	mdrHeader_t			*pinmodel, *mdr;
+        mdrFrame_t			*frame;
+	mdrLOD_t			*lod, *curlod;
+	mdrSurface_t			*surf, *cursurf;
+	mdrTriangle_t			*tri, *curtri;
+	mdrVertex_t			*v, *curv;
+	mdrWeight_t			*weight, *curweight;
+	mdrTag_t			*tag, *curtag;
+	int					size;
+	shader_t			*sh;
+
+	pinmodel = (mdrHeader_t *)buffer;
+
+	pinmodel->version = LittleLong(pinmodel->version);
+	if (pinmodel->version != MDR_VERSION) 
+	{
+		ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION);
+		return qfalse;
+	}
+
+	size = LittleLong(pinmodel->ofsEnd);
+	
+	if(size > filesize)
+	{
+		ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name);
+		return qfalse;
+	}
+	
+	mod->type = MOD_MDR;
+
+	pinmodel->numFrames = LittleLong(pinmodel->numFrames);
+	pinmodel->numBones = LittleLong(pinmodel->numBones);
+	pinmodel->ofsFrames = LittleLong(pinmodel->ofsFrames);
+	
+	// This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame
+	// over and over again, we'll uncompress it in this function already, so we must adjust the size of the target md4.
+	if(pinmodel->ofsFrames < 0)
+	{
+		// mdrFrame_t is larger than mdrCompFrame_t:
+		size += pinmodel->numFrames * sizeof(frame->name);
+		// now add enough space for the uncompressed bones.
+		size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t)));
+	}
+	
+	mod->dataSize += size;
+	mod->md4 = mdr = ri.Hunk_Alloc( size, h_low );
+
+	// Copy all the values over from the file and fix endian issues in the process, if necessary.
+	
+	mdr->ident = LittleLong(pinmodel->ident);
+	mdr->version = pinmodel->version;	// Don't need to swap byte order on this one, we already did above.
+	Q_strncpyz(mdr->name, pinmodel->name, sizeof(mdr->name));
+	mdr->numFrames = pinmodel->numFrames;
+	mdr->numBones = pinmodel->numBones;
+	mdr->numLODs = LittleLong(pinmodel->numLODs);
+	mdr->numTags = LittleLong(pinmodel->numTags);
+	// We don't care about offset values, we'll generate them ourselves while loading.
+	
+	mod->numLods = mdr->numLODs;
+
+	if ( mdr->numFrames < 1 ) 
+	{
+		ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name);
+		return qfalse;
+	}
+
+	/* The first frame will be put into the first free space after the header */
+	frame = (mdrFrame_t *)(mdr + 1);
+	mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr);
+		
+	if (pinmodel->ofsFrames < 0)
+	{
+		mdrCompFrame_t *cframe;
+				
+		// compressed model...				
+		cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames);
+
+		for(i = 0; i < mdr->numFrames; i++)
+		{
+			for(j = 0; j < 3; j++)
+			{
+				frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]);
+				frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]);
+				frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]);
+			}
+
+			frame->radius = LittleFloat(cframe->radius);
+			frame->name[0] = '\0';	// No name supplied in the compressed version.
+			
+			for(j = 0; j < mdr->numBones; j++)
+			{
+				for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++)
+				{
+					// Do swapping for the uncompressing functions. They seem to use shorts
+					// values only, so I assume this will work. Never tested it on other
+					// platforms, though.
+					
+					((unsigned short *)(cframe->bones[j].Comp))[k] =
+						LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] );
+				}
+				
+				/* Now do the actual uncompressing */
+				MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp);
+			}
+			
+			// Next Frame...
+			cframe = (mdrCompFrame_t *) &cframe->bones[j];
+			frame = (mdrFrame_t *) &frame->bones[j];
+		}
+	}
+	else
+	{
+		mdrFrame_t *curframe;
+		
+		// uncompressed model...
+		//
+    
+		curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames);
+		
+		// swap all the frames
+		for ( i = 0 ; i < mdr->numFrames ; i++) 
+		{
+			for(j = 0; j < 3; j++)
+			{
+				frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]);
+				frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]);
+				frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]);
+			}
+			
+			frame->radius = LittleFloat(curframe->radius);
+			Q_strncpyz(frame->name, curframe->name, sizeof(frame->name));
+			
+			for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++) 
+			{
+				((float *)frame->bones)[j] = LittleFloat( ((float *)curframe->bones)[j] );
+			}
+			
+			curframe++;
+			frame++;
+		}
+	}
+	
+	// frame should now point to the first free address after all frames.
+	lod = (mdrLOD_t *) frame;
+	mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr);
+	
+	curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs));
+		
+	// swap all the LOD's
+	for ( l = 0 ; l < mdr->numLODs ; l++)
+	{
+		lod->numSurfaces = LittleLong(curlod->numSurfaces);
+		
+		// swap all the surfaces
+		surf = (mdrSurface_t *) (lod + 1);
+		lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod);
+		cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces));
+		
+		for ( i = 0 ; i < lod->numSurfaces ; i++) {
+			// first do some copying stuff
+			
+			surf->ident = SF_MDR;
+			Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name));
+			Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader));
+			
+			surf->ofsHeader = (byte *) mdr - (byte *) surf;
+			
+			surf->numVerts = LittleLong(cursurf->numVerts);
+			surf->numTriangles = LittleLong(cursurf->numTriangles);
+			// numBoneReferences and BoneReferences generally seem to be unused
+			
+			// now do the checks that may fail.
+			if ( surf->numVerts > SHADER_MAX_VERTEXES ) 
+			{
+				ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on a surface (%i)",
+					  mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
+				return qfalse;
+			}
+			if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) 
+			{
+				ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on a surface (%i)",
+					  mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
+				return qfalse;
+			}
+			// lowercase the surface name so skin compares are faster
+			Q_strlwr( surf->name );
+
+			// register the shaders
+			sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue);
+			if ( sh->defaultShader ) {
+				surf->shaderIndex = 0;
+			} else {
+				surf->shaderIndex = sh->index;
+			}
+			
+			// now copy the vertexes.
+			v = (mdrVertex_t *) (surf + 1);
+			surf->ofsVerts = (int)((byte *) v - (byte *) surf);
+			curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts));
+			
+			for(j = 0; j < surf->numVerts; j++)
+			{
+				v->normal[0] = LittleFloat(curv->normal[0]);
+				v->normal[1] = LittleFloat(curv->normal[1]);
+				v->normal[2] = LittleFloat(curv->normal[2]);
+				
+				v->texCoords[0] = LittleFloat(curv->texCoords[0]);
+				v->texCoords[1] = LittleFloat(curv->texCoords[1]);
+				
+				v->numWeights = LittleLong(curv->numWeights);
+				weight = &v->weights[0];
+				curweight = &curv->weights[0];
+				
+				// Now copy all the weights
+				for(k = 0; k < v->numWeights; k++)
+				{
+					weight->boneIndex = LittleLong(curweight->boneIndex);
+					weight->boneWeight = LittleFloat(curweight->boneWeight);
+					
+					weight->offset[0] = LittleFloat(curweight->offset[0]);
+					weight->offset[1] = LittleFloat(curweight->offset[1]);
+					weight->offset[2] = LittleFloat(curweight->offset[2]);
+					
+					weight++;
+					curweight++;
+				}
+				
+				v = (mdrVertex_t *) weight;
+				curv = (mdrVertex_t *) curweight;
+			}
+						
+			// we know the offset to the triangles now:
+			tri = (mdrTriangle_t *) v;
+			surf->ofsTriangles = (int)((byte *) tri - (byte *) surf);
+			curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles));
+			
+			for(j = 0; j < surf->numTriangles; j++)
+			{
+				tri->indexes[0] = curtri->indexes[0];
+				tri->indexes[1] = curtri->indexes[1];
+				tri->indexes[2] = curtri->indexes[2];
+				
+				tri++;
+				curtri++;
+			}
+			
+			// tri and curtri now point to the end of their surfaces.
+			surf->ofsEnd = (byte *) tri - (byte *) surf;
+
+			// find the next surface
+			surf = (mdrSurface_t *) tri;
+			cursurf = (mdrSurface_t *) curtri;
+		}
+
+		// surf points to the next lod now.
+		lod->ofsEnd = (int)((byte *) surf - (byte *) lod);
+				
+		lod = (mdrLOD_t *) surf;
+		curlod = (mdrLOD_t *) cursurf;
+	}
+	
+	// lod points to the first tag now, so update the offset too.
+	tag = (mdrTag_t *) lod;
+	mdr->ofsTags = (int)((byte *) tag - (byte *) mdr);
+	curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags));
+	
+	for (i = 0 ; i < mdr->numTags ; i++)
+	{
+		tag->boneIndex = LittleLong(curtag->boneIndex);
+		Q_strncpyz(tag->name, curtag->name, sizeof(tag->name));
+		
+		tag++;
+		curtag++;
+	}
+	
+	// And finally we know the offset to the end.
+	mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr);
+
+	// phew! we're done.
+	
+	return qtrue;
+}
+#endif
+
+/*
+=================
 R_LoadMD4
 =================
 */
+
 static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) {
 	int					i, j, k, lodindex;
 	md4Header_t			*pinmodel, *md4;
@@ -399,7 +731,7 @@
 	mod->dataSize += size;
 	md4 = mod->md4 = ri.Hunk_Alloc( size, h_low );
 
-	Com_Memcpy( md4, buffer, LittleLong(pinmodel->ofsEnd) );
+	Com_Memcpy(md4, buffer, size);
 
     LL(md4->ident);
     LL(md4->version);
@@ -408,7 +740,7 @@
     LL(md4->numLODs);
     LL(md4->ofsFrames);
     LL(md4->ofsLODs);
-    LL(md4->ofsEnd);
+    md4->ofsEnd = size;
 
 	if ( md4->numFrames < 1 ) {
 		ri.Printf( PRINT_WARNING, "R_LoadMD4: %s has no frames\n", mod_name );
@@ -520,7 +852,6 @@
 
 
 
-
 //=============================================================================
 
 /*
@@ -624,6 +955,59 @@
 	return NULL;
 }
 
+#ifdef RAVENMD4
+void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t * dest) 
+{
+	int				i;
+	int				frameSize;
+	mdrFrame_t		*frame;
+	mdrTag_t		*tag;
+
+	if ( framenum >= mod->numFrames ) 
+	{
+		// it is possible to have a bad frame while changing models, so don't error
+		framenum = mod->numFrames - 1;
+	}
+
+	tag = (mdrTag_t *)((byte *)mod + mod->ofsTags);
+	for ( i = 0 ; i < mod->numTags ; i++, tag++ )
+	{
+		if ( !strcmp( tag->name, tagName ) )
+		{
+			Q_strncpyz(dest->name, tag->name, sizeof(dest->name));
+
+			// uncompressed model...
+			//
+			frameSize = (long)( &((mdrFrame_t *)0)->bones[ mod->numBones ] );
+			frame = (mdrFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize );
+	#if 1
+			VectorCopy(&frame->bones[tag->boneIndex].matrix[0][0], dest->axis[0] );
+			VectorCopy(&frame->bones[tag->boneIndex].matrix[1][0], dest->axis[1] );
+			VectorCopy(&frame->bones[tag->boneIndex].matrix[2][0], dest->axis[2] );
+	#else
+			{
+				int j,k;
+				for (j=0;j<3;j++)
+				{
+					for (k=0;k<3;k++)
+						dest->axis[j][k]=frame->bones[tag->boneIndex].matrix[k][j];
+				}
+			}
+	#endif
+			dest->origin[0]=frame->bones[tag->boneIndex].matrix[0][3];
+			dest->origin[1]=frame->bones[tag->boneIndex].matrix[1][3];
+			dest->origin[2]=frame->bones[tag->boneIndex].matrix[2][3];				
+
+			return;
+		}
+	}
+
+	AxisClear( dest->axis );
+	VectorClear( dest->origin );
+	strcpy(dest->name,"");
+}
+#endif
+
 /*
 ================
 R_LerpTag
@@ -632,25 +1016,45 @@
 int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, 
 					 float frac, const char *tagName ) {
 	md3Tag_t	*start, *end;
+#ifdef RAVENMD4
+	md3Tag_t	start_space, end_space;
+#endif
 	int		i;
 	float		frontLerp, backLerp;
 	model_t		*model;
 
 	model = R_GetModelByHandle( handle );
-	if ( !model->md3[0] ) {
-		AxisClear( tag->axis );
-		VectorClear( tag->origin );
-		return qfalse;
-	}
+	if ( !model->md3[0] )
+	{
+#ifdef RAVENMD4
+		if(model->md4)
+		{
+			start = &start_space;
+			end = &end_space;
+			R_GetAnimTag((mdrHeader_t *) model->md4, startFrame, tagName, start);
+			R_GetAnimTag((mdrHeader_t *) model->md4, endFrame, tagName, end);
+		}
+		else
+#endif
+		{
 
-	start = R_GetTag( model->md3[0], startFrame, tagName );
-	end = R_GetTag( model->md3[0], endFrame, tagName );
-	if ( !start || !end ) {
-		AxisClear( tag->axis );
-		VectorClear( tag->origin );
-		return qfalse;
+			AxisClear( tag->axis );
+			VectorClear( tag->origin );
+			return qfalse;
+
+		}
 	}
-
+	else
+	{
+		start = R_GetTag( model->md3[0], startFrame, tagName );
+		end = R_GetTag( model->md3[0], endFrame, tagName );
+		if ( !start || !end ) {
+			AxisClear( tag->axis );
+			VectorClear( tag->origin );
+			return qfalse;
+		}
+	}
+	
 	frontLerp = frac;
 	backLerp = 1.0f - frac;
 
@@ -698,3 +1102,4 @@
 	VectorCopy( frame->bounds[0], mins );
 	VectorCopy( frame->bounds[1], maxs );
 }
+

Modified: trunk/code/renderer/tr_shader.c
===================================================================
--- trunk/code/renderer/tr_shader.c	2005-09-23 02:59:15 UTC (rev 99)
+++ trunk/code/renderer/tr_shader.c	2005-09-23 17:08:25 UTC (rev 100)
@@ -2746,7 +2746,6 @@
 	return sh->index;
 }
 
-
 /*
 ====================
 R_GetShaderByHandle

Modified: trunk/code/renderer/tr_surface.c
===================================================================
--- trunk/code/renderer/tr_surface.c	2005-09-23 02:59:15 UTC (rev 99)
+++ trunk/code/renderer/tr_surface.c	2005-09-23 17:08:25 UTC (rev 100)
@@ -1208,11 +1208,14 @@
 	(void(*)(void*))RB_SurfaceSkip,			// SF_SKIP, 
 	(void(*)(void*))RB_SurfaceFace,			// SF_FACE,
 	(void(*)(void*))RB_SurfaceGrid,			// SF_GRID,
-	(void(*)(void*))RB_SurfaceTriangles,	// SF_TRIANGLES,
-	(void(*)(void*))RB_SurfacePolychain,	// SF_POLY,
+	(void(*)(void*))RB_SurfaceTriangles,		// SF_TRIANGLES,
+	(void(*)(void*))RB_SurfacePolychain,		// SF_POLY,
 	(void(*)(void*))RB_SurfaceMesh,			// SF_MD3,
 	(void(*)(void*))RB_SurfaceAnim,			// SF_MD4,
+#ifdef RAVENMD4
+	(void(*)(void*))RB_MDRSurfaceAnim,		// SF_MDR,
+#endif
 	(void(*)(void*))RB_SurfaceFlare,		// SF_FLARE,
 	(void(*)(void*))RB_SurfaceEntity,		// SF_ENTITY
-	(void(*)(void*))RB_SurfaceDisplayList	// SF_DISPLAY_LIST
+	(void(*)(void*))RB_SurfaceDisplayList		// SF_DISPLAY_LIST
 };




More information about the quake3-commits mailing list