00001 #ifndef _ID_TABLE_H_
00002 #define _ID_TABLE_H_
00003 #include "key_mutable_set.h"
00004 #include "ext_stl.h"
00005 #include "collidable.h"
00006
00008 const int fudgeFactor = 1;
00009
00011 template<class T>
00012 class IdTable {
00013 private:
00014 class CollideKeyLess {
00015 public:
00016 bool operator() (const KeyMutableShell<T> &a, const KeyMutableShell<T> &b) const {
00017 return (a->getCollideKey()<b->getCollideKey());
00018 }
00019 };
00020 class MeshIdLess {
00021 public:
00022 bool operator() (const MutableShell<T> &a, const MutableShell<T> &b) const {
00023 if (a->model==b->model) {
00024 return (a->getId()<b->getId());
00025 } else {
00026 return (a->model<b->model);
00027 }
00028 }
00029 };
00031 typedef MutableSet <T, MeshIdLess> MeshMapClass;
00032 typedef KeyMutableSet <typename T::CollideKey, T, CollideKeyLess> CollideMapClass;
00033 typedef Hashtable <int, T *, 65535 > IdMap;
00034 std::vector<int> deleteQueue;
00035 private:
00036 MeshMapClass meshMap;
00037 IdMap idMap;
00038 CollideMapClass collideMap;
00039
00040 inline void incrementAndCheck (typename CollideMapClass::iterator &iter) {
00041 iter=collideMap.changeKey(iter,(*iter)->recalculateCollideKey());
00042 }
00043 protected:
00045 bool del (int id) {
00046 using std::vector;
00047 T *spec=idMap.Get(id);
00048 if (!spec) {
00049 return false;
00050 }
00051 idMap.Delete(id);
00052 {
00053 typename CollideMapClass::iterator iter=collidemap.find(spec->getCollideKey());
00054 while (iter!=collidemap.end()) {
00055 if (spec==(*iter).second) {
00056 collidemap.erase(iter);
00057 }
00058 iter++;
00059 }
00060 }
00061 typename MeshMapClass::iterator iter=meshmap.find(spec);
00062 if (&(*iter)==spec) {
00063 meshmap.erase(iter);
00064 break;
00065 }
00066 return true;
00067 }
00068 public:
00069 void eraseAll () {
00070 meshMap.clear();
00071
00072 collideMap.clear();
00073 deleteQueue.clear();
00074 }
00076 int add (const T &s) {
00077 static int numgen=0;
00078 typename MeshMapClass::iterator iter= meshMap.insert(s);
00079 T *collidableToInsert=&(*iter).get();
00080 collideMap.insert(collidableToInsert);
00081 collidableToInsert->setId(numgen++);
00082 idMap.Put(collidableToInsert->getId(),collidableToInsert);
00083 return collidableToInsert->getId();
00084 }
00086 void kill(int id) {
00087 deleteQueue.push_back (id);
00088 }
00090 T * getById (int id) {
00091 typename IdMap::iterator iter = idMap.find(id);
00092 if (iter!=iter.end()) {
00093 return (*iter).second;
00094 } else {
00095 return NULL;
00096 }
00097 }
00098
00099
00100
00101
00103 void updateDeleteList() {
00104 while (!deleteQueue.empty()){
00105 Del (deleteQueue.back());
00106 deleteQueue.pop_back();
00107 }
00108 }
00110 void draw ();
00112 void update ();
00114 template <class Coll> void collideWithOther(Coll *coll, int surface, double minRadius, double maxRadius) {
00115 typename CollideMapClass::iterator othiter;
00116 typename T::CollideKey collideKey (surface,minRadius);
00117 othiter=this->collideMap.lower_bound(collideKey);
00118 while (othiter!=this->collideMap.end()&&(*othiter)->getCollideKey().radius<=maxRadius) {
00119 (*othiter)->collide(coll);
00120 ++othiter;
00121 }
00122 }
00124 void collideWithBolts() {
00125
00126 IdTable<Bolt> *btable=&world->surfaces[0]->boltField;
00127 typename CollideMapClass::iterator thisiter=collideMap.begin();
00128 for (;
00129 thisiter!=collideMap.end();
00130 ++thisiter) {
00131 const typename T::CollideKey &collideKey = ((*thisiter)->getCollideKey());
00132 int surface=collideKey.surface;
00133 btable=&world->surfaces[surface]->boltField;
00134 T * c = (*thisiter);
00135 float cRadius=c->getRadius();
00136 btable->collideWithOther(c,surface,collideKey.radius-fudgeFactor-cRadius,collideKey.radius+fudgeFactor+cRadius);
00137 }
00138 }
00139 void fixCollideOrder() {
00140 for (typename CollideMapClass::iterator thisiter=collideMap.begin();
00141 thisiter!=collideMap.end();
00142 incrementAndCheck(thisiter)) {}
00143 }
00145 void collideWithSame() {
00146 for (typename CollideMapClass::iterator thisiter=collideMap.begin();
00147 thisiter!=collideMap.end();
00148 ++thisiter) {
00149 const typename T::CollideKey &collideKey = ((*thisiter)->getCollideKey());
00150 for (typename CollideMapClass::iterator backward=thisiter;;) {
00151 if (backward==collideMap.begin())
00152 break;
00153 --backward;
00154 const typename T::CollideKey &backCollideKey = ((*backward)->getCollideKey());
00155 if ((backCollideKey.radius<(collideKey.radius-fudgeFactor-(2 * (*thisiter)->getRadius())))||(backCollideKey.surface!=collideKey.surface)) {
00156 break;
00157 }
00158 (*thisiter)->collide(*backward);
00159 }
00160 bool reachedthisiter=false;
00161 typename CollideMapClass::iterator otheriter=thisiter;
00162 ++otheriter;
00163 for (;otheriter!=collideMap.end();++otheriter) {
00164 const typename T::CollideKey &forwardCollideKey = ((*otheriter)->getCollideKey());
00165 if (forwardCollideKey.radius>(collideKey.radius+fudgeFactor+(2 * (*thisiter )->getRadius()))||forwardCollideKey.surface!=collideKey.surface) {
00166 break;
00167 }
00168 (*thisiter)->collide(*otheriter);
00169 }
00170 }
00171 }
00172 };
00173 #endif