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 "Pos.hpp" 00023 #include "Anim.hpp" 00024 #include "PosComponent.hpp" 00025 #include "../area/Area.hpp" 00026 #include "../sim.hpp" 00027 #include "../schema/SimSchema.hpp" 00028 #include "util/math/util_math.hpp" 00029 #include "util/math/all.hpp" 00030 #include <cstdio> 00031 #include <cstring> 00032 00033 00034 namespace se_core { 00035 00036 Pos 00037 ::Pos() : area_(0) 00038 , parent_(0) 00039 , index_(-1) 00040 , isGrounded_(true) 00041 { 00042 anim(0).setWeight(1); 00043 local_.setIdentity(); 00044 world_.setIdentity(); 00045 } 00046 00047 00048 short Pos 00049 ::terrainStyle() const { 00050 if(!hasArea()) 00051 return TS_VOID; 00052 const Area::Ptr a(area()); 00053 return a->terrainStyle(this->localCoor(), index()); 00054 } 00055 00056 long Pos 00057 ::touchedTerrain() const { 00058 if(!hasArea()) 00059 return TSM_VOID; 00060 const Area::Ptr a(area()); 00061 return a->touchedTerrain(this->localCoor(), radius()); 00062 } 00063 00064 00065 bool Pos 00066 ::isKeyFramePath(const Pos& other) const { 00067 // Check that both positions are inside an area 00068 if(!hasArea() || !other.hasArea()) 00069 return false; 00070 00071 00072 // Normal success case. Eliminate quickly. 00073 if(area_ == other.area_) 00074 return true; 00075 00076 // Are pages not neighbours? 00077 const Area::Ptr a(area()); 00078 const Area::Ptr oth(other.area_); 00079 if(!(a->isNeighbour(*(oth)))) 00080 return false; 00081 00082 // All negative cases eliminated 00083 return true; 00084 } 00085 00086 /* 00087 coor_world_t Pos 00088 ::pageDistanceSquared(const Pos& p) const { 00089 // Value returned if no legal path exists 00090 // TODO: Should perhaps be negative 00091 static const coor_world_t NO_PATH = -1; 00092 00093 if(!hasArea() || !p.hasArea()) { 00094 // return error distance 00095 return NO_PATH; 00096 } 00097 if(!isKeyFramePath(p)) { 00098 // return error distance 00099 return NO_PATH; 00100 } 00101 coor_world_t fromX = (coor_world_t)p.area()->pagePosX() 00102 + (coor_world_t)p.localCoor().x_; 00103 coor_world_t toX = (coor_world_t)area()->pagePosX() 00104 + (coor_world_t)localCoor().x_; 00105 00106 coor_world_t fromZ = ((coor_world_t)p.area()->pagePosZ() 00107 + (coor_world_t)p.localCoor().z_); 00108 coor_world_t toZ = ((coor_world_t)area()->pagePosZ() 00109 + (coor_world_t)localCoor().z_); 00110 00111 coor_world_t xDist = fromX - toX; 00112 coor_world_t zDist = fromZ - toZ; 00113 00114 //long xDist = (p.x_) - (x_); 00115 //long zDist = (p.z_) - (z_); 00116 00117 coor_world_t xDistSquared = xDist * xDist; 00118 coor_world_t zDistSquared = zDist * zDist; 00119 coor_world_t distSquared = xDistSquared + zDistSquared; 00120 00121 00122 # ifdef SE_FIXED_POINT 00123 // Overflowing distances are clamped down 00124 // to this legal distance 00125 static const coor_world_t OVERFLOWED = -2; 00126 00127 // Prevent overflow 00128 if(xDist > 0x7fff || xDist < -0x7fff || zDist > 0x7fff || zDist < -0x7fff) 00129 // Return greatest legal distance 00130 return OVERFLOWED; 00131 00132 // May overflow on adding xDistSquared and yDistSquared 00133 if(distSquared < 0) 00134 return OVERFLOWED; 00135 # endif 00136 00137 return distSquared; 00138 } 00139 */ 00140 00141 00142 void Pos 00143 ::setPos(const Pos& original) { 00144 local_.setViewPoint(original.local_); 00145 world_.setViewPoint(original.world_); 00146 area_ = original.area_; 00147 parent_ = original.parent_; 00148 index_ = original.index_; 00149 isGrounded_ = original.isGrounded_; 00150 bounds_ = original.bounds_; 00151 for(int i = 0; i < MAX_ANIMS; ++i) 00152 anim_[i] = original.anim_[i]; 00153 } 00154 00155 00156 void Pos 00157 ::swapAnims(int a, int b) { 00158 Anim tmp(anim_[a]); 00159 anim_[a] = anim_[b]; 00160 anim_[b] = tmp; 00161 } 00162 00163 void Pos 00164 ::setXZ(const Pos& original) { 00165 // Revert coordinates in xz plane. (Can still fall.) 00166 localCoor().x_ = original.localCoor().x_; 00167 localCoor().z_ = original.localCoor().z_; 00168 worldCoor().x_ = original.worldCoor().x_; 00169 worldCoor().z_ = original.worldCoor().z_; 00170 area_ = original.area_; 00171 } 00172 00173 00174 void Pos 00175 ::resetParent(bool doKeepWorldCoor) { 00176 parent_ = area_; 00177 00178 if(doKeepWorldCoor) { 00179 local_.setViewPoint(world_); 00180 } 00181 else { 00182 world_.setViewPoint(local_); 00183 } 00184 } 00185 00186 00187 bool Pos 00188 ::didParentMove() const { 00189 return parent_ != 0 && parent_->didMove(); 00190 } 00191 00192 00193 void Pos 00194 ::setParent(PosComponent& p, bool doKeepWorldCoor) { 00195 parent_ = &p; 00196 if(doKeepWorldCoor) { 00197 local_.setViewPoint(world_); 00198 local_.sub(p.nextPos().world_); 00199 } 00200 } 00201 00202 00203 void Pos 00204 ::setArea(PosComponent& area, bool doKeepWorldCoor) { 00205 //LogDetail(area.name()); 00206 if(parent_ == area_) { 00207 // Area is the root parent node 00208 setParent(area, doKeepWorldCoor); 00209 //parent_ = &area; 00210 } 00211 area_ = &area; 00212 updateIndex(); 00213 } 00214 00215 00216 void Pos 00217 ::setArea(PosComponent& area, const ViewPoint& vp, bool isLocalViewPoint) { 00218 if(parent_ == area_) { 00219 // Area is the root parent node 00220 parent_ = &area; 00221 } 00222 area_ = &area; 00223 if(isLocalViewPoint) { 00224 local_.setViewPoint(vp); 00225 updateWorldViewPoint(); 00226 } 00227 else { 00228 world_.setViewPoint(vp); 00229 updateLocalViewPoint(); 00230 } 00231 updateIndex(); 00232 } 00233 00234 00235 bool Pos 00236 ::hasArea(Composite& area) const { 00237 return area_ != 0 && area_->owner() == &area; 00238 } 00239 00240 00241 bool Pos 00242 ::hasArea(Component& area) const { 00243 return area_ != 0 && area_->owner() == area.owner(); 00244 } 00245 00246 00247 PosComponent* Pos 00248 ::updateArea() { 00249 // Entered new area? 00250 Area::Ptr next(area_); 00251 if(!next->isLegalWorldCoor(worldCoor())) { 00252 Area* a = next->neighbour(worldCoor()); 00253 if(a) { 00254 // Change area, keep world viewpoint 00255 setArea(*PosComponent::get(*a), true); 00256 next = a; 00257 // Cannot use old index as hint for index in new area 00258 setNoIndex(); 00259 } 00260 } 00261 00262 // Calc navigation mesh triangle id 00263 short newIndex = next->index(worldCoor(), index()); 00264 setIndex(newIndex); 00265 return area_; 00266 } 00267 00268 00269 void Pos 00270 ::updateIndex() { 00271 Area::Ptr next(area_); 00272 short newIndex = next->index(worldCoor(), -1); 00273 setIndex(newIndex); 00274 } 00275 00276 00277 void Pos 00278 ::resetArea() { 00279 if(parent_ == area_) { 00280 parent_ = 0; 00281 } 00282 area_ = 0; 00283 } 00284 00285 00286 void Pos 00287 ::updateWorldViewPoint() { 00288 world_.setViewPoint(local_); 00289 if(hasParent()) { 00290 // Parent should already have updated their worldViewPoint 00291 world_.add( parent()->nextPos().world_ ); 00292 } 00293 } 00294 00295 00296 void Pos 00297 ::areaCoor(const PosComponent& a, Point3& dest) const { 00298 dest.set( world_.coor_ ); 00299 Assert(a.nextPos().worldFace().isIdentity()); 00300 dest.sub( a.nextPos().world_.coor_ ); 00301 } 00302 00303 00304 void Pos 00305 ::areaFace(const PosComponent& a, Euler3& dest) const { 00306 dest.set( world_.face_ ); 00307 Assert(a.nextPos().worldFace().isIdentity()); 00308 dest.sub( a.nextPos().world_.face_ ); 00309 } 00310 00311 00312 void Pos 00313 ::areaViewPoint(const PosComponent& a, ViewPoint& dest) const { 00314 dest.setViewPoint(world_); 00315 dest.sub( a.nextPos().world_ ); 00316 } 00317 00318 void Pos 00319 ::updateLocalViewPoint() { 00320 local_.setViewPoint(world_); 00321 if(hasParent()) { 00322 // Parent should already have updated their worldViewPoint 00323 local_.sub( parent()->nextPos().world_ ); 00324 } 00325 } 00326 00327 00328 bool Pos 00329 ::isInsideCollisionRange(const Pos& p) const { 00330 coor_double_t collisionRange = p.radius() + radius(); 00331 return collisionRange * collisionRange >= worldCoor().distanceSquared(p.worldCoor()); 00332 } 00333 00334 00335 bool Pos 00336 ::isInsideCollisionRangeLinf(const Pos& p) const { 00337 coor_t collisionRange = p.radius() + radius(); 00338 return worldCoor().xzDistanceLinf(p.worldCoor()) <= collisionRange; 00339 } 00340 00341 00342 bool Pos 00343 ::hasInFront(const Point3& coor) const { 00344 // TODO: 00345 LogFatal("TODO:"); 00346 return false; // (xzFaceAwayAngle(coor) < (BrayT::DEG180 >> 1)); 00347 } 00348 00349 00350 void Pos 00351 ::updateY() { 00352 if(isGrounded() && area_) { 00353 const Area::Ptr a(area()); 00354 localCoor().y_ = a->groundHeight(localCoor(), index_); 00355 } 00356 } 00357 00358 }
Home Page | SagaEngine trunk (updated nightly) reference generated Sun Dec 2 20:06:11 2007 by Doxygen version 1.3.9.1.