pathManager.cpp
Engine/source/scene/pathManager.cpp
Classes:
class
Public Variables
bool
For frame signal.
Public Functions
ConsoleDocClass(PathManagerEvent , "@brief Class responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the registration, transmission , and management " "of paths on client and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n\n</a>" "For internal use only, not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> use in TorqueScript or game <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">development\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">internal\n</a>" )
DefineConsoleFunction(clearClientPaths , void , () , "" )
DefineConsoleFunction(clearServerPaths , void , () , "" )
Detailed Description
Public Variables
gClientPathManager
bool gEditingMission
For frame signal.
gServerPathManager
MODULE_END
MODULE_INIT
MODULE_SHUTDOWN
Public Functions
ConsoleDocClass(PathManagerEvent , "@brief Class responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the registration, transmission , and management " "of paths on client and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n\n</a>" "For internal use only, not intended <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> use in TorqueScript or game <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">development\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">internal\n</a>" )
DefineConsoleFunction(clearClientPaths , void , () , "" )
DefineConsoleFunction(clearServerPaths , void , () , "" )
IMPLEMENT_CO_NETEVENT_V1(PathManagerEvent )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "gfx/gfxDevice.h" 25#include "scene/pathManager.h" 26#include "sim/netConnection.h" 27#include "core/stream/bitStream.h" 28#include "scene/simPath.h" 29#include "math/mathIO.h" 30#include "scene/sceneRenderState.h" 31#include "scene/sceneManager.h" 32#include "platform/profiler.h" 33#include "core/module.h" 34#include "console/engineAPI.h" 35 36extern bool gEditingMission; 37 38 39namespace { 40 41U32 countNumBits(U32 n) 42{ 43 U32 count = 0; 44 while (n != 0) { 45 n >>= 1; 46 count++; 47 } 48 49 return count ? count : 1; 50} 51 52} // namespace {} 53 54 55MODULE_BEGIN( PathManager ) 56 57 MODULE_INIT 58 { 59 AssertFatal(gClientPathManager == NULL && gServerPathManager == NULL, "Error, already initialized the path manager!"); 60 61 gClientPathManager = new PathManager(false); 62 gServerPathManager = new PathManager(true); 63 } 64 65 MODULE_SHUTDOWN 66 { 67 AssertFatal(gClientPathManager != NULL && gServerPathManager != NULL, "Error, path manager not initialized!"); 68 69 delete gClientPathManager; 70 gClientPathManager = NULL; 71 delete gServerPathManager; 72 gServerPathManager = NULL; 73 } 74 75MODULE_END; 76 77 78//-------------------------------------------------------------------------- 79//-------------------------------------- PathManagerEvent 80// 81class PathManagerEvent : public NetEvent 82{ 83 public: 84 U32 modifiedPath; 85 bool clearPaths; 86 PathManager::PathEntry path; 87 88 public: 89 typedef NetEvent Parent; 90 PathManagerEvent() : modifiedPath(0), clearPaths(false) { } 91 92 void pack(NetConnection*, BitStream*); 93 void write(NetConnection*, BitStream*); 94 void unpack(NetConnection*, BitStream*); 95 void process(NetConnection*); 96 97 DECLARE_CONOBJECT(PathManagerEvent); 98}; 99 100void PathManagerEvent::pack(NetConnection*, BitStream* stream) 101{ 102 // Write out the modified path... 103 stream->write(modifiedPath); 104 stream->writeFlag(clearPaths); 105 stream->write(path.totalTime); 106 stream->write(path.positions.size()); 107 108 109 // This is here for safety. You can remove it if you want to try your luck at bigger sizes. -- BJG 110 AssertWarn(path.positions.size() < 1500/40, "Warning! Path size is pretty big - may cause packet overrun!"); 111 112 // Each one of these is about 8 floats and 2 ints 113 // so we'll say it's about 40 bytes in size, which is where the 40 in the above calc comes from. 114 for (U32 j = 0; j < path.positions.size(); j++) 115 { 116 mathWrite(*stream, path.positions[j]); 117 mathWrite(*stream, path.rotations[j]); 118 stream->write(path.msToNext[j]); 119 stream->write(path.smoothingType[j]); 120 } 121} 122 123void PathManagerEvent::write(NetConnection*nc, BitStream *stream) 124{ 125 pack(nc, stream); 126} 127 128void PathManagerEvent::unpack(NetConnection*, BitStream* stream) 129{ 130 // Read in the modified path... 131 132 stream->read(&modifiedPath); 133 clearPaths = stream->readFlag(); 134 stream->read(&path.totalTime); 135 136 U32 numPoints; 137 stream->read(&numPoints); 138 path.positions.setSize(numPoints); 139 path.rotations.setSize(numPoints); 140 path.msToNext.setSize(numPoints); 141 path.smoothingType.setSize(numPoints); 142 for (U32 j = 0; j < path.positions.size(); j++) 143 { 144 mathRead(*stream, &path.positions[j]); 145 mathRead(*stream, &path.rotations[j]); 146 stream->read(&path.msToNext[j]); 147 stream->read(&path.smoothingType[j]); 148 } 149} 150 151void PathManagerEvent::process(NetConnection*) 152{ 153 if (clearPaths) 154 { 155 // Clear out all the client's paths... 156 gClientPathManager->clearPaths(); 157 } 158 AssertFatal(modifiedPath <= gClientPathManager->mPaths.size(), "Error out of bounds path!"); 159 if (modifiedPath == gClientPathManager->mPaths.size()) { 160 PathManager::PathEntry *pe = new PathManager::PathEntry; 161 *pe = path; 162 gClientPathManager->mPaths.push_back(pe); 163 } 164 else 165 *(gClientPathManager->mPaths[modifiedPath]) = path; 166} 167 168IMPLEMENT_CO_NETEVENT_V1(PathManagerEvent); 169 170// Will be internalized once the @internal tag is working 171ConsoleDocClass( PathManagerEvent, 172 "@brief Class responsible for the registration, transmission, and management " 173 "of paths on client and server.\n\n" 174 175 "For internal use only, not intended for use in TorqueScript or game development\n\n" 176 177 "@internal\n" 178); 179 180//-------------------------------------------------------------------------- 181//-------------------------------------- PathManager Implementation 182// 183PathManager* gClientPathManager = NULL; 184PathManager* gServerPathManager = NULL; 185 186//-------------------------------------------------------------------------- 187PathManager::PathManager(const bool isServer) 188{ 189 VECTOR_SET_ASSOCIATION(mPaths); 190 191 mIsServer = isServer; 192} 193 194PathManager::~PathManager() 195{ 196 clearPaths(); 197} 198 199void PathManager::clearPaths() 200{ 201 for (U32 i = 0; i < mPaths.size(); i++) 202 delete mPaths[i]; 203 mPaths.setSize(0); 204#ifdef TORQUE_DEBUG 205 // This gets rid of the memory used by the vector. 206 // Prevents it from showing up in memory leak logs. 207 mPaths.compact(); 208#endif 209} 210 211DefineConsoleFunction( clearServerPaths, void, ( ), , "") 212{ 213 gServerPathManager->clearPaths(); 214} 215 216DefineConsoleFunction( clearClientPaths, void, ( ), , "") 217{ 218 gClientPathManager->clearPaths(); 219} 220 221//-------------------------------------------------------------------------- 222U32 PathManager::allocatePathId() 223{ 224 mPaths.increment(); 225 mPaths.last() = new PathEntry; 226 227 return (mPaths.size() - 1); 228} 229 230 231void PathManager::updatePath(const U32 id, 232 const Vector<Point3F>& positions, 233 const Vector<QuatF>& rotations, 234 const Vector<U32>& times, 235 const Vector<U32>& smoothingTypes) 236{ 237 AssertFatal(mIsServer == true, "PathManager::updatePath: Error, must be called on the server side"); 238 AssertFatal(id < mPaths.size(), "PathManager::updatePath: error, id out of range"); 239 AssertFatal(positions.size() == times.size() && positions.size() == smoothingTypes.size(), "Error, times and positions must match!"); 240 241 PathEntry& rEntry = *mPaths[id]; 242 243 rEntry.positions = positions; 244 rEntry.rotations = rotations; 245 rEntry.msToNext = times; 246 rEntry.smoothingType = smoothingTypes; 247 248 rEntry.totalTime = 0; 249 for (S32 i = 0; i < S32(rEntry.msToNext.size()); i++) 250 rEntry.totalTime += rEntry.msToNext[i]; 251 252 transmitPath(id); 253} 254 255 256//-------------------------------------------------------------------------- 257void PathManager::transmitPaths(NetConnection* nc) 258{ 259 AssertFatal(mIsServer, "Error, cannot call transmitPaths on client path manager!"); 260 261 // Send over paths 262 for(S32 i = 0; i < mPaths.size(); i++) 263 { 264 PathManagerEvent* event = new PathManagerEvent; 265 event->clearPaths = (i == 0); 266 event->modifiedPath = i; 267 event->path = *(mPaths[i]); 268 nc->postNetEvent(event); 269 } 270} 271 272void PathManager::transmitPath(const U32 id) 273{ 274 AssertFatal(mIsServer, "Error, cannot call transmitNewPath on client path manager!"); 275 276 // Post to all active clients that have already received their paths... 277 // 278 SimGroup* pClientGroup = Sim::getClientGroup(); 279 for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++) { 280 NetConnection* nc = dynamic_cast<NetConnection*>(*itr); 281 if (nc && nc->missionPathsSent()) 282 { 283 // Transmit the updated path... 284 PathManagerEvent* event = new PathManagerEvent; 285 event->modifiedPath = id; 286 event->clearPaths = false; 287 event->path = *(mPaths[id]); 288 nc->postNetEvent(event); 289 } 290 } 291} 292 293void PathManager::getPathPosition(const U32 id, 294 const F64 msPosition, 295 Point3F& rPosition, 296 QuatF &rotation) 297{ 298 AssertFatal(isValidPath(id), "Error, this is not a valid path!"); 299 PROFILE_START(PathManGetPos); 300 301 // Ok, query holds our path information... 302 F64 ms = msPosition; 303 if (ms > mPaths[id]->totalTime) 304 ms = mPaths[id]->totalTime; 305 306 S32 startNode = 0; 307 while (ms > mPaths[id]->msToNext[startNode]) { 308 ms -= mPaths[id]->msToNext[startNode]; 309 startNode++; 310 } 311 S32 endNode = (startNode + 1) % mPaths[id]->positions.size(); 312 313 Point3F& rStart = mPaths[id]->positions[startNode]; 314 Point3F& rEnd = mPaths[id]->positions[endNode]; 315 316 F64 interp = ms / F32(mPaths[id]->msToNext[startNode]); 317 if(mPaths[id]->smoothingType[startNode] == Marker::SmoothingTypeLinear) 318 { 319 rPosition = (rStart * (1.0 - interp)) + (rEnd * interp); 320 } 321 else if(mPaths[id]->smoothingType[startNode] == Marker::SmoothingTypeAccelerate) 322 { 323 interp = mSin(interp * M_PI - (M_PI / 2)) * 0.5 + 0.5; 324 rPosition = (rStart * (1.0 - interp)) + (rEnd * interp); 325 } 326 else if(mPaths[id]->smoothingType[startNode] == Marker::SmoothingTypeSpline) 327 { 328 S32 preStart = startNode - 1; 329 S32 postEnd = endNode + 1; 330 if(postEnd >= mPaths[id]->positions.size()) 331 postEnd = 0; 332 if(preStart < 0) 333 preStart = mPaths[id]->positions.size() - 1; 334 Point3F p0 = mPaths[id]->positions[preStart]; 335 Point3F p1 = rStart; 336 Point3F p2 = rEnd; 337 Point3F p3 = mPaths[id]->positions[postEnd]; 338 rPosition.x = mCatmullrom(interp, p0.x, p1.x, p2.x, p3.x); 339 rPosition.y = mCatmullrom(interp, p0.y, p1.y, p2.y, p3.y); 340 rPosition.z = mCatmullrom(interp, p0.z, p1.z, p2.z, p3.z); 341 } 342 rotation.interpolate( mPaths[id]->rotations[startNode], mPaths[id]->rotations[endNode], interp ); 343 PROFILE_END(); 344} 345 346U32 PathManager::getPathTotalTime(const U32 id) const 347{ 348 AssertFatal(isValidPath(id), "Error, this is not a valid path!"); 349 350 return mPaths[id]->totalTime; 351} 352 353U32 PathManager::getPathNumWaypoints(const U32 id) const 354{ 355 AssertFatal(isValidPath(id), "Error, this is not a valid path!"); 356 357 return mPaths[id]->positions.size(); 358} 359 360U32 PathManager::getWaypointTime(const U32 id, const U32 wayPoint) const 361{ 362 AssertFatal(isValidPath(id), "Error, this is not a valid path!"); 363 AssertFatal(wayPoint < getPathNumWaypoints(id), "Invalid waypoint!"); 364 365 U32 time = 0; 366 for (U32 i = 0; i < wayPoint; i++) 367 time += mPaths[id]->msToNext[i]; 368 369 return time; 370} 371 372U32 PathManager::getPathTimeBits(const U32 id) 373{ 374 AssertFatal(isValidPath(id), "Error, this is not a valid path!"); 375 376 return countNumBits(mPaths[id]->totalTime); 377} 378 379U32 PathManager::getPathWaypointBits(const U32 id) 380{ 381 AssertFatal(isValidPath(id), "Error, this is not a valid path!"); 382 383 return countNumBits(mPaths[id]->positions.size()); 384} 385 386 387bool PathManager::dumpState(BitStream* stream) const 388{ 389 stream->write(mPaths.size()); 390 391 for (U32 i = 0; i < mPaths.size(); i++) { 392 const PathEntry& rEntry = *mPaths[i]; 393 stream->write(rEntry.totalTime); 394 395 stream->write(rEntry.positions.size()); 396 for (U32 j = 0; j < rEntry.positions.size(); j++) { 397 mathWrite(*stream, rEntry.positions[j]); 398 stream->write(rEntry.msToNext[j]); 399 } 400 } 401 402 return stream->getStatus() == Stream::Ok; 403} 404 405bool PathManager::readState(BitStream* stream) 406{ 407 U32 i; 408 for (i = 0; i < mPaths.size(); i++) 409 delete mPaths[i]; 410 411 U32 numPaths; 412 stream->read(&numPaths); 413 mPaths.setSize(numPaths); 414 415 for (i = 0; i < mPaths.size(); i++) { 416 mPaths[i] = new PathEntry; 417 PathEntry& rEntry = *mPaths[i]; 418 419 stream->read(&rEntry.totalTime); 420 421 U32 numPositions; 422 stream->read(&numPositions); 423 rEntry.positions.setSize(numPositions); 424 rEntry.msToNext.setSize(numPositions); 425 for (U32 j = 0; j < rEntry.positions.size(); j++) { 426 mathRead(*stream, &rEntry.positions[j]); 427 stream->read(&rEntry.msToNext[j]); 428 } 429 } 430 431 return stream->getStatus() == Stream::Ok; 432} 433 434 435 436
