CollisionComponent.cpp

Go to the documentation of this file.
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.

SourceForge.net Logo