mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2024-11-24 21:12:03 +00:00
354 lines
14 KiB
C
354 lines
14 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.
|
||
|
|
||
|
===========================================================================
|
||
|
*/
|
||
|
|
||
|
#ifndef __CLIP_H__
|
||
|
#define __CLIP_H__
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
Handles collision detection with the world and between physics objects.
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
#define CLIPMODEL_ID_TO_JOINT_HANDLE( id ) ( ( id ) >= 0 ? INVALID_JOINT : ((jointHandle_t) ( -1 - id )) )
|
||
|
#define JOINT_HANDLE_TO_CLIPMODEL_ID( id ) ( -1 - id )
|
||
|
|
||
|
class idClip;
|
||
|
class idClipModel;
|
||
|
class idEntity;
|
||
|
|
||
|
//===============================================================
|
||
|
//
|
||
|
// idClipModel
|
||
|
//
|
||
|
//===============================================================
|
||
|
|
||
|
class idClipModel {
|
||
|
|
||
|
friend class idClip;
|
||
|
|
||
|
public:
|
||
|
idClipModel();
|
||
|
explicit idClipModel( const char *name );
|
||
|
explicit idClipModel( const idTraceModel &trm );
|
||
|
explicit idClipModel( const idTraceModel &trm, bool persistantThroughSave );
|
||
|
explicit idClipModel( const int renderModelHandle );
|
||
|
explicit idClipModel( const idClipModel *model );
|
||
|
~idClipModel();
|
||
|
|
||
|
bool LoadModel( const char *name );
|
||
|
void LoadModel( const idTraceModel &trm, bool persistantThroughSave = true );
|
||
|
void LoadModel( const int renderModelHandle );
|
||
|
|
||
|
void Save( idSaveGame *savefile ) const;
|
||
|
void Restore( idRestoreGame *savefile );
|
||
|
|
||
|
void Link( idClip &clp ); // must have been linked with an entity and id before
|
||
|
void Link( idClip &clp, idEntity *ent, int newId, const idVec3 &newOrigin, const idMat3 &newAxis, int renderModelHandle = -1 );
|
||
|
void Unlink(); // unlink from sectors
|
||
|
void SetPosition( const idVec3 &newOrigin, const idMat3 &newAxis ); // unlinks the clip model
|
||
|
void Translate( const idVec3 &translation ); // unlinks the clip model
|
||
|
void Rotate( const idRotation &rotation ); // unlinks the clip model
|
||
|
void Enable(); // enable for clipping
|
||
|
void Disable(); // keep linked but disable for clipping
|
||
|
void SetMaterial( const idMaterial *m );
|
||
|
const idMaterial * GetMaterial() const;
|
||
|
void SetContents( int newContents ); // override contents
|
||
|
int GetContents() const;
|
||
|
void SetEntity( idEntity *newEntity );
|
||
|
idEntity * GetEntity() const;
|
||
|
void SetId( int newId );
|
||
|
int GetId() const;
|
||
|
void SetOwner( idEntity *newOwner );
|
||
|
idEntity * GetOwner() const;
|
||
|
const idBounds & GetBounds() const;
|
||
|
const idBounds & GetAbsBounds() const;
|
||
|
const idVec3 & GetOrigin() const;
|
||
|
const idMat3 & GetAxis() const;
|
||
|
bool IsTraceModel() const; // returns true if this is a trace model
|
||
|
bool IsRenderModel() const; // returns true if this is a render model
|
||
|
bool IsLinked() const; // returns true if the clip model is linked
|
||
|
bool IsEnabled() const; // returns true if enabled for collision detection
|
||
|
bool IsEqual( const idTraceModel &trm ) const;
|
||
|
cmHandle_t Handle() const; // returns handle used to collide vs this model
|
||
|
const idTraceModel * GetTraceModel() const;
|
||
|
void GetMassProperties( const float density, float &mass, idVec3 ¢erOfMass, idMat3 &inertiaTensor ) const;
|
||
|
|
||
|
static cmHandle_t CheckModel( const char *name );
|
||
|
static void ClearTraceModelCache();
|
||
|
static int TraceModelCacheSize();
|
||
|
|
||
|
static void SaveTraceModels( idSaveGame *savefile );
|
||
|
static void RestoreTraceModels( idRestoreGame *savefile );
|
||
|
|
||
|
private:
|
||
|
bool enabled; // true if this clip model is used for clipping
|
||
|
idEntity * entity; // entity using this clip model
|
||
|
int id; // id for entities that use multiple clip models
|
||
|
idEntity * owner; // owner of the entity that owns this clip model
|
||
|
idVec3 origin; // origin of clip model
|
||
|
idMat3 axis; // orientation of clip model
|
||
|
idBounds bounds; // bounds
|
||
|
idBounds absBounds; // absolute bounds
|
||
|
const idMaterial * material; // material for trace models
|
||
|
int contents; // all contents ored together
|
||
|
cmHandle_t collisionModelHandle; // handle to collision model
|
||
|
int traceModelIndex; // trace model used for collision detection
|
||
|
int renderModelHandle; // render model def handle
|
||
|
|
||
|
struct clipLink_s * clipLinks; // links into sectors
|
||
|
int touchCount;
|
||
|
|
||
|
void Init(); // initialize
|
||
|
void Link_r( struct clipSector_s *node );
|
||
|
|
||
|
static int AllocTraceModel( const idTraceModel &trm, bool persistantThroughSaves = true );
|
||
|
static void FreeTraceModel( int traceModelIndex );
|
||
|
static idTraceModel * GetCachedTraceModel( int traceModelIndex );
|
||
|
static int GetTraceModelHashKey( const idTraceModel &trm );
|
||
|
static struct trmCache_s * GetTraceModelEntry( int traceModelIndex );
|
||
|
};
|
||
|
|
||
|
|
||
|
ID_INLINE void idClipModel::Translate( const idVec3 &translation ) {
|
||
|
Unlink();
|
||
|
origin += translation;
|
||
|
}
|
||
|
|
||
|
ID_INLINE void idClipModel::Rotate( const idRotation &rotation ) {
|
||
|
Unlink();
|
||
|
origin *= rotation;
|
||
|
axis *= rotation.ToMat3();
|
||
|
}
|
||
|
|
||
|
ID_INLINE void idClipModel::Enable() {
|
||
|
enabled = true;
|
||
|
}
|
||
|
|
||
|
ID_INLINE void idClipModel::Disable() {
|
||
|
enabled = false;
|
||
|
}
|
||
|
|
||
|
ID_INLINE void idClipModel::SetMaterial( const idMaterial *m ) {
|
||
|
material = m;
|
||
|
}
|
||
|
|
||
|
ID_INLINE const idMaterial * idClipModel::GetMaterial() const {
|
||
|
return material;
|
||
|
}
|
||
|
|
||
|
ID_INLINE void idClipModel::SetContents( int newContents ) {
|
||
|
contents = newContents;
|
||
|
}
|
||
|
|
||
|
ID_INLINE int idClipModel::GetContents() const {
|
||
|
return contents;
|
||
|
}
|
||
|
|
||
|
ID_INLINE void idClipModel::SetEntity( idEntity *newEntity ) {
|
||
|
entity = newEntity;
|
||
|
}
|
||
|
|
||
|
ID_INLINE idEntity *idClipModel::GetEntity() const {
|
||
|
return entity;
|
||
|
}
|
||
|
|
||
|
ID_INLINE void idClipModel::SetId( int newId ) {
|
||
|
id = newId;
|
||
|
}
|
||
|
|
||
|
ID_INLINE int idClipModel::GetId() const {
|
||
|
return id;
|
||
|
}
|
||
|
|
||
|
ID_INLINE void idClipModel::SetOwner( idEntity *newOwner ) {
|
||
|
owner = newOwner;
|
||
|
}
|
||
|
|
||
|
ID_INLINE idEntity *idClipModel::GetOwner() const {
|
||
|
return owner;
|
||
|
}
|
||
|
|
||
|
ID_INLINE const idBounds &idClipModel::GetBounds() const {
|
||
|
return bounds;
|
||
|
}
|
||
|
|
||
|
ID_INLINE const idBounds &idClipModel::GetAbsBounds() const {
|
||
|
return absBounds;
|
||
|
}
|
||
|
|
||
|
ID_INLINE const idVec3 &idClipModel::GetOrigin() const {
|
||
|
return origin;
|
||
|
}
|
||
|
|
||
|
ID_INLINE const idMat3 &idClipModel::GetAxis() const {
|
||
|
return axis;
|
||
|
}
|
||
|
|
||
|
ID_INLINE bool idClipModel::IsRenderModel() const {
|
||
|
return ( renderModelHandle != -1 );
|
||
|
}
|
||
|
|
||
|
ID_INLINE bool idClipModel::IsTraceModel() const {
|
||
|
return ( traceModelIndex != -1 );
|
||
|
}
|
||
|
|
||
|
ID_INLINE bool idClipModel::IsLinked() const {
|
||
|
return ( clipLinks != NULL );
|
||
|
}
|
||
|
|
||
|
ID_INLINE bool idClipModel::IsEnabled() const {
|
||
|
return enabled;
|
||
|
}
|
||
|
|
||
|
ID_INLINE bool idClipModel::IsEqual( const idTraceModel &trm ) const {
|
||
|
return ( traceModelIndex != -1 && *GetCachedTraceModel( traceModelIndex ) == trm );
|
||
|
}
|
||
|
|
||
|
ID_INLINE const idTraceModel *idClipModel::GetTraceModel() const {
|
||
|
if ( !IsTraceModel() ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
return idClipModel::GetCachedTraceModel( traceModelIndex );
|
||
|
}
|
||
|
|
||
|
|
||
|
//===============================================================
|
||
|
//
|
||
|
// idClip
|
||
|
//
|
||
|
//===============================================================
|
||
|
|
||
|
class idClip {
|
||
|
|
||
|
friend class idClipModel;
|
||
|
|
||
|
public:
|
||
|
idClip();
|
||
|
|
||
|
void Init();
|
||
|
void Shutdown();
|
||
|
|
||
|
// clip versus the rest of the world
|
||
|
bool Translation( trace_t &results, const idVec3 &start, const idVec3 &end,
|
||
|
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity );
|
||
|
bool Rotation( trace_t &results, const idVec3 &start, const idRotation &rotation,
|
||
|
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity );
|
||
|
bool Motion( trace_t &results, const idVec3 &start, const idVec3 &end, const idRotation &rotation,
|
||
|
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity );
|
||
|
int Contacts( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth,
|
||
|
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity );
|
||
|
int Contents( const idVec3 &start,
|
||
|
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity );
|
||
|
|
||
|
// special case translations versus the rest of the world
|
||
|
bool TracePoint( trace_t &results, const idVec3 &start, const idVec3 &end,
|
||
|
int contentMask, const idEntity *passEntity );
|
||
|
bool TraceBounds( trace_t &results, const idVec3 &start, const idVec3 &end, const idBounds &bounds,
|
||
|
int contentMask, const idEntity *passEntity );
|
||
|
|
||
|
// clip versus a specific model
|
||
|
void TranslationModel( trace_t &results, const idVec3 &start, const idVec3 &end,
|
||
|
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
|
||
|
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
|
||
|
void RotationModel( trace_t &results, const idVec3 &start, const idRotation &rotation,
|
||
|
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
|
||
|
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
|
||
|
int ContactsModel( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth,
|
||
|
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
|
||
|
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
|
||
|
int ContentsModel( const idVec3 &start,
|
||
|
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
|
||
|
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
|
||
|
|
||
|
// clip versus all entities but not the world
|
||
|
void TranslationEntities( trace_t &results, const idVec3 &start, const idVec3 &end,
|
||
|
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity );
|
||
|
|
||
|
// get a contact feature
|
||
|
bool GetModelContactFeature( const contactInfo_t &contact, const idClipModel *clipModel, idFixedWinding &winding ) const;
|
||
|
|
||
|
// get entities/clip models within or touching the given bounds
|
||
|
int EntitiesTouchingBounds( const idBounds &bounds, int contentMask, idEntity **entityList, int maxCount ) const;
|
||
|
int ClipModelsTouchingBounds( const idBounds &bounds, int contentMask, idClipModel **clipModelList, int maxCount ) const;
|
||
|
|
||
|
const idBounds & GetWorldBounds() const;
|
||
|
idClipModel * DefaultClipModel();
|
||
|
|
||
|
// stats and debug drawing
|
||
|
void PrintStatistics();
|
||
|
void DrawClipModels( const idVec3 &eye, const float radius, const idEntity *passEntity );
|
||
|
bool DrawModelContactFeature( const contactInfo_t &contact, const idClipModel *clipModel, int lifetime ) const;
|
||
|
|
||
|
private:
|
||
|
int numClipSectors;
|
||
|
struct clipSector_s * clipSectors;
|
||
|
idBounds worldBounds;
|
||
|
idClipModel temporaryClipModel;
|
||
|
idClipModel defaultClipModel;
|
||
|
mutable int touchCount;
|
||
|
// statistics
|
||
|
int numTranslations;
|
||
|
int numRotations;
|
||
|
int numMotions;
|
||
|
int numRenderModelTraces;
|
||
|
int numContents;
|
||
|
int numContacts;
|
||
|
|
||
|
private:
|
||
|
struct clipSector_s * CreateClipSectors_r( const int depth, const idBounds &bounds, idVec3 &maxSector );
|
||
|
void ClipModelsTouchingBounds_r( const struct clipSector_s *node, struct listParms_s &parms ) const;
|
||
|
const idTraceModel * TraceModelForClipModel( const idClipModel *mdl ) const;
|
||
|
int GetTraceClipModels( const idBounds &bounds, int contentMask, const idEntity *passEntity, idClipModel **clipModelList ) const;
|
||
|
void TraceRenderModel( trace_t &trace, const idVec3 &start, const idVec3 &end, const float radius, const idMat3 &axis, idClipModel *touch ) const;
|
||
|
};
|
||
|
|
||
|
|
||
|
ID_INLINE bool idClip::TracePoint( trace_t &results, const idVec3 &start, const idVec3 &end, int contentMask, const idEntity *passEntity ) {
|
||
|
Translation( results, start, end, NULL, mat3_identity, contentMask, passEntity );
|
||
|
return ( results.fraction < 1.0f );
|
||
|
}
|
||
|
|
||
|
ID_INLINE bool idClip::TraceBounds( trace_t &results, const idVec3 &start, const idVec3 &end, const idBounds &bounds, int contentMask, const idEntity *passEntity ) {
|
||
|
temporaryClipModel.LoadModel( idTraceModel( bounds ) );
|
||
|
Translation( results, start, end, &temporaryClipModel, mat3_identity, contentMask, passEntity );
|
||
|
return ( results.fraction < 1.0f );
|
||
|
}
|
||
|
|
||
|
ID_INLINE const idBounds & idClip::GetWorldBounds() const {
|
||
|
return worldBounds;
|
||
|
}
|
||
|
|
||
|
ID_INLINE idClipModel *idClip::DefaultClipModel() {
|
||
|
return &defaultClipModel;
|
||
|
}
|
||
|
|
||
|
#endif /* !__CLIP_H__ */
|