mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2024-12-11 13:11:47 +00:00
399 lines
10 KiB
C++
399 lines
10 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
|
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
|
|
|
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#pragma hdrstop
|
|
#include "../idlib/precompiled.h"
|
|
|
|
#include "tr_local.h"
|
|
#include "Model_local.h"
|
|
#include "Model_md3.h"
|
|
|
|
/***********************************************************************
|
|
|
|
idMD3Mesh
|
|
|
|
***********************************************************************/
|
|
|
|
#define LL(x) x=LittleLong(x)
|
|
|
|
/*
|
|
=================
|
|
idRenderModelMD3::InitFromFile
|
|
=================
|
|
*/
|
|
void idRenderModelMD3::InitFromFile( const char* fileName )
|
|
{
|
|
int i, j;
|
|
md3Header_t* pinmodel;
|
|
md3Frame_t* frame;
|
|
md3Surface_t* surf;
|
|
md3Shader_t* shader;
|
|
md3Triangle_t* tri;
|
|
md3St_t* st;
|
|
md3XyzNormal_t* xyz;
|
|
md3Tag_t* tag;
|
|
void* buffer;
|
|
int version;
|
|
int size;
|
|
|
|
|
|
name = fileName;
|
|
|
|
size = fileSystem->ReadFile( fileName, &buffer, NULL );
|
|
if( !size || size < 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
pinmodel = ( md3Header_t* )buffer;
|
|
|
|
version = LittleLong( pinmodel->version );
|
|
if( version != MD3_VERSION )
|
|
{
|
|
fileSystem->FreeFile( buffer );
|
|
common->Warning( "InitFromFile: %s has wrong version (%i should be %i)",
|
|
fileName, version, MD3_VERSION );
|
|
return;
|
|
}
|
|
|
|
size = LittleLong( pinmodel->ofsEnd );
|
|
dataSize += size;
|
|
md3 = ( md3Header_t* )Mem_Alloc( size, TAG_MODEL );
|
|
|
|
memcpy( md3, buffer, LittleLong( pinmodel->ofsEnd ) );
|
|
|
|
LL( md3->ident );
|
|
LL( md3->version );
|
|
LL( md3->numFrames );
|
|
LL( md3->numTags );
|
|
LL( md3->numSurfaces );
|
|
LL( md3->ofsFrames );
|
|
LL( md3->ofsTags );
|
|
LL( md3->ofsSurfaces );
|
|
LL( md3->ofsEnd );
|
|
|
|
if( md3->numFrames < 1 )
|
|
{
|
|
common->Warning( "InitFromFile: %s has no frames", fileName );
|
|
fileSystem->FreeFile( buffer );
|
|
return;
|
|
}
|
|
|
|
// swap all the frames
|
|
frame = ( md3Frame_t* )( ( byte* )md3 + md3->ofsFrames );
|
|
for( i = 0 ; i < md3->numFrames ; i++, frame++ )
|
|
{
|
|
frame->radius = LittleFloat( frame->radius );
|
|
for( j = 0 ; j < 3 ; j++ )
|
|
{
|
|
frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
|
|
frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
|
|
frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
|
|
}
|
|
}
|
|
|
|
// swap all the tags
|
|
tag = ( md3Tag_t* )( ( byte* )md3 + md3->ofsTags );
|
|
for( i = 0 ; i < md3->numTags * md3->numFrames ; i++, tag++ )
|
|
{
|
|
for( j = 0 ; j < 3 ; j++ )
|
|
{
|
|
tag->origin[j] = LittleFloat( tag->origin[j] );
|
|
tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
|
|
tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
|
|
tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
|
|
}
|
|
}
|
|
|
|
// swap all the surfaces
|
|
surf = ( md3Surface_t* )( ( byte* )md3 + md3->ofsSurfaces );
|
|
for( i = 0 ; i < md3->numSurfaces ; i++ )
|
|
{
|
|
|
|
LL( surf->ident );
|
|
LL( surf->flags );
|
|
LL( surf->numFrames );
|
|
LL( surf->numShaders );
|
|
LL( surf->numTriangles );
|
|
LL( surf->ofsTriangles );
|
|
LL( surf->numVerts );
|
|
LL( surf->ofsShaders );
|
|
LL( surf->ofsSt );
|
|
LL( surf->ofsXyzNormals );
|
|
LL( surf->ofsEnd );
|
|
|
|
if( surf->numVerts > SHADER_MAX_VERTEXES )
|
|
{
|
|
common->Error( "InitFromFile: %s has more than %i verts on a surface (%i)",
|
|
fileName, SHADER_MAX_VERTEXES, surf->numVerts );
|
|
}
|
|
if( surf->numTriangles * 3 > SHADER_MAX_INDEXES )
|
|
{
|
|
common->Error( "InitFromFile: %s has more than %i triangles on a surface (%i)",
|
|
fileName, SHADER_MAX_INDEXES / 3, surf->numTriangles );
|
|
}
|
|
|
|
// change to surface identifier
|
|
surf->ident = 0; //SF_MD3;
|
|
|
|
// lowercase the surface name so skin compares are faster
|
|
int slen = ( int )strlen( surf->name );
|
|
for( j = 0; j < slen; j++ )
|
|
{
|
|
surf->name[j] = tolower( surf->name[j] );
|
|
}
|
|
|
|
// strip off a trailing _1 or _2
|
|
// this is a crutch for q3data being a mess
|
|
j = strlen( surf->name );
|
|
if( j > 2 && surf->name[j - 2] == '_' )
|
|
{
|
|
surf->name[j - 2] = 0;
|
|
}
|
|
|
|
// register the shaders
|
|
shader = ( md3Shader_t* )( ( byte* )surf + surf->ofsShaders );
|
|
for( j = 0 ; j < surf->numShaders ; j++, shader++ )
|
|
{
|
|
const idMaterial* sh;
|
|
|
|
sh = declManager->FindMaterial( shader->name );
|
|
shader->shader = sh;
|
|
}
|
|
|
|
// swap all the triangles
|
|
tri = ( md3Triangle_t* )( ( byte* )surf + surf->ofsTriangles );
|
|
for( j = 0 ; j < surf->numTriangles ; j++, tri++ )
|
|
{
|
|
LL( tri->indexes[0] );
|
|
LL( tri->indexes[1] );
|
|
LL( tri->indexes[2] );
|
|
}
|
|
|
|
// swap all the ST
|
|
st = ( md3St_t* )( ( byte* )surf + surf->ofsSt );
|
|
for( j = 0 ; j < surf->numVerts ; j++, st++ )
|
|
{
|
|
st->st[0] = LittleFloat( st->st[0] );
|
|
st->st[1] = LittleFloat( st->st[1] );
|
|
}
|
|
|
|
// swap all the XyzNormals
|
|
xyz = ( md3XyzNormal_t* )( ( byte* )surf + surf->ofsXyzNormals );
|
|
for( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
|
|
{
|
|
xyz->xyz[0] = LittleShort( xyz->xyz[0] );
|
|
xyz->xyz[1] = LittleShort( xyz->xyz[1] );
|
|
xyz->xyz[2] = LittleShort( xyz->xyz[2] );
|
|
|
|
xyz->normal = LittleShort( xyz->normal );
|
|
}
|
|
|
|
|
|
// find the next surface
|
|
surf = ( md3Surface_t* )( ( byte* )surf + surf->ofsEnd );
|
|
}
|
|
|
|
fileSystem->FreeFile( buffer );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idRenderModelMD3::IsDynamicModel
|
|
=================
|
|
*/
|
|
dynamicModel_t idRenderModelMD3::IsDynamicModel() const
|
|
{
|
|
return DM_CACHED;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idRenderModelMD3::LerpMeshVertexes
|
|
=================
|
|
*/
|
|
void idRenderModelMD3::LerpMeshVertexes( srfTriangles_t* tri, const struct md3Surface_s* surf, const float backlerp, const int frame, const int oldframe ) const
|
|
{
|
|
short* oldXyz, *newXyz;
|
|
float oldXyzScale, newXyzScale;
|
|
int vertNum;
|
|
int numVerts;
|
|
|
|
newXyz = ( short* )( ( byte* )surf + surf->ofsXyzNormals ) + ( frame * surf->numVerts * 4 );
|
|
|
|
newXyzScale = MD3_XYZ_SCALE * ( 1.0 - backlerp );
|
|
|
|
numVerts = surf->numVerts;
|
|
|
|
if( backlerp == 0 )
|
|
{
|
|
//
|
|
// just copy the vertexes
|
|
//
|
|
for( vertNum = 0 ; vertNum < numVerts ; vertNum++, newXyz += 4 )
|
|
{
|
|
|
|
idDrawVert* outvert = &tri->verts[tri->numVerts];
|
|
|
|
outvert->xyz.x = newXyz[0] * newXyzScale;
|
|
outvert->xyz.y = newXyz[1] * newXyzScale;
|
|
outvert->xyz.z = newXyz[2] * newXyzScale;
|
|
|
|
tri->numVerts++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// interpolate and copy the vertexes
|
|
//
|
|
oldXyz = ( short* )( ( byte* )surf + surf->ofsXyzNormals ) + ( oldframe * surf->numVerts * 4 );
|
|
|
|
oldXyzScale = MD3_XYZ_SCALE * backlerp;
|
|
|
|
for( vertNum = 0 ; vertNum < numVerts ; vertNum++, oldXyz += 4, newXyz += 4 )
|
|
{
|
|
|
|
idDrawVert* outvert = &tri->verts[tri->numVerts];
|
|
|
|
// interpolate the xyz
|
|
outvert->xyz.x = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;
|
|
outvert->xyz.y = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;
|
|
outvert->xyz.z = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;
|
|
|
|
tri->numVerts++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============
|
|
idRenderModelMD3::InstantiateDynamicModel
|
|
=============
|
|
*/
|
|
idRenderModel* idRenderModelMD3::InstantiateDynamicModel( const struct renderEntity_s* ent, const viewDef_t* view, idRenderModel* cachedModel )
|
|
{
|
|
int i, j;
|
|
float backlerp;
|
|
int* triangles;
|
|
int indexes;
|
|
int numVerts;
|
|
md3Surface_t* surface;
|
|
int frame, oldframe;
|
|
idRenderModelStatic* staticModel;
|
|
|
|
if( cachedModel )
|
|
{
|
|
delete cachedModel;
|
|
cachedModel = NULL;
|
|
}
|
|
|
|
staticModel = new( TAG_MODEL ) idRenderModelStatic;
|
|
staticModel->bounds.Clear();
|
|
|
|
surface = ( md3Surface_t* )( ( byte* )md3 + md3->ofsSurfaces );
|
|
|
|
// TODO: these need set by an entity
|
|
frame = ent->shaderParms[SHADERPARM_MD3_FRAME]; // probably want to keep frames < 1000 or so
|
|
oldframe = ent->shaderParms[SHADERPARM_MD3_LASTFRAME];
|
|
backlerp = ent->shaderParms[SHADERPARM_MD3_BACKLERP];
|
|
|
|
for( i = 0; i < md3->numSurfaces; i++ )
|
|
{
|
|
|
|
srfTriangles_t* tri = R_AllocStaticTriSurf();
|
|
R_AllocStaticTriSurfVerts( tri, surface->numVerts );
|
|
R_AllocStaticTriSurfIndexes( tri, surface->numTriangles * 3 );
|
|
tri->bounds.Clear();
|
|
|
|
modelSurface_t surf;
|
|
|
|
surf.geometry = tri;
|
|
|
|
md3Shader_t* shaders = ( md3Shader_t* )( ( byte* )surface + surface->ofsShaders );
|
|
surf.shader = shaders->shader;
|
|
|
|
LerpMeshVertexes( tri, surface, backlerp, frame, oldframe );
|
|
|
|
triangles = ( int* )( ( byte* )surface + surface->ofsTriangles );
|
|
indexes = surface->numTriangles * 3;
|
|
for( j = 0 ; j < indexes ; j++ )
|
|
{
|
|
tri->indexes[j] = triangles[j];
|
|
}
|
|
tri->numIndexes += indexes;
|
|
|
|
const idVec2* texCoords = ( idVec2* )( ( byte* )surface + surface->ofsSt );
|
|
|
|
numVerts = surface->numVerts;
|
|
for( j = 0; j < numVerts; j++ )
|
|
{
|
|
tri->verts[j].SetTexCoord( texCoords[j] );
|
|
}
|
|
|
|
R_BoundTriSurf( tri );
|
|
|
|
staticModel->AddSurface( surf );
|
|
staticModel->bounds.AddPoint( surf.geometry->bounds[0] );
|
|
staticModel->bounds.AddPoint( surf.geometry->bounds[1] );
|
|
|
|
// find the next surface
|
|
surface = ( md3Surface_t* )( ( byte* )surface + surface->ofsEnd );
|
|
}
|
|
|
|
return staticModel;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idRenderModelMD3::Bounds
|
|
=====================
|
|
*/
|
|
|
|
idBounds idRenderModelMD3::Bounds( const struct renderEntity_s* ent ) const
|
|
{
|
|
idBounds ret;
|
|
|
|
ret.Clear();
|
|
|
|
if( !ent || !md3 )
|
|
{
|
|
// just give it the editor bounds
|
|
ret.AddPoint( idVec3( -10, -10, -10 ) );
|
|
ret.AddPoint( idVec3( 10, 10, 10 ) );
|
|
return ret;
|
|
}
|
|
|
|
md3Frame_t* frame = ( md3Frame_t* )( ( byte* )md3 + md3->ofsFrames );
|
|
|
|
ret.AddPoint( frame->bounds[0] );
|
|
ret.AddPoint( frame->bounds[1] );
|
|
|
|
return ret;
|
|
}
|
|
|