doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Clip.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "../Game_local.h"
33 
34 #define MAX_SECTOR_DEPTH 12
35 #define MAX_SECTORS ((1<<(MAX_SECTOR_DEPTH+1))-1)
36 
37 typedef struct clipSector_s {
38  int axis; // -1 = leaf node
39  float dist;
40  struct clipSector_s * children[2];
42 } clipSector_t;
43 
44 typedef struct clipLink_s {
46  struct clipSector_s * sector;
49  struct clipLink_s * nextLink;
50 } clipLink_t;
51 
52 typedef struct trmCache_s {
54  int refCount;
55  float volume;
58 } trmCache_t;
59 
61 
63 
64 
65 /*
66 ===============================================================
67 
68  idClipModel trace model cache
69 
70 ===============================================================
71 */
72 
73 static idList<trmCache_s*> traceModelCache;
74 static idHashIndex traceModelHash;
75 
76 /*
77 ===============
78 idClipModel::ClearTraceModelCache
79 ===============
80 */
82  traceModelCache.DeleteContents( true );
83  traceModelHash.Free();
84 }
85 
86 /*
87 ===============
88 idClipModel::TraceModelCacheSize
89 ===============
90 */
92  return traceModelCache.Num() * sizeof( idTraceModel );
93 }
94 
95 /*
96 ===============
97 idClipModel::AllocTraceModel
98 ===============
99 */
101  int i, hashKey, traceModelIndex;
102  trmCache_t *entry;
103 
104  hashKey = GetTraceModelHashKey( trm );
105  for ( i = traceModelHash.First( hashKey ); i >= 0; i = traceModelHash.Next( i ) ) {
106  if ( traceModelCache[i]->trm == trm ) {
107  traceModelCache[i]->refCount++;
108  return i;
109  }
110  }
111 
112  entry = new trmCache_t;
113  entry->trm = trm;
114  entry->trm.GetMassProperties( 1.0f, entry->volume, entry->centerOfMass, entry->inertiaTensor );
115  entry->refCount = 1;
116 
117  traceModelIndex = traceModelCache.Append( entry );
118  traceModelHash.Add( hashKey, traceModelIndex );
119  return traceModelIndex;
120 }
121 
122 /*
123 ===============
124 idClipModel::FreeTraceModel
125 ===============
126 */
127 void idClipModel::FreeTraceModel( int traceModelIndex ) {
128  if ( traceModelIndex < 0 || traceModelIndex >= traceModelCache.Num() || traceModelCache[traceModelIndex]->refCount <= 0 ) {
129  gameLocal.Warning( "idClipModel::FreeTraceModel: tried to free uncached trace model" );
130  return;
131  }
132  traceModelCache[traceModelIndex]->refCount--;
133 }
134 
135 /*
136 ===============
137 idClipModel::GetCachedTraceModel
138 ===============
139 */
141  return &traceModelCache[traceModelIndex]->trm;
142 }
143 
144 /*
145 ===============
146 idClipModel::GetTraceModelHashKey
147 ===============
148 */
150  const idVec3 &v = trm.bounds[0];
151  return ( trm.type << 8 ) ^ ( trm.numVerts << 4 ) ^ ( trm.numEdges << 2 ) ^ ( trm.numPolys << 0 ) ^ idMath::FloatHash( v.ToFloatPtr(), v.GetDimension() );
152 }
153 
154 /*
155 ===============
156 idClipModel::SaveTraceModels
157 ===============
158 */
160  int i;
161 
162  savefile->WriteInt( traceModelCache.Num() );
163  for ( i = 0; i < traceModelCache.Num(); i++ ) {
164  trmCache_t *entry = traceModelCache[i];
165 
166  savefile->WriteTraceModel( entry->trm );
167  savefile->WriteFloat( entry->volume );
168  savefile->WriteVec3( entry->centerOfMass );
169  savefile->WriteMat3( entry->inertiaTensor );
170  }
171 }
172 
173 /*
174 ===============
175 idClipModel::RestoreTraceModels
176 ===============
177 */
179  int i, num;
180 
182 
183  savefile->ReadInt( num );
184  traceModelCache.SetNum( num );
185 
186  for ( i = 0; i < num; i++ ) {
187  trmCache_t *entry = new trmCache_t;
188 
189  savefile->ReadTraceModel( entry->trm );
190 
191  savefile->ReadFloat( entry->volume );
192  savefile->ReadVec3( entry->centerOfMass );
193  savefile->ReadMat3( entry->inertiaTensor );
194  entry->refCount = 0;
195 
196  traceModelCache[i] = entry;
197  traceModelHash.Add( GetTraceModelHashKey( entry->trm ), i );
198  }
199 }
200 
201 
202 /*
203 ===============================================================
204 
205  idClipModel
206 
207 ===============================================================
208 */
209 
210 /*
211 ================
212 idClipModel::LoadModel
213 ================
214 */
215 bool idClipModel::LoadModel( const char *name ) {
216  renderModelHandle = -1;
217  if ( traceModelIndex != -1 ) {
219  traceModelIndex = -1;
220  }
222  if ( collisionModelHandle ) {
225  return true;
226  } else {
227  bounds.Zero();
228  return false;
229  }
230 }
231 
232 /*
233 ================
234 idClipModel::LoadModel
235 ================
236 */
239  renderModelHandle = -1;
240  if ( traceModelIndex != -1 ) {
242  }
244  bounds = trm.bounds;
245 }
246 
247 /*
248 ================
249 idClipModel::LoadModel
250 ================
251 */
252 void idClipModel::LoadModel( const int renderModelHandle ) {
254  this->renderModelHandle = renderModelHandle;
255  if ( renderModelHandle != -1 ) {
256  const renderEntity_t *renderEntity = gameRenderWorld->GetRenderEntity( renderModelHandle );
257  if ( renderEntity ) {
258  bounds = renderEntity->bounds;
259  }
260  }
261  if ( traceModelIndex != -1 ) {
263  traceModelIndex = -1;
264  }
265 }
266 
267 /*
268 ================
269 idClipModel::Init
270 ================
271 */
272 void idClipModel::Init( void ) {
273  enabled = true;
274  entity = NULL;
275  id = 0;
276  owner = NULL;
277  origin.Zero();
278  axis.Identity();
279  bounds.Zero();
280  absBounds.Zero();
281  material = NULL;
284  renderModelHandle = -1;
285  traceModelIndex = -1;
286  clipLinks = NULL;
287  touchCount = -1;
288 }
289 
290 /*
291 ================
292 idClipModel::idClipModel
293 ================
294 */
296  Init();
297 }
298 
299 /*
300 ================
301 idClipModel::idClipModel
302 ================
303 */
305  Init();
306  LoadModel( name );
307 }
308 
309 /*
310 ================
311 idClipModel::idClipModel
312 ================
313 */
315  Init();
316  LoadModel( trm );
317 }
318 
319 /*
320 ================
321 idClipModel::idClipModel
322 ================
323 */
324 idClipModel::idClipModel( const int renderModelHandle ) {
325  Init();
327  LoadModel( renderModelHandle );
328 }
329 
330 /*
331 ================
332 idClipModel::idClipModel
333 ================
334 */
336  enabled = model->enabled;
337  entity = model->entity;
338  id = model->id;
339  owner = model->owner;
340  origin = model->origin;
341  axis = model->axis;
342  bounds = model->bounds;
343  absBounds = model->absBounds;
344  material = model->material;
345  contents = model->contents;
347  traceModelIndex = -1;
348  if ( model->traceModelIndex != -1 ) {
350  }
352  clipLinks = NULL;
353  touchCount = -1;
354 }
355 
356 /*
357 ================
358 idClipModel::~idClipModel
359 ================
360 */
362  // make sure the clip model is no longer linked
363  Unlink();
364  if ( traceModelIndex != -1 ) {
366  }
367 }
368 
369 /*
370 ================
371 idClipModel::Save
372 ================
373 */
374 void idClipModel::Save( idSaveGame *savefile ) const {
375  savefile->WriteBool( enabled );
376  savefile->WriteObject( entity );
377  savefile->WriteInt( id );
378  savefile->WriteObject( owner );
379  savefile->WriteVec3( origin );
380  savefile->WriteMat3( axis );
381  savefile->WriteBounds( bounds );
382  savefile->WriteBounds( absBounds );
383  savefile->WriteMaterial( material );
384  savefile->WriteInt( contents );
385  if ( collisionModelHandle >= 0 ) {
387  } else {
388  savefile->WriteString( "" );
389  }
390  savefile->WriteInt( traceModelIndex );
391  savefile->WriteInt( renderModelHandle );
392  savefile->WriteBool( clipLinks != NULL );
393  savefile->WriteInt( touchCount );
394 }
395 
396 /*
397 ================
398 idClipModel::Restore
399 ================
400 */
402  idStr collisionModelName;
403  bool linked;
404 
405  savefile->ReadBool( enabled );
406  savefile->ReadObject( reinterpret_cast<idClass *&>( entity ) );
407  savefile->ReadInt( id );
408  savefile->ReadObject( reinterpret_cast<idClass *&>( owner ) );
409  savefile->ReadVec3( origin );
410  savefile->ReadMat3( axis );
411  savefile->ReadBounds( bounds );
412  savefile->ReadBounds( absBounds );
413  savefile->ReadMaterial( material );
414  savefile->ReadInt( contents );
415  savefile->ReadString( collisionModelName );
416  if ( collisionModelName.Length() ) {
417  collisionModelHandle = collisionModelManager->LoadModel( collisionModelName, false );
418  } else {
420  }
421  savefile->ReadInt( traceModelIndex );
422  if ( traceModelIndex >= 0 ) {
423  traceModelCache[traceModelIndex]->refCount++;
424  }
425  savefile->ReadInt( renderModelHandle );
426  savefile->ReadBool( linked );
427  savefile->ReadInt( touchCount );
428 
429  // the render model will be set when the clip model is linked
430  renderModelHandle = -1;
431  clipLinks = NULL;
432  touchCount = -1;
433 
434  if ( linked ) {
436  }
437 }
438 
439 /*
440 ================
441 idClipModel::SetPosition
442 ================
443 */
444 void idClipModel::SetPosition( const idVec3 &newOrigin, const idMat3 &newAxis ) {
445  if ( clipLinks ) {
446  Unlink(); // unlink from old position
447  }
448  origin = newOrigin;
449  axis = newAxis;
450 }
451 
452 /*
453 ================
454 idClipModel::Handle
455 ================
456 */
458  assert( renderModelHandle == -1 );
459  if ( collisionModelHandle ) {
460  return collisionModelHandle;
461  } else if ( traceModelIndex != -1 ) {
463  } else {
464  // this happens in multiplayer on the combat models
465  gameLocal.Warning( "idClipModel::Handle: clip model %d on '%s' (%x) is not a collision or trace model", id, entity->name.c_str(), entity->entityNumber );
466  return 0;
467  }
468 }
469 
470 /*
471 ================
472 idClipModel::GetMassProperties
473 ================
474 */
475 void idClipModel::GetMassProperties( const float density, float &mass, idVec3 &centerOfMass, idMat3 &inertiaTensor ) const {
476  if ( traceModelIndex == -1 ) {
477  gameLocal.Error( "idClipModel::GetMassProperties: clip model %d on '%s' is not a trace model\n", id, entity->name.c_str() );
478  }
479 
480  trmCache_t *entry = traceModelCache[traceModelIndex];
481  mass = entry->volume * density;
482  centerOfMass = entry->centerOfMass;
483  inertiaTensor = density * entry->inertiaTensor;
484 }
485 
486 /*
487 ===============
488 idClipModel::Unlink
489 ===============
490 */
491 void idClipModel::Unlink( void ) {
492  clipLink_t *link;
493 
494  for ( link = clipLinks; link; link = clipLinks ) {
495  clipLinks = link->nextLink;
496  if ( link->prevInSector ) {
497  link->prevInSector->nextInSector = link->nextInSector;
498  } else {
499  link->sector->clipLinks = link->nextInSector;
500  }
501  if ( link->nextInSector ) {
502  link->nextInSector->prevInSector = link->prevInSector;
503  }
504  clipLinkAllocator.Free( link );
505  }
506 }
507 
508 /*
509 ===============
510 idClipModel::Link_r
511 ===============
512 */
513 void idClipModel::Link_r( struct clipSector_s *node ) {
514  clipLink_t *link;
515 
516  while( node->axis != -1 ) {
517  if ( absBounds[0][node->axis] > node->dist ) {
518  node = node->children[0];
519  } else if ( absBounds[1][node->axis] < node->dist ) {
520  node = node->children[1];
521  } else {
522  Link_r( node->children[0] );
523  node = node->children[1];
524  }
525  }
526 
527  link = clipLinkAllocator.Alloc();
528  link->clipModel = this;
529  link->sector = node;
530  link->nextInSector = node->clipLinks;
531  link->prevInSector = NULL;
532  if ( node->clipLinks ) {
533  node->clipLinks->prevInSector = link;
534  }
535  node->clipLinks = link;
536  link->nextLink = clipLinks;
537  clipLinks = link;
538 }
539 
540 /*
541 ===============
542 idClipModel::Link
543 ===============
544 */
545 void idClipModel::Link( idClip &clp ) {
546 
548  if ( !idClipModel::entity ) {
549  return;
550  }
551 
552  if ( clipLinks ) {
553  Unlink(); // unlink from old position
554  }
555 
556  if ( bounds.IsCleared() ) {
557  return;
558  }
559 
560  // set the abs box
561  if ( axis.IsRotated() ) {
562  // expand for rotation
564  } else {
565  // normal
566  absBounds[0] = bounds[0] + origin;
567  absBounds[1] = bounds[1] + origin;
568  }
569 
570  // because movement is clipped an epsilon away from an actual edge,
571  // we must fully check even when bounding boxes don't quite touch
574 
575  Link_r( clp.clipSectors );
576 }
577 
578 /*
579 ===============
580 idClipModel::Link
581 ===============
582 */
583 void idClipModel::Link( idClip &clp, idEntity *ent, int newId, const idVec3 &newOrigin, const idMat3 &newAxis, int renderModelHandle ) {
584 
585  this->entity = ent;
586  this->id = newId;
587  this->origin = newOrigin;
588  this->axis = newAxis;
589  if ( renderModelHandle != -1 ) {
590  this->renderModelHandle = renderModelHandle;
591  const renderEntity_t *renderEntity = gameRenderWorld->GetRenderEntity( renderModelHandle );
592  if ( renderEntity ) {
593  this->bounds = renderEntity->bounds;
594  }
595  }
596  this->Link( clp );
597 }
598 
599 /*
600 ============
601 idClipModel::CheckModel
602 ============
603 */
605  return collisionModelManager->LoadModel( name, false );
606 }
607 
608 
609 /*
610 ===============================================================
611 
612  idClip
613 
614 ===============================================================
615 */
616 
617 /*
618 ===============
619 idClip::idClip
620 ===============
621 */
622 idClip::idClip( void ) {
623  numClipSectors = 0;
624  clipSectors = NULL;
625  worldBounds.Zero();
627 }
628 
629 /*
630 ===============
631 idClip::CreateClipSectors_r
632 
633 Builds a uniformly subdivided tree for the given world size
634 ===============
635 */
636 clipSector_t *idClip::CreateClipSectors_r( const int depth, const idBounds &bounds, idVec3 &maxSector ) {
637  int i;
638  clipSector_t *anode;
639  idVec3 size;
640  idBounds front, back;
641 
644 
645  if ( depth == MAX_SECTOR_DEPTH ) {
646  anode->axis = -1;
647  anode->children[0] = anode->children[1] = NULL;
648 
649  for ( i = 0; i < 3; i++ ) {
650  if ( bounds[1][i] - bounds[0][i] > maxSector[i] ) {
651  maxSector[i] = bounds[1][i] - bounds[0][i];
652  }
653  }
654  return anode;
655  }
656 
657  size = bounds[1] - bounds[0];
658  if ( size[0] >= size[1] && size[0] >= size[2] ) {
659  anode->axis = 0;
660  } else if ( size[1] >= size[0] && size[1] >= size[2] ) {
661  anode->axis = 1;
662  } else {
663  anode->axis = 2;
664  }
665 
666  anode->dist = 0.5f * ( bounds[1][anode->axis] + bounds[0][anode->axis] );
667 
668  front = bounds;
669  back = bounds;
670 
671  front[0][anode->axis] = back[1][anode->axis] = anode->dist;
672 
673  anode->children[0] = CreateClipSectors_r( depth+1, front, maxSector );
674  anode->children[1] = CreateClipSectors_r( depth+1, back, maxSector );
675 
676  return anode;
677 }
678 
679 /*
680 ===============
681 idClip::Init
682 ===============
683 */
684 void idClip::Init( void ) {
685  cmHandle_t h;
686  idVec3 size, maxSector = vec3_origin;
687 
688  // clear clip sectors
690  memset( clipSectors, 0, MAX_SECTORS * sizeof( clipSector_t ) );
691  numClipSectors = 0;
692  touchCount = -1;
693  // get world map bounds
694  h = collisionModelManager->LoadModel( "worldMap", false );
696  // create world sectors
697  CreateClipSectors_r( 0, worldBounds, maxSector );
698 
699  size = worldBounds[1] - worldBounds[0];
700  gameLocal.Printf( "map bounds are (%1.1f, %1.1f, %1.1f)\n", size[0], size[1], size[2] );
701  gameLocal.Printf( "max clip sector is (%1.1f, %1.1f, %1.1f)\n", maxSector[0], maxSector[1], maxSector[2] );
702 
703  // initialize a default clip model
704  defaultClipModel.LoadModel( idTraceModel( idBounds( idVec3( 0, 0, 0 ) ).Expand( 8 ) ) );
705 
706  // set counters to zero
708 }
709 
710 /*
711 ===============
712 idClip::Shutdown
713 ===============
714 */
715 void idClip::Shutdown( void ) {
716  delete[] clipSectors;
717  clipSectors = NULL;
718 
719  // free the trace model used for the temporaryClipModel
720  if ( temporaryClipModel.traceModelIndex != -1 ) {
723  }
724 
725  // free the trace model used for the defaultClipModel
726  if ( defaultClipModel.traceModelIndex != -1 ) {
729  }
730 
731  clipLinkAllocator.Shutdown();
732 }
733 
734 /*
735 ====================
736 idClip::ClipModelsTouchingBounds_r
737 ====================
738 */
739 typedef struct listParms_s {
743  int count;
744  int maxCount;
745 } listParms_t;
746 
747 void idClip::ClipModelsTouchingBounds_r( const struct clipSector_s *node, listParms_t &parms ) const {
748 
749  while( node->axis != -1 ) {
750  if ( parms.bounds[0][node->axis] > node->dist ) {
751  node = node->children[0];
752  } else if ( parms.bounds[1][node->axis] < node->dist ) {
753  node = node->children[1];
754  } else {
755  ClipModelsTouchingBounds_r( node->children[0], parms );
756  node = node->children[1];
757  }
758  }
759 
760  for ( clipLink_t *link = node->clipLinks; link; link = link->nextInSector ) {
761  idClipModel *check = link->clipModel;
762 
763  // if the clip model is enabled
764  if ( !check->enabled ) {
765  continue;
766  }
767 
768  // avoid duplicates in the list
769  if ( check->touchCount == touchCount ) {
770  continue;
771  }
772 
773  // if the clip model does not have any contents we are looking for
774  if ( !( check->contents & parms.contentMask ) ) {
775  continue;
776  }
777 
778  // if the bounds really do overlap
779  if ( check->absBounds[0][0] > parms.bounds[1][0] ||
780  check->absBounds[1][0] < parms.bounds[0][0] ||
781  check->absBounds[0][1] > parms.bounds[1][1] ||
782  check->absBounds[1][1] < parms.bounds[0][1] ||
783  check->absBounds[0][2] > parms.bounds[1][2] ||
784  check->absBounds[1][2] < parms.bounds[0][2] ) {
785  continue;
786  }
787 
788  if ( parms.count >= parms.maxCount ) {
789  gameLocal.Warning( "idClip::ClipModelsTouchingBounds_r: max count" );
790  return;
791  }
792 
793  check->touchCount = touchCount;
794  parms.list[parms.count] = check;
795  parms.count++;
796  }
797 }
798 
799 /*
800 ================
801 idClip::ClipModelsTouchingBounds
802 ================
803 */
804 int idClip::ClipModelsTouchingBounds( const idBounds &bounds, int contentMask, idClipModel **clipModelList, int maxCount ) const {
805  listParms_t parms;
806 
807  if ( bounds[0][0] > bounds[1][0] ||
808  bounds[0][1] > bounds[1][1] ||
809  bounds[0][2] > bounds[1][2] ) {
810  // we should not go through the tree for degenerate or backwards bounds
811  assert( false );
812  return 0;
813  }
814 
815  parms.bounds[0] = bounds[0] - vec3_boxEpsilon;
816  parms.bounds[1] = bounds[1] + vec3_boxEpsilon;
817  parms.contentMask = contentMask;
818  parms.list = clipModelList;
819  parms.count = 0;
820  parms.maxCount = maxCount;
821 
822  touchCount++;
824 
825  return parms.count;
826 }
827 
828 /*
829 ================
830 idClip::EntitiesTouchingBounds
831 ================
832 */
833 int idClip::EntitiesTouchingBounds( const idBounds &bounds, int contentMask, idEntity **entityList, int maxCount ) const {
834  idClipModel *clipModelList[MAX_GENTITIES];
835  int i, j, count, entCount;
836 
837  count = idClip::ClipModelsTouchingBounds( bounds, contentMask, clipModelList, MAX_GENTITIES );
838  entCount = 0;
839  for ( i = 0; i < count; i++ ) {
840  // entity could already be in the list because an entity can use multiple clip models
841  for ( j = 0; j < entCount; j++ ) {
842  if ( entityList[j] == clipModelList[i]->entity ) {
843  break;
844  }
845  }
846  if ( j >= entCount ) {
847  if ( entCount >= maxCount ) {
848  gameLocal.Warning( "idClip::EntitiesTouchingBounds: max count" );
849  return entCount;
850  }
851  entityList[entCount] = clipModelList[i]->entity;
852  entCount++;
853  }
854  }
855 
856  return entCount;
857 }
858 
859 /*
860 ====================
861 idClip::GetTraceClipModels
862 
863  an ent will be excluded from testing if:
864  cm->entity == passEntity ( don't clip against the pass entity )
865  cm->entity == passOwner ( missiles don't clip with owner )
866  cm->owner == passEntity ( don't interact with your own missiles )
867  cm->owner == passOwner ( don't interact with other missiles from same owner )
868 ====================
869 */
870 int idClip::GetTraceClipModels( const idBounds &bounds, int contentMask, const idEntity *passEntity, idClipModel **clipModelList ) const {
871  int i, num;
872  idClipModel *cm;
873  idEntity *passOwner;
874 
875  num = ClipModelsTouchingBounds( bounds, contentMask, clipModelList, MAX_GENTITIES );
876 
877  if ( !passEntity ) {
878  return num;
879  }
880 
881  if ( passEntity->GetPhysics()->GetNumClipModels() > 0 ) {
882  passOwner = passEntity->GetPhysics()->GetClipModel()->GetOwner();
883  } else {
884  passOwner = NULL;
885  }
886 
887  for ( i = 0; i < num; i++ ) {
888 
889  cm = clipModelList[i];
890 
891  // check if we should ignore this entity
892  if ( cm->entity == passEntity ) {
893  clipModelList[i] = NULL; // don't clip against the pass entity
894  } else if ( cm->entity == passOwner ) {
895  clipModelList[i] = NULL; // missiles don't clip with their owner
896  } else if ( cm->owner ) {
897  if ( cm->owner == passEntity ) {
898  clipModelList[i] = NULL; // don't clip against own missiles
899  } else if ( cm->owner == passOwner ) {
900  clipModelList[i] = NULL; // don't clip against other missiles from same owner
901  }
902  }
903  }
904 
905  return num;
906 }
907 
908 /*
909 ============
910 idClip::TraceRenderModel
911 ============
912 */
913 void idClip::TraceRenderModel( trace_t &trace, const idVec3 &start, const idVec3 &end, const float radius, const idMat3 &axis, idClipModel *touch ) const {
914  trace.fraction = 1.0f;
915 
916  // if the trace is passing through the bounds
917  if ( touch->absBounds.Expand( radius ).LineIntersection( start, end ) ) {
918  modelTrace_t modelTrace;
919 
920  // test with exact render model and modify trace_t structure accordingly
921  if ( gameRenderWorld->ModelTrace( modelTrace, touch->renderModelHandle, start, end, radius ) ) {
922  trace.fraction = modelTrace.fraction;
923  trace.endAxis = axis;
924  trace.endpos = modelTrace.point;
925  trace.c.normal = modelTrace.normal;
926  trace.c.dist = modelTrace.point * modelTrace.normal;
927  trace.c.point = modelTrace.point;
928  trace.c.type = CONTACT_TRMVERTEX;
929  trace.c.modelFeature = 0;
930  trace.c.trmFeature = 0;
931  trace.c.contents = modelTrace.material->GetContentFlags();
932  trace.c.material = modelTrace.material;
933  // NOTE: trace.c.id will be the joint number
934  touch->id = JOINT_HANDLE_TO_CLIPMODEL_ID( modelTrace.jointNumber );
935  }
936  }
937 }
938 
939 /*
940 ============
941 idClip::TraceModelForClipModel
942 ============
943 */
945  if ( !mdl ) {
946  return NULL;
947  } else {
948  if ( !mdl->IsTraceModel() ) {
949  if ( mdl->GetEntity() ) {
950  gameLocal.Error( "TraceModelForClipModel: clip model %d on '%s' is not a trace model\n", mdl->GetId(), mdl->GetEntity()->name.c_str() );
951  } else {
952  gameLocal.Error( "TraceModelForClipModel: clip model %d is not a trace model\n", mdl->GetId() );
953  }
954  }
956  }
957 }
958 
959 /*
960 ============
961 idClip::TestHugeTranslation
962 ============
963 */
964 ID_INLINE bool TestHugeTranslation( trace_t &results, const idClipModel *mdl, const idVec3 &start, const idVec3 &end, const idMat3 &trmAxis ) {
965  if ( mdl != NULL && ( end - start ).LengthSqr() > Square( CM_MAX_TRACE_DIST ) ) {
966 #ifndef CTF
967  // May be important: This occurs in CTF when a player connects and spawns
968  // in the PVS of a player that has a flag that is spawning the idMoveableItem
969  // "nuggets". The error seems benign and the assert was getting in the way
970  // of testing.
971  assert( 0 );
972 #endif
973 
974  results.fraction = 0.0f;
975  results.endpos = start;
976  results.endAxis = trmAxis;
977  memset( &results.c, 0, sizeof( results.c ) );
978  results.c.point = start;
979 
980  if ( mdl->GetEntity() ) {
981  gameLocal.Printf( "huge translation for clip model %d on entity %d '%s'\n", mdl->GetId(), mdl->GetEntity()->entityNumber, mdl->GetEntity()->GetName() );
982  } else {
983  gameLocal.Printf( "huge translation for clip model %d\n", mdl->GetId() );
984  }
985  return true;
986  }
987  return false;
988 }
989 
990 /*
991 ============
992 idClip::TranslationEntities
993 ============
994 */
995 void idClip::TranslationEntities( trace_t &results, const idVec3 &start, const idVec3 &end,
996  const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) {
997  int i, num;
998  idClipModel *touch, *clipModelList[MAX_GENTITIES];
999  idBounds traceBounds;
1000  float radius;
1001  trace_t trace;
1002  const idTraceModel *trm;
1003 
1004  if ( TestHugeTranslation( results, mdl, start, end, trmAxis ) ) {
1005  return;
1006  }
1007 
1008  trm = TraceModelForClipModel( mdl );
1009 
1010  results.fraction = 1.0f;
1011  results.endpos = end;
1012  results.endAxis = trmAxis;
1013 
1014  if ( !trm ) {
1015  traceBounds.FromPointTranslation( start, end - start );
1016  radius = 0.0f;
1017  } else {
1018  traceBounds.FromBoundsTranslation( trm->bounds, start, trmAxis, end - start );
1019  radius = trm->bounds.GetRadius();
1020  }
1021 
1022  num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList );
1023 
1024  for ( i = 0; i < num; i++ ) {
1025  touch = clipModelList[i];
1026 
1027  if ( !touch ) {
1028  continue;
1029  }
1030 
1031  if ( touch->renderModelHandle != -1 ) {
1033  TraceRenderModel( trace, start, end, radius, trmAxis, touch );
1034  } else {
1036  collisionModelManager->Translation( &trace, start, end, trm, trmAxis, contentMask,
1037  touch->Handle(), touch->origin, touch->axis );
1038  }
1039 
1040  if ( trace.fraction < results.fraction ) {
1041  results = trace;
1042  results.c.entityNum = touch->entity->entityNumber;
1043  results.c.id = touch->id;
1044  if ( results.fraction == 0.0f ) {
1045  break;
1046  }
1047  }
1048  }
1049 }
1050 
1051 /*
1052 ============
1053 idClip::Translation
1054 ============
1055 */
1056 bool idClip::Translation( trace_t &results, const idVec3 &start, const idVec3 &end,
1057  const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) {
1058  int i, num;
1059  idClipModel *touch, *clipModelList[MAX_GENTITIES];
1060  idBounds traceBounds;
1061  float radius;
1062  trace_t trace;
1063  const idTraceModel *trm;
1064 
1065  if ( TestHugeTranslation( results, mdl, start, end, trmAxis ) ) {
1066  return true;
1067  }
1068 
1069  trm = TraceModelForClipModel( mdl );
1070 
1071  if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) {
1072  // test world
1074  collisionModelManager->Translation( &results, start, end, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default );
1075  results.c.entityNum = results.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
1076  if ( results.fraction == 0.0f ) {
1077  return true; // blocked immediately by the world
1078  }
1079  } else {
1080  memset( &results, 0, sizeof( results ) );
1081  results.fraction = 1.0f;
1082  results.endpos = end;
1083  results.endAxis = trmAxis;
1084  }
1085 
1086  if ( !trm ) {
1087  traceBounds.FromPointTranslation( start, results.endpos - start );
1088  radius = 0.0f;
1089  } else {
1090  traceBounds.FromBoundsTranslation( trm->bounds, start, trmAxis, results.endpos - start );
1091  radius = trm->bounds.GetRadius();
1092  }
1093 
1094  num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList );
1095 
1096  for ( i = 0; i < num; i++ ) {
1097  touch = clipModelList[i];
1098 
1099  if ( !touch ) {
1100  continue;
1101  }
1102 
1103  if ( touch->renderModelHandle != -1 ) {
1105  TraceRenderModel( trace, start, end, radius, trmAxis, touch );
1106  } else {
1108  collisionModelManager->Translation( &trace, start, end, trm, trmAxis, contentMask,
1109  touch->Handle(), touch->origin, touch->axis );
1110  }
1111 
1112  if ( trace.fraction < results.fraction ) {
1113  results = trace;
1114  results.c.entityNum = touch->entity->entityNumber;
1115  results.c.id = touch->id;
1116  if ( results.fraction == 0.0f ) {
1117  break;
1118  }
1119  }
1120  }
1121 
1122  return ( results.fraction < 1.0f );
1123 }
1124 
1125 /*
1126 ============
1127 idClip::Rotation
1128 ============
1129 */
1130 bool idClip::Rotation( trace_t &results, const idVec3 &start, const idRotation &rotation,
1131  const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) {
1132  int i, num;
1133  idClipModel *touch, *clipModelList[MAX_GENTITIES];
1134  idBounds traceBounds;
1135  trace_t trace;
1136  const idTraceModel *trm;
1137 
1138  trm = TraceModelForClipModel( mdl );
1139 
1140  if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) {
1141  // test world
1143  collisionModelManager->Rotation( &results, start, rotation, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default );
1144  results.c.entityNum = results.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
1145  if ( results.fraction == 0.0f ) {
1146  return true; // blocked immediately by the world
1147  }
1148  } else {
1149  memset( &results, 0, sizeof( results ) );
1150  results.fraction = 1.0f;
1151  results.endpos = start;
1152  results.endAxis = trmAxis * rotation.ToMat3();
1153  }
1154 
1155  if ( !trm ) {
1156  traceBounds.FromPointRotation( start, rotation );
1157  } else {
1158  traceBounds.FromBoundsRotation( trm->bounds, start, trmAxis, rotation );
1159  }
1160 
1161  num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList );
1162 
1163  for ( i = 0; i < num; i++ ) {
1164  touch = clipModelList[i];
1165 
1166  if ( !touch ) {
1167  continue;
1168  }
1169 
1170  // no rotational collision with render models
1171  if ( touch->renderModelHandle != -1 ) {
1172  continue;
1173  }
1174 
1176  collisionModelManager->Rotation( &trace, start, rotation, trm, trmAxis, contentMask,
1177  touch->Handle(), touch->origin, touch->axis );
1178 
1179  if ( trace.fraction < results.fraction ) {
1180  results = trace;
1181  results.c.entityNum = touch->entity->entityNumber;
1182  results.c.id = touch->id;
1183  if ( results.fraction == 0.0f ) {
1184  break;
1185  }
1186  }
1187  }
1188 
1189  return ( results.fraction < 1.0f );
1190 }
1191 
1192 /*
1193 ============
1194 idClip::Motion
1195 ============
1196 */
1197 bool idClip::Motion( trace_t &results, const idVec3 &start, const idVec3 &end, const idRotation &rotation,
1198  const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) {
1199  int i, num;
1200  idClipModel *touch, *clipModelList[MAX_GENTITIES];
1201  idVec3 dir, endPosition;
1202  idBounds traceBounds;
1203  float radius;
1204  trace_t translationalTrace, rotationalTrace, trace;
1205  idRotation endRotation;
1206  const idTraceModel *trm;
1207 
1208  assert( rotation.GetOrigin() == start );
1209 
1210  if ( TestHugeTranslation( results, mdl, start, end, trmAxis ) ) {
1211  return true;
1212  }
1213 
1214  if ( mdl != NULL && rotation.GetAngle() != 0.0f && rotation.GetVec() != vec3_origin ) {
1215  // if no translation
1216  if ( start == end ) {
1217  // pure rotation
1218  return Rotation( results, start, rotation, mdl, trmAxis, contentMask, passEntity );
1219  }
1220  } else if ( start != end ) {
1221  // pure translation
1222  return Translation( results, start, end, mdl, trmAxis, contentMask, passEntity );
1223  } else {
1224  // no motion
1225  results.fraction = 1.0f;
1226  results.endpos = start;
1227  results.endAxis = trmAxis;
1228  return false;
1229  }
1230 
1231  trm = TraceModelForClipModel( mdl );
1232 
1233  radius = trm->bounds.GetRadius();
1234 
1235  if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) {
1236  // translational collision with world
1238  collisionModelManager->Translation( &translationalTrace, start, end, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default );
1239  translationalTrace.c.entityNum = translationalTrace.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
1240  } else {
1241  memset( &translationalTrace, 0, sizeof( translationalTrace ) );
1242  translationalTrace.fraction = 1.0f;
1243  translationalTrace.endpos = end;
1244  translationalTrace.endAxis = trmAxis;
1245  }
1246 
1247  if ( translationalTrace.fraction != 0.0f ) {
1248 
1249  traceBounds.FromBoundsRotation( trm->bounds, start, trmAxis, rotation );
1250  dir = translationalTrace.endpos - start;
1251  for ( i = 0; i < 3; i++ ) {
1252  if ( dir[i] < 0.0f ) {
1253  traceBounds[0][i] += dir[i];
1254  }
1255  else {
1256  traceBounds[1][i] += dir[i];
1257  }
1258  }
1259 
1260  num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList );
1261 
1262  for ( i = 0; i < num; i++ ) {
1263  touch = clipModelList[i];
1264 
1265  if ( !touch ) {
1266  continue;
1267  }
1268 
1269  if ( touch->renderModelHandle != -1 ) {
1271  TraceRenderModel( trace, start, end, radius, trmAxis, touch );
1272  } else {
1274  collisionModelManager->Translation( &trace, start, end, trm, trmAxis, contentMask,
1275  touch->Handle(), touch->origin, touch->axis );
1276  }
1277 
1278  if ( trace.fraction < translationalTrace.fraction ) {
1279  translationalTrace = trace;
1280  translationalTrace.c.entityNum = touch->entity->entityNumber;
1281  translationalTrace.c.id = touch->id;
1282  if ( translationalTrace.fraction == 0.0f ) {
1283  break;
1284  }
1285  }
1286  }
1287  } else {
1288  num = -1;
1289  }
1290 
1291  endPosition = translationalTrace.endpos;
1292  endRotation = rotation;
1293  endRotation.SetOrigin( endPosition );
1294 
1295  if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) {
1296  // rotational collision with world
1298  collisionModelManager->Rotation( &rotationalTrace, endPosition, endRotation, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default );
1299  rotationalTrace.c.entityNum = rotationalTrace.fraction != 1.0f ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
1300  } else {
1301  memset( &rotationalTrace, 0, sizeof( rotationalTrace ) );
1302  rotationalTrace.fraction = 1.0f;
1303  rotationalTrace.endpos = endPosition;
1304  rotationalTrace.endAxis = trmAxis * rotation.ToMat3();
1305  }
1306 
1307  if ( rotationalTrace.fraction != 0.0f ) {
1308 
1309  if ( num == -1 ) {
1310  traceBounds.FromBoundsRotation( trm->bounds, endPosition, trmAxis, endRotation );
1311  num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList );
1312  }
1313 
1314  for ( i = 0; i < num; i++ ) {
1315  touch = clipModelList[i];
1316 
1317  if ( !touch ) {
1318  continue;
1319  }
1320 
1321  // no rotational collision detection with render models
1322  if ( touch->renderModelHandle != -1 ) {
1323  continue;
1324  }
1325 
1327  collisionModelManager->Rotation( &trace, endPosition, endRotation, trm, trmAxis, contentMask,
1328  touch->Handle(), touch->origin, touch->axis );
1329 
1330  if ( trace.fraction < rotationalTrace.fraction ) {
1331  rotationalTrace = trace;
1332  rotationalTrace.c.entityNum = touch->entity->entityNumber;
1333  rotationalTrace.c.id = touch->id;
1334  if ( rotationalTrace.fraction == 0.0f ) {
1335  break;
1336  }
1337  }
1338  }
1339  }
1340 
1341  if ( rotationalTrace.fraction < 1.0f ) {
1342  results = rotationalTrace;
1343  } else {
1344  results = translationalTrace;
1345  results.endAxis = rotationalTrace.endAxis;
1346  }
1347 
1348  results.fraction = Max( translationalTrace.fraction, rotationalTrace.fraction );
1349 
1350  return ( translationalTrace.fraction < 1.0f || rotationalTrace.fraction < 1.0f );
1351 }
1352 
1353 /*
1354 ============
1355 idClip::Contacts
1356 ============
1357 */
1358 int idClip::Contacts( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth,
1359  const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) {
1360  int i, j, num, n, numContacts;
1361  idClipModel *touch, *clipModelList[MAX_GENTITIES];
1362  idBounds traceBounds;
1363  const idTraceModel *trm;
1364 
1365  trm = TraceModelForClipModel( mdl );
1366 
1367  if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) {
1368  // test world
1370  numContacts = collisionModelManager->Contacts( contacts, maxContacts, start, dir, depth, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default );
1371  } else {
1372  numContacts = 0;
1373  }
1374 
1375  for ( i = 0; i < numContacts; i++ ) {
1376  contacts[i].entityNum = ENTITYNUM_WORLD;
1377  contacts[i].id = 0;
1378  }
1379 
1380  if ( numContacts >= maxContacts ) {
1381  return numContacts;
1382  }
1383 
1384  if ( !trm ) {
1385  traceBounds = idBounds( start ).Expand( depth );
1386  } else {
1387  traceBounds.FromTransformedBounds( trm->bounds, start, trmAxis );
1388  traceBounds.ExpandSelf( depth );
1389  }
1390 
1391  num = GetTraceClipModels( traceBounds, contentMask, passEntity, clipModelList );
1392 
1393  for ( i = 0; i < num; i++ ) {
1394  touch = clipModelList[i];
1395 
1396  if ( !touch ) {
1397  continue;
1398  }
1399 
1400  // no contacts with render models
1401  if ( touch->renderModelHandle != -1 ) {
1402  continue;
1403  }
1404 
1406  n = collisionModelManager->Contacts( contacts + numContacts, maxContacts - numContacts,
1407  start, dir, depth, trm, trmAxis, contentMask,
1408  touch->Handle(), touch->origin, touch->axis );
1409 
1410  for ( j = 0; j < n; j++ ) {
1411  contacts[numContacts].entityNum = touch->entity->entityNumber;
1412  contacts[numContacts].id = touch->id;
1413  numContacts++;
1414  }
1415 
1416  if ( numContacts >= maxContacts ) {
1417  break;
1418  }
1419  }
1420 
1421  return numContacts;
1422 }
1423 
1424 /*
1425 ============
1426 idClip::Contents
1427 ============
1428 */
1429 int idClip::Contents( const idVec3 &start, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity ) {
1430  int i, num, contents;
1431  idClipModel *touch, *clipModelList[MAX_GENTITIES];
1432  idBounds traceBounds;
1433  const idTraceModel *trm;
1434 
1435  trm = TraceModelForClipModel( mdl );
1436 
1437  if ( !passEntity || passEntity->entityNumber != ENTITYNUM_WORLD ) {
1438  // test world
1440  contents = collisionModelManager->Contents( start, trm, trmAxis, contentMask, 0, vec3_origin, mat3_default );
1441  } else {
1442  contents = 0;
1443  }
1444 
1445  if ( !trm ) {
1446  traceBounds[0] = start;
1447  traceBounds[1] = start;
1448  } else if ( trmAxis.IsRotated() ) {
1449  traceBounds.FromTransformedBounds( trm->bounds, start, trmAxis );
1450  } else {
1451  traceBounds[0] = trm->bounds[0] + start;
1452  traceBounds[1] = trm->bounds[1] + start;
1453  }
1454 
1455  num = GetTraceClipModels( traceBounds, -1, passEntity, clipModelList );
1456 
1457  for ( i = 0; i < num; i++ ) {
1458  touch = clipModelList[i];
1459 
1460  if ( !touch ) {
1461  continue;
1462  }
1463 
1464  // no contents test with render models
1465  if ( touch->renderModelHandle != -1 ) {
1466  continue;
1467  }
1468 
1469  // if the entity does not have any contents we are looking for
1470  if ( ( touch->contents & contentMask ) == 0 ) {
1471  continue;
1472  }
1473 
1474  // if the entity has no new contents flags
1475  if ( ( touch->contents & contents ) == touch->contents ) {
1476  continue;
1477  }
1478 
1480  if ( collisionModelManager->Contents( start, trm, trmAxis, contentMask, touch->Handle(), touch->origin, touch->axis ) ) {
1481  contents |= ( touch->contents & contentMask );
1482  }
1483  }
1484 
1485  return contents;
1486 }
1487 
1488 /*
1489 ============
1490 idClip::TranslationModel
1491 ============
1492 */
1493 void idClip::TranslationModel( trace_t &results, const idVec3 &start, const idVec3 &end,
1494  const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
1495  cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
1496  const idTraceModel *trm = TraceModelForClipModel( mdl );
1498  collisionModelManager->Translation( &results, start, end, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
1499 }
1500 
1501 /*
1502 ============
1503 idClip::RotationModel
1504 ============
1505 */
1506 void idClip::RotationModel( trace_t &results, const idVec3 &start, const idRotation &rotation,
1507  const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
1508  cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
1509  const idTraceModel *trm = TraceModelForClipModel( mdl );
1511  collisionModelManager->Rotation( &results, start, rotation, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
1512 }
1513 
1514 /*
1515 ============
1516 idClip::ContactsModel
1517 ============
1518 */
1519 int idClip::ContactsModel( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth,
1520  const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
1521  cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
1522  const idTraceModel *trm = TraceModelForClipModel( mdl );
1524  return collisionModelManager->Contacts( contacts, maxContacts, start, dir, depth, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
1525 }
1526 
1527 /*
1528 ============
1529 idClip::ContentsModel
1530 ============
1531 */
1533  const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
1534  cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
1535  const idTraceModel *trm = TraceModelForClipModel( mdl );
1537  return collisionModelManager->Contents( start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
1538 }
1539 
1540 /*
1541 ============
1542 idClip::GetModelContactFeature
1543 ============
1544 */
1545 bool idClip::GetModelContactFeature( const contactInfo_t &contact, const idClipModel *clipModel, idFixedWinding &winding ) const {
1546  int i;
1547  cmHandle_t handle;
1548  idVec3 start, end;
1549 
1550  handle = -1;
1551  winding.Clear();
1552 
1553  if ( clipModel == NULL ) {
1554  handle = 0;
1555  } else {
1556  if ( clipModel->renderModelHandle != -1 ) {
1557  winding += contact.point;
1558  return true;
1559  } else if ( clipModel->traceModelIndex != -1 ) {
1561  } else {
1562  handle = clipModel->collisionModelHandle;
1563  }
1564  }
1565 
1566  // if contact with a collision model
1567  if ( handle != -1 ) {
1568  switch( contact.type ) {
1569  case CONTACT_EDGE: {
1570  // the model contact feature is a collision model edge
1571  collisionModelManager->GetModelEdge( handle, contact.modelFeature, start, end );
1572  winding += start;
1573  winding += end;
1574  break;
1575  }
1576  case CONTACT_MODELVERTEX: {
1577  // the model contact feature is a collision model vertex
1578  collisionModelManager->GetModelVertex( handle, contact.modelFeature, start );
1579  winding += start;
1580  break;
1581  }
1582  case CONTACT_TRMVERTEX: {
1583  // the model contact feature is a collision model polygon
1584  collisionModelManager->GetModelPolygon( handle, contact.modelFeature, winding );
1585  break;
1586  }
1587  }
1588  }
1589 
1590  // transform the winding to world space
1591  if ( clipModel ) {
1592  for ( i = 0; i < winding.GetNumPoints(); i++ ) {
1593  winding[i].ToVec3() *= clipModel->axis;
1594  winding[i].ToVec3() += clipModel->origin;
1595  }
1596  }
1597 
1598  return true;
1599 }
1600 
1601 /*
1602 ============
1603 idClip::PrintStatistics
1604 ============
1605 */
1607  gameLocal.Printf( "t = %-3d, r = %-3d, m = %-3d, render = %-3d, contents = %-3d, contacts = %-3d\n",
1610 }
1611 
1612 /*
1613 ============
1614 idClip::DrawClipModels
1615 ============
1616 */
1617 void idClip::DrawClipModels( const idVec3 &eye, const float radius, const idEntity *passEntity ) {
1618  int i, num;
1619  idBounds bounds;
1620  idClipModel *clipModelList[MAX_GENTITIES];
1621  idClipModel *clipModel;
1622 
1623  bounds = idBounds( eye ).Expand( radius );
1624 
1625  num = idClip::ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES );
1626 
1627  for ( i = 0; i < num; i++ ) {
1628  clipModel = clipModelList[i];
1629  if ( clipModel->GetEntity() == passEntity ) {
1630  continue;
1631  }
1632  if ( clipModel->renderModelHandle != -1 ) {
1634  } else {
1635  collisionModelManager->DrawModel( clipModel->Handle(), clipModel->GetOrigin(), clipModel->GetAxis(), eye, radius );
1636  }
1637  }
1638 }
1639 
1640 /*
1641 ============
1642 idClip::DrawModelContactFeature
1643 ============
1644 */
1645 bool idClip::DrawModelContactFeature( const contactInfo_t &contact, const idClipModel *clipModel, int lifetime ) const {
1646  int i;
1647  idMat3 axis;
1648  idFixedWinding winding;
1649 
1650  if ( !GetModelContactFeature( contact, clipModel, winding ) ) {
1651  return false;
1652  }
1653 
1654  axis = contact.normal.ToMat3();
1655 
1656  if ( winding.GetNumPoints() == 1 ) {
1657  gameRenderWorld->DebugLine( colorCyan, winding[0].ToVec3(), winding[0].ToVec3() + 2.0f * axis[0], lifetime );
1658  gameRenderWorld->DebugLine( colorWhite, winding[0].ToVec3() - 1.0f * axis[1], winding[0].ToVec3() + 1.0f * axis[1], lifetime );
1659  gameRenderWorld->DebugLine( colorWhite, winding[0].ToVec3() - 1.0f * axis[2], winding[0].ToVec3() + 1.0f * axis[2], lifetime );
1660  } else {
1661  for ( i = 0; i < winding.GetNumPoints(); i++ ) {
1662  gameRenderWorld->DebugLine( colorCyan, winding[i].ToVec3(), winding[(i+1)%winding.GetNumPoints()].ToVec3(), lifetime );
1663  }
1664  }
1665 
1666  axis[0] = -axis[0];
1667  axis[2] = -axis[2];
1668  gameRenderWorld->DrawText( contact.material->GetName(), winding.GetCenter() - 4.0f * axis[2], 0.1f, colorWhite, axis, 1, 5000 );
1669 
1670  return true;
1671 }
traceModel_t type
Definition: TraceModel.h:86
int ClipModelsTouchingBounds(const idBounds &bounds, int contentMask, idClipModel **clipModelList, int maxCount) const
Definition: Clip.cpp:804
idEntity * GetEntity(void) const
Definition: Clip.h:178
idMat3 inertiaTensor
Definition: Clip.cpp:57
idMat3 ToMat3(void) const
Definition: Vector.cpp:195
void WriteString(const char *string)
Definition: SaveGame.cpp:231
idBounds bounds
Definition: Clip.cpp:740
void DrawClipModels(const idVec3 &eye, const float radius, const idEntity *passEntity)
Definition: Clip.cpp:1617
assert(prefInfo.fullscreenBtn)
static void ClearTraceModelCache(void)
Definition: Clip.cpp:81
void Link(idClip &clp)
Definition: Clip.cpp:545
virtual bool GetModelContents(cmHandle_t model, int &contents) const =0
idEntity * entity
Definition: Clip.h:113
int refCount
Definition: Clip.cpp:54
void ReadMaterial(const idMaterial *&material)
Definition: SaveGame.cpp:1132
void WriteObject(const idClass *obj)
Definition: SaveGame.cpp:329
int Next(const int index) const
Definition: HashIndex.h:247
idClip clip
Definition: Game_local.h:296
idVec4 colorWhite
Definition: Lib.cpp:116
void Printf(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:699
void Zero(void)
Definition: Bounds.h:206
#define MAX_GENTITIES
Definition: Game_local.h:83
idBounds bounds
Definition: Clip.h:118
const GLdouble * v
Definition: glext.h:2936
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)
Definition: Clip.cpp:1358
#define MAX_SECTORS
Definition: Clip.cpp:35
void SetNum(int newnum, bool resize=true)
Definition: List.h:289
bool GetModelContactFeature(const contactInfo_t &contact, const idClipModel *clipModel, idFixedWinding &winding) const
Definition: Clip.cpp:1545
void FromPointRotation(const idVec3 &point, const idRotation &rotation)
Definition: Bounds.cpp:363
ID_INLINE T Max(T x, T y)
Definition: Lib.h:158
const float * ToFloatPtr(void) const
Definition: Vector.h:719
int Length(void) const
Definition: Str.h:702
void void void void void Error(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:783
static int TraceModelCacheSize(void)
Definition: Clip.cpp:91
idClipModel ** list
Definition: Clip.cpp:742
const idMaterial * material
Definition: RenderWorld.h:249
const idMat3 & GetAxis(void) const
Definition: Clip.h:210
#define CM_BOX_EPSILON
GLenum GLsizei n
Definition: glext.h:3705
int numMotions
Definition: Clip.h:319
static void FreeTraceModel(int traceModelIndex)
Definition: Clip.cpp:127
idMat3 axis
Definition: Clip.h:117
Definition: Clip.h:248
virtual int GetNumClipModels(void) const =0
virtual void Translation(trace_t *results, const idVec3 &start, const idVec3 &end, const idTraceModel *trm, const idMat3 &trmAxis, int contentMask, cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis)=0
static int FloatHash(const float *array, const int numFloats)
Definition: Math.h:922
#define CM_MAX_TRACE_DIST
ID_INLINE bool TestHugeTranslation(trace_t &results, const idClipModel *mdl, const idVec3 &start, const idVec3 &end, const idMat3 &trmAxis)
Definition: Clip.cpp:964
const char * GetName(void) const
Definition: DeclManager.h:140
Definition: Vector.h:316
void ReadBool(bool &value)
Definition: SaveGame.cpp:976
bool enabled
Definition: Clip.h:112
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glext.h:2878
idBounds absBounds
Definition: Clip.h:119
ID_INLINE T Square(T x)
Definition: Math.h:104
struct trmCache_s trmCache_t
contactType_t type
idVec3 centerOfMass
Definition: Clip.cpp:56
void ReadTraceModel(idTraceModel &trace)
Definition: SaveGame.cpp:1482
const idVec3 & GetOrigin(void) const
Definition: Clip.h:206
int numTranslations
Definition: Clip.h:317
int cmHandle_t
virtual const char * GetModelName(cmHandle_t model) const =0
idTraceModel trm
Definition: Clip.cpp:53
virtual int Contents(const idVec3 &start, const idTraceModel *trm, const idMat3 &trmAxis, int contentMask, cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis)=0
float GetRadius(void) const
Definition: Bounds.cpp:39
virtual int Contacts(contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth, const idTraceModel *trm, const idMat3 &trmAxis, int contentMask, cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis)=0
virtual void DrawModel(cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis, const idVec3 &viewOrigin, const float radius)=0
void Identity(void)
Definition: Matrix.h:591
bool IsRotated(void) const
Definition: Matrix.h:624
void GetMassProperties(const float density, float &mass, idVec3 &centerOfMass, idMat3 &inertiaTensor) const
int i
Definition: process.py:33
contactInfo_t c
GLuint GLuint num
Definition: glext.h:5390
void FromBoundsRotation(const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idRotation &rotation)
Definition: Bounds.cpp:386
void WriteVec3(const idVec3 &vec)
Definition: SaveGame.cpp:253
void Free(void)
Definition: HashIndex.cpp:75
const idTraceModel * TraceModelForClipModel(const idClipModel *mdl) const
Definition: Clip.cpp:944
void WriteMaterial(const idMaterial *material)
Definition: SaveGame.cpp:380
struct listParms_s listParms_t
int EntitiesTouchingBounds(const idBounds &bounds, int contentMask, idEntity **entityList, int maxCount) const
Definition: Clip.cpp:833
float fraction
virtual bool GetModelVertex(cmHandle_t model, int vertexNum, idVec3 &vertex) const =0
int First(const int key) const
Definition: HashIndex.h:238
idVec3 endpos
void WriteBool(const bool value)
Definition: SaveGame.cpp:222
int GetTraceClipModels(const idBounds &bounds, int contentMask, const idEntity *passEntity, idClipModel **clipModelList) const
Definition: Clip.cpp:870
void Init(void)
Definition: Clip.cpp:272
int numContacts
Definition: Clip.h:322
void void void Warning(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:735
idClipModel temporaryClipModel
Definition: Clip.h:313
int numContents
Definition: Clip.h:321
void FromBoundsTranslation(const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idVec3 &translation)
Definition: Bounds.cpp:290
idBlockAlloc< clipLink_t, 1024 > clipLinkAllocator
Definition: Clip.cpp:62
int numRenderModelTraces
Definition: Clip.h:320
const idMaterial * material
float GetAngle(void) const
Definition: Rotation.h:154
GLuint GLuint GLsizei count
Definition: glext.h:2845
idClipModel defaultClipModel
Definition: Clip.h:314
virtual cmHandle_t LoadModel(const char *modelName, const bool precache)=0
idPhysics * GetPhysics(void) const
Definition: Entity.cpp:2607
virtual void DebugLine(const idVec4 &color, const idVec3 &start, const idVec3 &end, const int lifetime=0, const bool depthTest=false)=0
void Shutdown(void)
Definition: Clip.cpp:715
void GetMassProperties(const float density, float &mass, idVec3 &centerOfMass, idMat3 &inertiaTensor) const
Definition: Clip.cpp:475
int GetNumPoints(void) const
Definition: Winding.h:238
int axis
Definition: Clip.cpp:38
void ReadFloat(float &value)
Definition: SaveGame.cpp:967
idBounds worldBounds
Definition: Clip.h:312
static void RestoreTraceModels(idRestoreGame *savefile)
Definition: Clip.cpp:178
int touchCount
Definition: Clip.h:127
idVec3 vec3_origin(0.0f, 0.0f, 0.0f)
struct clipSector_s * clipSectors
Definition: Clip.h:311
virtual bool GetModelPolygon(cmHandle_t model, int polygonNum, idFixedWinding &winding) const =0
void FromPointTranslation(const idVec3 &point, const idVec3 &translation)
Definition: Bounds.cpp:268
GLuint GLuint end
Definition: glext.h:2845
void WriteFloat(const float value)
Definition: SaveGame.cpp:213
type * Alloc(void)
Definition: Heap.h:197
virtual void Rotation(trace_t *results, const idVec3 &start, const idRotation &rotation, const idTraceModel *trm, const idMat3 &trmAxis, int contentMask, cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis)=0
virtual bool GetModelEdge(cmHandle_t model, int edgeNum, idVec3 &start, idVec3 &end) const =0
cmHandle_t Handle(void) const
Definition: Clip.cpp:457
#define NULL
Definition: Lib.h:88
idEntity * GetOwner(void) const
Definition: Clip.h:194
void Shutdown(void)
Definition: Heap.h:224
const int GetContentFlags(void) const
Definition: Material.h:497
static int AllocTraceModel(const idTraceModel &trm)
Definition: Clip.cpp:100
struct clipLink_s * clipLinks
Definition: Clip.cpp:41
virtual void Clear(void)
Definition: Winding.h:398
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)
Definition: Clip.cpp:1519
#define mat3_default
Definition: Matrix.h:413
static void SaveTraceModels(idSaveGame *savefile)
Definition: Clip.cpp:159
void PrintStatistics(void)
Definition: Clip.cpp:1606
bool IsTraceModel(void) const
Definition: Clip.h:218
void Save(idSaveGame *savefile) const
Definition: Clip.cpp:374
int numRotations
Definition: Clip.h:318
int touchCount
Definition: Clip.h:315
idMat3 endAxis
int renderModelHandle
Definition: Clip.h:124
int GetId(void) const
Definition: Clip.h:186
void DeleteContents(bool clear)
Definition: List.h:207
void TraceRenderModel(trace_t &trace, const idVec3 &start, const idVec3 &end, const float radius, const idMat3 &axis, idClipModel *touch) const
Definition: Clip.cpp:913
struct clipLink_s * clipLinks
Definition: Clip.h:126
void Link_r(struct clipSector_s *node)
Definition: Clip.cpp:513
virtual void DrawText(const char *text, const idVec3 &origin, float scale, const idVec4 &color, const idMat3 &viewAxis, const int align=1, const int lifetime=0, bool depthTest=false)=0
void FromTransformedBounds(const idBounds &bounds, const idVec3 &origin, const idMat3 &axis)
Definition: Bounds.cpp:232
#define MAX_SECTOR_DEPTH
Definition: Clip.cpp:34
idVec3 vec3_boxEpsilon(CM_BOX_EPSILON, CM_BOX_EPSILON, CM_BOX_EPSILON)
struct clipLink_s clipLink_t
idGameLocal gameLocal
Definition: Game_local.cpp:64
idVec3 origin
Definition: Clip.h:116
~idClipModel(void)
Definition: Clip.cpp:361
idBounds Expand(const float d) const
Definition: Bounds.h:317
int count
Definition: Clip.cpp:743
void ReadBounds(idBounds &bounds)
Definition: SaveGame.cpp:1038
int maxCount
Definition: Clip.cpp:744
virtual idClipModel * GetClipModel(int id=0) const =0
void WriteInt(const int value)
Definition: SaveGame.cpp:168
int contents
Definition: Clip.h:121
void WriteMat3(const idMat3 &mat)
Definition: SaveGame.cpp:309
const idVec3 & GetVec(void) const
Definition: Rotation.h:150
void ReadMat3(idMat3 &mat)
Definition: SaveGame.cpp:1064
int id
Definition: Clip.h:114
idVec4 colorCyan
Definition: Lib.cpp:122
struct clipSector_s * CreateClipSectors_r(const int depth, const idBounds &bounds, idVec3 &maxSector)
Definition: Clip.cpp:636
idVec3 normal
Definition: RenderWorld.h:248
int Append(const type &obj)
Definition: List.h:646
void Init(void)
Definition: Clip.cpp:684
void ClipModelsTouchingBounds_r(const struct clipSector_s *node, struct listParms_s &parms) const
Definition: Clip.cpp:747
Definition: Matrix.h:333
idVec3 point
Definition: RenderWorld.h:247
bool LineIntersection(const idVec3 &start, const idVec3 &end) const
Definition: Bounds.cpp:135
bool DrawModelContactFeature(const contactInfo_t &contact, const idClipModel *clipModel, int lifetime) const
Definition: Clip.cpp:1645
void SetOrigin(const idVec3 &rotationOrigin)
Definition: Rotation.h:115
tuple f
Definition: idal.py:89
#define ENTITYNUM_WORLD
Definition: Game_local.h:85
bool IsCleared(void) const
Definition: Bounds.h:222
bool LoadModel(const char *name)
Definition: Clip.cpp:215
const idMat3 & ToMat3(void) const
Definition: Rotation.cpp:60
int Num(void) const
Definition: List.h:265
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
const idMaterial * material
Definition: Clip.h:120
bool Rotation(trace_t &results, const idVec3 &start, const idRotation &rotation, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity)
Definition: Clip.cpp:1130
idVec3 GetCenter(void) const
Definition: Winding.cpp:639
GLsizei maxCount
Definition: glext.h:3628
int Contents(const idVec3 &start, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity)
Definition: Clip.cpp:1429
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)
Definition: Clip.cpp:1506
int ContentsModel(const idVec3 &start, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis)
Definition: Clip.cpp:1532
idEntity * owner
Definition: Clip.h:115
Definition: Str.h:116
idBounds bounds
Definition: RenderWorld.h:95
void WriteTraceModel(const idTraceModel &trace)
Definition: SaveGame.cpp:706
idClipModel(void)
Definition: Clip.cpp:295
const char * GetName(void) const
Definition: Entity.cpp:875
void ReadVec3(idVec3 &vec)
Definition: SaveGame.cpp:1011
const char * c_str(void) const
Definition: Str.h:487
cmHandle_t collisionModelHandle
Definition: Clip.h:122
idClip(void)
Definition: Clip.cpp:622
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)
Definition: Clip.cpp:1493
int numClipSectors
Definition: Clip.h:310
void TranslationEntities(trace_t &results, const idVec3 &start, const idVec3 &end, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity)
Definition: Clip.cpp:995
void WriteBounds(const idBounds &bounds)
Definition: SaveGame.cpp:280
const idVec3 & GetOrigin(void) const
Definition: Rotation.h:146
const idBounds & GetAbsBounds(void) const
Definition: Clip.h:202
void Free(type *element)
Definition: Heap.h:216
float dist
Definition: Clip.cpp:39
float fraction
Definition: RenderWorld.h:246
void Add(const int key, const int index)
Definition: HashIndex.h:193
virtual cmHandle_t SetupTrmModel(const idTraceModel &trm, const idMaterial *material)=0
static cmHandle_t CheckModel(const char *name)
Definition: Clip.cpp:604
GLint j
Definition: qgl.h:264
idBounds & ExpandSelf(const float d)
Definition: Bounds.h:322
virtual void DebugBounds(const idVec4 &color, const idBounds &bounds, const idVec3 &org=vec3_origin, const int lifetime=0)=0
struct clipSector_s clipSector_t
idRenderWorld * gameRenderWorld
Definition: Game_local.cpp:55
virtual bool ModelTrace(modelTrace_t &trace, qhandle_t entityHandle, const idVec3 &start, const idVec3 &end, const float radius) const =0
bool Translation(trace_t &results, const idVec3 &start, const idVec3 &end, const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity)
Definition: Clip.cpp:1056
float volume
Definition: Clip.cpp:55
int entityNumber
Definition: Entity.h:111
Definition: List.h:84
int GetDimension(void) const
Definition: Vector.h:707
idStr name
Definition: Entity.h:121
static idTraceModel * GetCachedTraceModel(int traceModelIndex)
Definition: Clip.cpp:140
int traceModelIndex
Definition: Clip.h:123
void Unlink(void)
Definition: Clip.cpp:491
struct clipSector_s * children[2]
Definition: Clip.cpp:40
virtual bool GetModelBounds(cmHandle_t model, idBounds &bounds) const =0
void Restore(idRestoreGame *savefile)
Definition: Clip.cpp:401
void Zero(void)
Definition: Vector.h:415
void ReadString(idStr &string)
Definition: SaveGame.cpp:985
idBounds bounds
Definition: TraceModel.h:94
#define JOINT_HANDLE_TO_CLIPMODEL_ID(id)
Definition: Clip.h:41
void ReadInt(int &value)
Definition: SaveGame.cpp:922
void SetPosition(const idVec3 &newOrigin, const idMat3 &newAxis)
Definition: Clip.cpp:444
idCollisionModelManager * collisionModelManager
virtual const renderEntity_t * GetRenderEntity(qhandle_t entityHandle) const =0
GLuint start
Definition: glext.h:2845
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)
Definition: Clip.cpp:1197
int contentMask
Definition: Clip.cpp:741
void ReadObject(idClass *&obj)
Definition: SaveGame.cpp:1083
#define ENTITYNUM_NONE
Definition: Game_local.h:84
static int GetTraceModelHashKey(const idTraceModel &trm)
Definition: Clip.cpp:149