00001 /* 00002 SagaEngine library 00003 Copyright (c) 2002-2006 Skalden Studio AS 00004 00005 This software is provided 'as-is', without any express or implied 00006 warranty. In no event will the authors be held liable for any 00007 damages arising from the use of this software. 00008 00009 Permission is granted to distribute the library under the terms of the 00010 Q Public License version 1.0. Be sure to read and understand the license 00011 before using the library. It should be included here, or you may read it 00012 at http://www.trolltech.com/products/qt/licenses/licensing/qpl 00013 00014 The original version of this library can be located at: 00015 http://www.sagaengine.com/ 00016 00017 Rune Myrland 00018 rune@skalden.com 00019 */ 00020 00021 00022 #include "CollisionComponent.hpp" 00023 #include "CollisionAreaComponent.hpp" 00024 #include "../schema/SimSchema.hpp" 00025 #include "util/error/Log.hpp" 00026 #include "../thing/Actor.hpp" 00027 #include "../react/all.hpp" 00028 #include "util/bounds/BoundingBox.hpp" 00029 #include "util/bounds/BoundingCylinder.hpp" 00030 00031 00032 namespace se_core { 00033 /* 00034 CollisionComponent 00035 ::CollisionComponent(Composite* owner, PosComponent* posComponent) 00036 : AreaChildComponent(sct_COLLISION, owner) 00037 , posComponent_(posComponent) 00038 , isCollideable_(false) 00039 , ignore_(0), p1_(0, 0, 0), p2_(0, 0, 0), radius_(0) { 00040 geometryType_ = geometryType(); 00041 } 00042 */ 00043 00044 00045 CollisionComponent 00046 ::CollisionComponent(Composite* owner, const ComponentFactory* factory) 00047 : AreaChildComponent(sct_COLLISION, owner, factory) 00048 , substance_(0) 00049 , isCollideable_(false), doObstructView_(false) 00050 , ignore_(0), p1_(0, 0, 0), p2_(0, 0, 0), radius_(0) { 00051 posComponent_ = static_cast<PosComponent*>(owner_->component(sct_POS)); 00052 Assert(posComponent_); 00053 geometryType_ = geometryType(); 00054 } 00055 00056 00057 CollisionComponent 00058 ::~CollisionComponent() { 00059 } 00060 00061 00062 bool CollisionComponent 00063 ::doObstructView() const { 00064 return doObstructView_; 00065 } 00066 00067 void CollisionComponent 00068 ::setCollideable(bool isCollideable) { 00069 if(isCollideable_ == isCollideable) 00070 return; 00071 00072 isCollideable_ = isCollideable; 00073 if(parent_) { 00074 CollisionAreaComponent* cac = static_cast<CollisionAreaComponent*>(parent_); 00075 if(isCollideable_) { 00076 updateAreaCovered(); 00077 cac->addCollideable(*this); 00078 } 00079 else { 00080 cac->removeCollideable(*this); 00081 } 00082 } 00083 } 00084 00085 00086 void CollisionComponent 00087 ::zoneChanged(int zoneType, Composite* newArea, Composite* oldArea) { 00088 if(zoneType != st_AREA) 00089 return; 00090 00091 if(oldArea) { 00092 resetParent(); 00093 if(isCollideable_) { 00094 CollisionAreaComponent* cac = static_cast<CollisionAreaComponent*>(oldArea->component(type())); 00095 cac->removeCollideable(*this); 00096 } 00097 } 00098 if(newArea) { 00099 CollisionAreaComponent* cac = static_cast<CollisionAreaComponent*>(newArea->component(type())); 00100 setParent(*cac); 00101 if(isCollideable_) { 00102 updateAreaCovered(); 00103 cac->addCollideable(*this); 00104 } 00105 } 00106 } 00107 00108 00109 void CollisionComponent 00110 ::updateAreaCovered() { 00111 geometryType_ = geometryType(); 00112 if(geometryType_ == geom_CYLINDER) { 00113 p1_.reset(); 00114 p2_.reset(); 00115 radius_ = posComponent_->nextPos().bounds_.radius(); 00116 BoundingBox toBox(posComponent_->nextPos().worldCoor(), posComponent_->nextPos().bounds_); 00117 areaCovered_ = toBox; 00118 if(posComponent_->pos().isKeyFramePath(posComponent_->nextPos())) { 00119 BoundingBox fromBox(posComponent_->pos().worldCoor(), posComponent_->pos().bounds_); 00120 areaCovered_.merge(fromBox); 00121 } 00122 } 00123 else if(geometryType_ == geom_LONG_CYLINDER) { 00124 const BoundingBox& b = posComponent().nextPos().bounds_; 00125 coor_t xSize = b.maxX_ - b.minX_; 00126 coor_t zSize = b.maxZ_ - b.minZ_; 00127 if(xSize > zSize) { 00128 radius_ = CoorT::half(zSize); 00129 p1_.z_ = p2_.z_ = CoorT::half(b.minZ_ + b.maxZ_); 00130 p1_.x_ = b.minX_ + radius_; 00131 p2_.x_ = b.maxX_ - radius_; 00132 } 00133 else { 00134 radius_ = CoorT::half(xSize); 00135 p1_.x_ = p2_.x_ = CoorT::half(b.minX_ + b.maxX_); 00136 p1_.z_ = b.minZ_ + radius_; 00137 p2_.z_ = b.maxZ_ - radius_; 00138 } 00139 p1_.y_ = p2_.y_ = b.minY_; 00140 00141 Euler3& face = posComponent_->nextPos().worldFace(); 00142 if(!face.isIdentity()) { 00143 AssertWarning(face.pitch_ == 0 || face.roll_ == 0, "Pitch and roll not supported for non-cylindrical things"); 00144 if(face.pitch_ != 0 || face.roll_ != 0) { 00145 setCollideable(false); 00146 } 00147 p1_.rotate(face); 00148 p2_.rotate(face); 00149 } 00150 00151 Point3 wp1, wp2; 00152 wp1.add(p1_, posComponent_->nextPos().worldCoor()); 00153 wp2.add(p2_, posComponent_->nextPos().worldCoor()); 00154 00155 coor_t height = b.maxY_ - b.minY_; 00156 00157 BoundingBox b1(wp1, radius_, height); 00158 BoundingBox b2(wp2, radius_, height); 00159 areaCovered_ = b1; 00160 areaCovered_.merge(b2); 00161 } 00162 00163 } 00164 00165 00166 void CollisionComponent 00167 ::move() { 00168 if(!parent_) 00169 return; 00170 00171 Point3 oldPos, newPos; 00172 coor_t oldRadius = areaCovered().radius(); 00173 areaCovered().center(oldPos); 00174 00175 updateAreaCovered(); 00176 00177 coor_t newRadius = areaCovered().radius(); 00178 areaCovered().center(newPos); 00179 00180 CollisionAreaComponent* const cac = static_cast<CollisionAreaComponent*>(parent_); 00181 Assert(cac->collisionGrid()); 00182 cac->collisionGrid()->move(oldPos, oldRadius, newPos, newRadius, *this); 00183 } 00184 00185 00186 float CollisionComponent 00187 ::penetration(const CollisionComponent& other) const { 00188 Point3 p, t; 00189 coor_t radSum = bouncePoints(SCALE_RES, other, p, t); 00190 float pen = radSum - CoorT::sqrt(p.xzDistanceSquared(t)); 00191 if(pen < 0) 00192 return 0; 00193 return pen; 00194 } 00195 00196 00197 bool CollisionComponent 00198 ::doesGeometryCollide(const CollisionComponent& other) const { 00199 Point3 p, t; 00200 coor_t radSum = bouncePoints(SCALE_RES, other, p, t); 00201 bool res = (p.xzDistanceSquared(t) < radSum * radSum); 00202 return res; 00203 } 00204 00205 00206 bool CollisionComponent 00207 ::didGeometryCollide(const CollisionComponent& other) const { 00208 Point3 p, t; 00209 coor_t radSum = bouncePoints(0, other, p, t); 00210 return (p.xzDistanceSquared(t) < radSum * radSum); 00211 } 00212 00213 00214 scale_t CollisionComponent 00215 ::whenDoesGeometryCollide(const CollisionComponent& other) const { 00216 // Only cylinder support at the moment 00217 const PosComponent& pusher = posComponent(); 00218 const PosComponent& target = other.posComponent(); 00219 00220 coor_t radiusSum = pusher.nextPos().bounds_.smallRadius() + target.nextPos().bounds_.smallRadius(); 00221 coor_t radiusSumSq = radiusSum * radiusSum; 00222 00223 Point3 tNow, tNext; 00224 00225 scale_t min = 0, max = 1; 00226 Point3 mp, mt; 00227 for(int i = 0; i < 8; ++i) { 00228 scale_t middle = (min + max) / 2; 00229 pusher.worldCoor(middle, mp); 00230 //target.worldCoor(middle, mt); 00231 other.bouncePoint(middle, mp, mt); 00232 00233 coor_double_t dSq = mp.xzDistanceSquared(mt); 00234 if(dSq > radiusSumSq) { 00235 min = middle; 00236 } 00237 else { 00238 max = middle; 00239 } 00240 } 00241 return min; 00242 } 00243 00244 00245 int CollisionComponent 00246 ::tag() const { 00247 return owner()->tag(); 00248 } 00249 00250 00251 coor_t CollisionComponent 00252 ::bouncePoint(const Point3& c, const Point3& testPoint, Point3& dest) const { 00253 if(geometryType_ == geom_CYLINDER) { 00254 dest.set(c); 00255 return radius_; 00256 } 00257 00258 Point3 wp1, wp2; 00259 wp1.add(c, p1_); 00260 wp2.add(c, p2_); 00261 dest.nearestPoint(wp1, wp2, testPoint); 00262 return radius_; 00263 } 00264 00265 00266 coor_t CollisionComponent 00267 ::bouncePoints(const Point3& o1, const Point3& o2, Point3& d1, Point3& d2) const { 00268 areaCovered().center(d1); 00269 if(geometryType_ == geom_CYLINDER) { 00270 d2.nearestPoint(o1, o2, d1); 00271 return radius_; 00272 } 00273 00274 Point3 wp1, wp2; 00275 wp1.add(d1, p1_); 00276 wp2.add(d1, p2_); 00277 00278 for(int i = 0; i < 8; ++i) { 00279 d2.nearestPoint(o1, o2, d1); 00280 d1.nearestPoint(wp1, wp2, d2); 00281 } 00282 return radius_; 00283 } 00284 00285 00286 coor_t CollisionComponent 00287 ::bouncePoint(scale_t alpha, const Point3& testPoint, Point3& dest) const { 00288 Point3 c; 00289 posComponent().worldCoor(alpha, c); 00290 return bouncePoint(c, testPoint, dest); 00291 } 00292 00293 coor_t CollisionComponent 00294 ::bouncePoints(scale_t alpha, const CollisionComponent& other, Point3& d1, Point3& d2) const { 00295 Point3 tmp; 00296 other.posComponent().worldCoor(alpha, tmp); 00297 coor_t radSum = bouncePoint(alpha, tmp, d1); 00298 radSum += other.bouncePoint(alpha, d1, d2); 00299 d1.y_ = d2.y_; 00300 return radSum; 00301 } 00302 00303 bool CollisionComponent 00304 ::shouldIgnore(const CollisionComponent& cc) const { 00305 return &cc == ignore_ || cc.ignore_ == this; 00306 } 00307 }
Home Page | SagaEngine trunk (updated nightly) reference generated Sun Dec 2 20:06:11 2007 by Doxygen version 1.3.9.1.