diff options
-rw-r--r-- | code/qcommon/qfiles.h | 124 | ||||
-rw-r--r-- | code/renderer/tr_animation.c | 497 | ||||
-rw-r--r-- | code/renderer/tr_image.c | 60 | ||||
-rw-r--r-- | code/renderer/tr_local.h | 39 | ||||
-rw-r--r-- | code/renderer/tr_main.c | 5 | ||||
-rw-r--r-- | code/renderer/tr_mesh.c | 27 | ||||
-rw-r--r-- | code/renderer/tr_model.c | 459 | ||||
-rw-r--r-- | code/renderer/tr_shader.c | 1 | ||||
-rw-r--r-- | code/renderer/tr_surface.c | 9 |
9 files changed, 1148 insertions, 73 deletions
diff --git a/code/qcommon/qfiles.h b/code/qcommon/qfiles.h index c0d5968..3fd44ed 100644 --- a/code/qcommon/qfiles.h +++ b/code/qcommon/qfiles.h @@ -299,6 +299,130 @@ typedef struct { 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@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 /* ============================================================================== diff --git a/code/renderer/tr_animation.c b/code/renderer/tr_animation.c index 61b9057..fda0f11 100644 --- a/code/renderer/tr_animation.c +++ b/code/renderer/tr_animation.c @@ -45,7 +45,7 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) { 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 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) { } } - /* ============== RB_SurfaceAnim @@ -90,9 +89,9 @@ void RB_SurfaceAnim( md4Surface_t *surface ) { 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 @@ void RB_SurfaceAnim( md4Surface_t *surface ) { 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 @@ void RB_SurfaceAnim( md4Surface_t *surface ) { } +#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 diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index 8094a16..630b886 100644 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -1391,10 +1391,10 @@ static void LoadJPG( const char *filename, unsigned char **pic, int *width, int /* 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,8 +1454,6 @@ static void LoadJPG( const char *filename, unsigned char **pic, int *width, int /* 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 @@ -1465,7 +1463,10 @@ static void LoadJPG( const char *filename, unsigned char **pic, int *width, int 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 @@ static void LoadJPG( const char *filename, unsigned char **pic, int *width, int * 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; diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index fc1b464..e29feba 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -525,6 +525,9 @@ typedef enum { 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 @@ typedef enum { 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 @@ typedef struct model_s { 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,6 +1211,8 @@ int R_SumOfUsedImages( void ); void R_InitSkins( void ); skin_t *R_GetSkinByHandle( qhandle_t hSkin ); +int R_ComputeLOD( trRefEntity_t *ent ); + // // tr_shader.c @@ -1421,6 +1429,27 @@ void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, fl 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 + /* ============================================================= @@ -1429,9 +1458,13 @@ 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 /* ============================================================= diff --git a/code/renderer/tr_main.c b/code/renderer/tr_main.c index 536cb5a..187e351 100644 --- a/code/renderer/tr_main.c +++ b/code/renderer/tr_main.c @@ -1356,6 +1356,11 @@ void R_AddEntitySurfaces (void) { case MOD_MD4: R_AddAnimSurfaces( ent ); break; +#ifdef RAVENMD4 + case MOD_MDR: + R_MDRAddAnimSurfaces( ent ); + break; +#endif case MOD_BRUSH: R_AddBrushModelSurfaces( ent ); break; diff --git a/code/renderer/tr_mesh.c b/code/renderer/tr_mesh.c index 155b4e6..e1e261e 100644 --- a/code/renderer/tr_mesh.c +++ b/code/renderer/tr_mesh.c @@ -168,6 +168,10 @@ int R_ComputeLOD( trRefEntity_t *ent ) { 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 @@ int R_ComputeLOD( trRefEntity_t *ent ) { // 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 ) { diff --git a/code/renderer/tr_model.c b/code/renderer/tr_model.c index 2b92917..80b8094 100644 --- a/code/renderer/tr_model.c +++ b/code/renderer/tr_model.c @@ -27,6 +27,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 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 @@ qhandle_t RE_RegisterModel( const char *name ) { 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 @@ qhandle_t RE_RegisterModel( const char *name ) { // 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 + + 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( filename, (void **)&buf ); + ri.FS_ReadFile( namebuf, (void **)&buf ); if ( !buf ) { continue; } @@ -369,9 +407,303 @@ static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_ /* ================= +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 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) { 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 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) { 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 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) { - //============================================================================= /* @@ -624,6 +955,59 @@ static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) { 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 @@ R_LerpTag 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 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { VectorCopy( frame->bounds[0], mins ); VectorCopy( frame->bounds[1], maxs ); } + diff --git a/code/renderer/tr_shader.c b/code/renderer/tr_shader.c index 5376fa2..3de2bba 100644 --- a/code/renderer/tr_shader.c +++ b/code/renderer/tr_shader.c @@ -2746,7 +2746,6 @@ qhandle_t RE_RegisterShaderNoMip( const char *name ) { return sh->index; } - /* ==================== R_GetShaderByHandle diff --git a/code/renderer/tr_surface.c b/code/renderer/tr_surface.c index 2f4d1c9..7b5e764 100644 --- a/code/renderer/tr_surface.c +++ b/code/renderer/tr_surface.c @@ -1208,11 +1208,14 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { (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 }; |