Planeshift
|
00001 /* 00002 * loader.h - Author: Mike Gist 00003 * 00004 * Copyright (C) 2009 Atomic Blue ([email protected], http://www.atomicblue.org) 00005 * 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU General Public License 00009 * as published by the Free Software Foundation (version 2 of the License) 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * 00018 */ 00019 00020 #ifndef __LOADER_H__ 00021 #define __LOADER_H__ 00022 00023 #include <csgeom/poly3d.h> 00024 #include <csgfx/shadervar.h> 00025 #include <csutil/scf_implementation.h> 00026 #include <csutil/hash.h> 00027 #include <csutil/threading/rwmutex.h> 00028 #include <csutil/threadmanager.h> 00029 #include <csutil/refcount.h> 00030 #include <csutil/typetraits.h> 00031 00032 #include <iengine/engine.h> 00033 #include <iengine/material.h> 00034 #include <iengine/mesh.h> 00035 #include <iengine/meshgen.h> 00036 #include <iengine/sector.h> 00037 #include <iengine/texture.h> 00038 #include <iengine/movable.h> 00039 #include <imesh/object.h> 00040 #include <imesh/objmodel.h> 00041 #include <imap/loader.h> 00042 #include <iutil/objreg.h> 00043 #include <iutil/vfs.h> 00044 00045 #include <ibgloader.h> 00046 #include <iscenemanipulate.h> 00047 00048 #ifdef CS_DEBUG 00049 #define LOADER_DEBUG_MESSAGE(...) csPrintf(__VA_ARGS__) 00050 #else 00051 #define LOADER_DEBUG_MESSAGE(...) 00052 #endif 00053 00054 //#ifdef CS_DEBUG 00055 #undef CS_ASSERT_MSG 00056 #define CS_ASSERT_MSG(msg, x) if(!(x)) printf("ART ERROR: %s\n", msg) 00057 //#endif 00058 00059 struct iCollideSystem; 00060 struct iEngineSequenceManager; 00061 struct iSyntaxService; 00062 00063 CS_PLUGIN_NAMESPACE_BEGIN(bgLoader) 00064 { 00065 00066 // string literals for usage as template parameter 00067 namespace ObjectNames 00068 { 00069 extern const char texture[8]; 00070 extern const char material[9]; 00071 extern const char trigger[8]; 00072 extern const char sequence[9]; 00073 extern const char meshobj[5]; 00074 extern const char meshfact[13]; 00075 extern const char meshgen[8]; 00076 extern const char light[6]; 00077 extern const char portal[7]; 00078 extern const char sector[7]; 00079 } 00080 00090 class BgLoader : public ThreadedCallable<BgLoader>, 00091 public scfImplementation3<BgLoader, 00092 iBgLoader, 00093 iSceneManipulate, 00094 iComponent> 00095 { 00096 private: 00097 // forward declaration 00098 class Loadable; 00099 struct iDelayedLoader; 00100 00101 public: 00102 BgLoader(iBase *p); 00103 virtual ~BgLoader(); 00104 00108 bool Initialize(iObjectRegistry* _object_reg); 00109 00113 csPtr<iThreadReturn> LoadMaterial(const char* name, bool wait = false); 00114 00118 csPtr<iThreadReturn> LoadFactory(const char* name, bool wait = false); 00119 00128 void CloneFactory(const char* name, const char* newName, bool* failed = NULL, const csReversibleTransform& trans = csReversibleTransform()); 00129 00136 THREADED_CALLABLE_DECL1(BgLoader, PrecacheData, csThreadReturn, const char*, path, THREADEDL, false, false); 00137 00142 void ClearTemporaryData() 00143 { 00144 parserData.xmltokens.Empty(); 00145 parserData.textures.Clear(); 00146 parserData.meshes.Clear(); 00147 parserData.svstrings.Invalidate(); 00148 parserData.syntaxService.Invalidate(); 00149 tman.Invalidate(); 00150 } 00151 00160 void UpdatePosition(const csVector3& pos, const char* sectorName, bool force); 00161 00172 void ContinueLoading(bool waiting); 00173 00177 iThreadedLoader* GetLoader() { return tloader; } 00178 00182 size_t GetLoadingCount() { return loadList.GetSize(); } 00183 00187 iObjectRegistry* GetObjectRegistry() const { return object_reg; } 00188 00192 void SetLoadRange(float r) { loadRange = r; if (lastSector.IsValid()) UpdatePosition(lastPos, lastSector->GetName(), true); } 00193 00198 bool HasValidPosition() const { return validPosition; } 00199 00206 bool InWaterArea(const char* sector, csVector3* pos, csColor4** colour); 00207 00211 bool LoadZones(iStringArray* regions, bool priority = false); 00212 00217 bool LoadPriorityZones(iStringArray* regions); 00218 00224 csPtr<iStringArray> GetShaderName(const char* usageType); 00225 00233 iMeshWrapper* CreateAndSelectMesh(const char* factName, const char* matName, 00234 iCamera* camera, const csVector2& pos); 00235 00241 iMeshWrapper* SelectMesh(iCamera* camera, const csVector2& pos); 00242 00250 bool TranslateSelected(bool vertical, iCamera* camera, const csVector2& pos); 00251 00256 void RotateSelected(const csVector2& pos); 00257 00264 void SetRotation(int flags_h, int flags_v); 00265 00269 void SetPosition(const csVector2& pos) { previousPosition = pos; }; 00270 00274 void RemoveSelected(); 00275 00276 void GetPosition(csVector3 & pos, csVector3 & rot, const csVector2& screenPos); 00277 00281 csRefArray<StartPosition> GetStartPositions() 00282 { 00283 csRefArray<StartPosition> array; 00284 CS::Threading::ScopedReadLock lock(parserData.positions.lock); 00285 LockedType<StartPosition>::HashType::GlobalIterator it(parserData.positions.hash.GetIterator()); 00286 while(it.HasNext()) 00287 { 00288 array.Push(it.Next()); 00289 } 00290 return array; 00291 } 00292 00293 // internal accessors 00294 iEngine* GetEngine() const 00295 { 00296 return engine; 00297 } 00298 00299 iVFS* GetVFS() 00300 { 00301 vfsLock.Lock(); 00302 return vfs; 00303 } 00304 00305 void ReleaseVFS() 00306 { 00307 vfsLock.Unlock(); 00308 } 00309 00310 iThreadedLoader* GetLoader() const 00311 { 00312 return tloader; 00313 } 00314 00315 iCollideSystem* GetCDSys() const 00316 { 00317 return cdsys; 00318 } 00319 00320 // increase load count - to be used by loadables only 00321 void RegisterPendingObject(Loadable* obj) 00322 { 00323 CS::Threading::RecursiveMutexScopedLock lock(loadLock); 00324 loadList.Push(obj); 00325 } 00326 00327 // decrease load count - to be used by loadables only 00328 void UnregisterPendingObject(Loadable* obj) 00329 { 00330 CS::Threading::RecursiveMutexScopedLock lock(loadLock); 00331 size_t index = loadList.Find(obj); 00332 00333 // make sure ContinuedLoading won't skip any elements 00334 if(index <= loadOffset) 00335 { 00336 --loadOffset; 00337 } 00338 loadList.DeleteIndex(index); 00339 } 00340 00341 // register delayed loader 00342 void RegisterDelayedLoader(iDelayedLoader* loader) 00343 { 00344 CS::Threading::RecursiveMutexScopedLock lock(loadLock); 00345 delayedLoadList.Push(loader); 00346 } 00347 00348 void UnregisterDelayedLoader(iDelayedLoader* loader) 00349 { 00350 CS::Threading::RecursiveMutexScopedLock lock(loadLock); 00351 size_t index = delayedLoadList.Find(loader); 00352 00353 // make sure ContinuedLoading won't skip any elements 00354 if(index <= delayedOffset) 00355 { 00356 --delayedOffset; 00357 } 00358 delayedLoadList.DeleteIndex(index); 00359 } 00360 00361 private: 00362 // The various gfx feature options we have. 00363 enum gfxFeatures 00364 { 00365 useLowestShaders = 0x1, 00366 useLowShaders = 0x2 | useLowestShaders, 00367 useMediumShaders = 0x4 | useLowShaders, 00368 useHighShaders = 0x8 | useMediumShaders, 00369 useHighestShaders = 0x10 | useHighShaders, 00370 useShadows = 0x20, 00371 useMeshGen = 0x40, 00372 useAll = (useHighestShaders | useShadows | useMeshGen) 00373 }; 00374 00375 /******************************************************** 00376 * Data structures representing components of the world. 00377 *******************************************************/ 00378 00379 // forward declarations 00380 class Sector; 00381 class Zone; 00382 class Texture; 00383 class MeshObj; 00384 class Sequence; 00385 class Light; 00386 struct ParserData; 00387 struct GlobalParserData; 00388 00389 // generic objects used for loading/parsing 00390 00391 // helper clases used with object classes that represent the world 00392 template<typename T> struct CheckedLoad 00393 { 00394 csRef<T> obj; 00395 bool checked; 00396 00397 CheckedLoad(const csRef<T>& obj) : obj(obj), checked(false) 00398 { 00399 } 00400 00401 CheckedLoad(const CheckedLoad& other) : obj(other.obj), checked(false) 00402 { 00403 } 00404 }; 00405 00409 template<typename T, bool check = true> struct LockedType 00410 { 00411 public: 00412 typedef csHash<csRef<T>, csStringID> HashType; 00413 HashType hash; 00414 csStringSet stringSet; 00415 CS::Threading::ReadWriteMutex lock; 00416 00417 csPtr<T> Get(const char* name) 00418 { 00419 csRef<T> object; 00420 CS::Threading::ScopedReadLock scopedLock(lock); 00421 if(stringSet.Contains(name)) 00422 { 00423 csStringID objectID = stringSet.Request(name); 00424 object = hash.Get(objectID, csRef<T>()); 00425 } 00426 return csPtr<T>(object); 00427 } 00428 00429 // workaround for completely braindead gcc 4.0.x (thanks apple!) 00430 void Put(const csRef<T>& obj) 00431 { 00432 Put(obj, 0); 00433 } 00434 00435 void Put(const csRef<T>& obj, const char* name) 00436 { 00437 CS::Threading::ScopedWriteLock scopedLock(lock); 00438 csStringID objectID; 00439 if(name) 00440 { 00441 objectID = stringSet.Request(name); 00442 } 00443 else 00444 { 00445 objectID = stringSet.Request(obj->GetName()); 00446 } 00447 00448 // check for duplicates 00449 if(check && hash.Contains(objectID)) 00450 { 00451 //LOADER_DEBUG_MESSAGE("detected name conflict for object '%s'\n", name ? name : obj->GetName()); 00452 } 00453 else 00454 { 00455 hash.Put(objectID, obj); 00456 } 00457 } 00458 00459 void Delete(const char* name) 00460 { 00461 CS::Threading::ScopedWriteLock scopedLock(lock); 00462 if(stringSet.Contains(name)) 00463 { 00464 csStringID id = stringSet.Request(name); 00465 hash.DeleteAll(id); 00466 stringSet.Delete(id); 00467 } 00468 } 00469 00470 void Clear() 00471 { 00472 stringSet.Empty(); 00473 hash.Empty(); 00474 } 00475 }; 00476 00477 class RangeBased 00478 { 00479 protected: 00480 csBox3 bbox; 00481 00482 public: 00483 inline bool InRange(const csBox3& curBBox) const 00484 { 00485 return curBBox.Overlap(bbox); 00486 } 00487 00488 inline bool OutOfRange(const csBox3& curBBox) const 00489 { 00490 return !curBBox.Overlap(bbox); 00491 } 00492 }; 00493 00494 // Loaded unconditionally - not range based. 00495 class AlwaysLoaded 00496 { 00497 public: 00498 inline bool InRange(const csBox3& /*curBBox*/) const 00499 { 00500 return true; 00501 } 00502 00503 inline bool OutOfRange(const csBox3& /*curBBox*/) const 00504 { 00505 return false; 00506 } 00507 }; 00508 00512 class Loadable : public csObject 00513 { 00514 public: 00515 Loadable(BgLoader* parent) : parent(parent), 00516 loading(false), useCount(0) 00517 { 00518 } 00519 00520 Loadable(const Loadable& other) : csObject(0), parent(other.parent), 00521 loading(false), useCount(0) 00522 { 00523 SetName(other.GetName()); 00524 } 00525 00526 virtual ~Loadable() 00527 { 00528 } 00529 00530 /* 00531 * Return true if underlying CS object was loaded. 00532 */ 00533 bool Load(bool wait = false) 00534 { 00535 CS::Threading::RecursiveMutexScopedLock lock(busy); 00536 checked = true; 00537 if(useCount == 0) 00538 { 00539 lingerCount = 0; 00540 00541 if(!loading) 00542 { 00543 loading = true; 00544 GetParent()->RegisterPendingObject(this); 00545 } 00546 00547 if(LoadObject(wait)) 00548 { 00549 loading = false; 00550 ++useCount; 00551 GetParent()->UnregisterPendingObject(this); 00552 00553 FinishObject(); 00554 } 00555 00556 return !loading; 00557 } 00558 else 00559 { 00560 ++useCount; 00561 return true; 00562 } 00563 } 00564 00565 void AbortLoad() 00566 { 00567 CS::Threading::RecursiveMutexScopedLock lock(busy); 00568 if(loading) 00569 { 00570 loading = false; 00571 checked = false; 00572 00573 // do a blocked load and then unload for now 00574 // to prevent some race conditions with CS' internal loader 00575 Load(true); 00576 Unload(); 00577 00578 //UnloadObject(); 00579 GetParent()->UnregisterPendingObject(this); 00580 } 00581 } 00582 00583 void Unload() 00584 { 00585 CS::Threading::RecursiveMutexScopedLock lock(busy); 00586 if(useCount == 0) 00587 { 00588 LOADER_DEBUG_MESSAGE("tried to free not loaded object '%s'\n", GetName()); 00589 return; 00590 } 00591 00592 CS_ASSERT_MSG("unloading currently loading object!", !loading); 00593 00594 --useCount; 00595 if(useCount == 0) 00596 { 00597 UnloadObject(); 00598 } 00599 } 00600 00601 virtual bool LoadObject(bool wait) = 0; 00602 virtual void UnloadObject() = 0; 00603 virtual void FinishObject() {} 00604 00605 bool IsLoaded() const 00606 { 00607 CS::Threading::RecursiveMutexScopedLock lock(busy); 00608 return useCount > 0; 00609 } 00610 00611 inline BgLoader* GetParent() const 00612 { 00613 return parent; 00614 } 00615 00616 void ResetChecked() 00617 { 00618 CS::Threading::RecursiveMutexScopedLock lock(busy); 00619 checked = false; 00620 } 00621 00622 bool IsChecked() const 00623 { 00624 CS::Threading::RecursiveMutexScopedLock lock(busy); 00625 return checked; 00626 } 00627 00628 size_t GetLingerCount() const 00629 { 00630 CS::Threading::RecursiveMutexScopedLock lock(busy); 00631 return lingerCount; 00632 } 00633 00634 void IncLingerCount() 00635 { 00636 CS::Threading::RecursiveMutexScopedLock lock(busy); 00637 ++lingerCount; 00638 } 00639 00640 protected: 00641 void MarkChecked() 00642 { 00643 CS::Threading::RecursiveMutexScopedLock lock(busy); 00644 checked = true; 00645 } 00646 00647 template<typename T, const char* TypeName> void CheckRemove(csRef<T>& ref) 00648 { 00649 if(ref.IsValid()) 00650 { 00651 csWeakRef<T> check(ref); 00652 parent->GetEngine()->RemoveObject(ref); 00653 ref.Invalidate(); 00654 if(check.IsValid()) 00655 { 00656 LOADER_DEBUG_MESSAGE("detected leaking %s: %u %s\n", TypeName, check->GetRefCount(), GetName()); 00657 } 00658 } 00659 } 00660 00661 private: 00662 mutable CS::Threading::RecursiveMutex busy; 00663 00664 BgLoader* parent; 00665 bool loading; 00666 bool checked; 00667 size_t lingerCount; 00668 size_t useCount; 00669 }; 00670 00671 struct iDelayedLoader : public iThreadReturn 00672 { 00673 virtual void ContinueLoading(bool wait) = 0; 00674 }; 00675 00676 template<typename T> class DelayedLoader : public scfImplementation1<DelayedLoader<T>, iDelayedLoader> 00677 { 00678 public: 00679 DelayedLoader(T* target) : scfImplementation1<DelayedLoader<T>, iDelayedLoader>(this), 00680 target(target), finished(false), 00681 waitLock(0), waitCondition(0) 00682 { 00683 if(target) 00684 { 00685 // valid target, register us with the parent 00686 BgLoader* parent = target->GetParent(); 00687 parent->RegisterDelayedLoader(this); 00688 } 00689 else 00690 { 00691 finished = true; 00692 } 00693 } 00694 00695 virtual ~DelayedLoader() 00696 { 00697 if(!target.IsValid()) 00698 { 00699 return; 00700 } 00701 00702 // free result 00703 result.Invalidate(); 00704 00705 if(finished) 00706 { 00707 // unload the object 00708 target->Unload(); 00709 } 00710 else 00711 { 00712 // unregister us with the parent 00713 BgLoader* parent = target->GetParent(); 00714 parent->UnregisterDelayedLoader(this); 00715 00716 // don't abort load here - we're still on the load 00717 // list so we'll be detected as lingering if applicaple 00718 // and removed accordingly 00719 } 00720 } 00721 00722 void ContinueLoading(bool wait) 00723 { 00724 CS::Threading::MutexScopedLock lock(busy); 00725 if(target.IsValid() && !finished && target->Load(wait)) 00726 { 00727 // done loading 00728 00729 // unregister us with the parent 00730 BgLoader* parent = target->GetParent(); 00731 parent->UnregisterDelayedLoader(this); 00732 00733 if(waitLock) waitLock->Lock(); 00734 00735 // mark finished and set result accordingly; 00736 finished = true; 00737 csRef<typename T::ObjectType> ref = target->GetObject(); 00738 result = ref; 00739 00740 // notify tm if it's waiting for us 00741 if(waitCondition) 00742 { 00743 waitCondition->NotifyAll(); 00744 } 00745 00746 if(waitLock) waitLock->Unlock(); 00747 } 00748 } 00749 00750 void Wait(bool /*process*/) 00751 { 00752 ContinueLoading(true); 00753 } 00754 00755 void* GetResultPtr() 00756 { 00757 CS::Threading::MutexScopedLock lock(busy); 00758 return result; 00759 } 00760 00761 csRef<iBase> GetResultRefPtr() 00762 { 00763 CS::Threading::MutexScopedLock lock(busy); 00764 return result; 00765 } 00766 00767 bool IsFinished() 00768 { 00769 CS::Threading::MutexScopedLock lock(busy); 00770 return finished; 00771 } 00772 00773 bool WasSuccessful() 00774 { 00775 CS::Threading::MutexScopedLock lock(busy); 00776 return result.IsValid(); 00777 } 00778 00779 void SetWaitPtrs(CS::Threading::Condition* c, CS::Threading::Mutex* m) 00780 { 00781 CS::Threading::MutexScopedLock lock(busy); 00782 waitCondition = c; 00783 waitLock = m; 00784 } 00785 00786 // doesn't have to be threadsafe 00787 void SetJob(iJob* newJob) 00788 { 00789 job = newJob; 00790 } 00791 00792 // doesn't have to be threadsafe 00793 iJob* GetJob() const 00794 { 00795 return job; 00796 } 00797 00798 private: 00799 // disable functions iThreadReturn requires but we don't want to implement 00800 void MarkSuccessful() {} 00801 void MarkFinished() {} 00802 void SetResult(csRef<iBase> /*result*/) {} 00803 void SetResult(void* /*result*/) {} 00804 void Copy(iThreadReturn* /*other*/) {} 00805 00806 // private data 00807 CS::Threading::Mutex busy; 00808 csRef<T> target; 00809 csRef<iBase> result; 00810 bool finished; 00811 00812 // thread return specific data 00813 CS::Threading::Mutex* waitLock; 00814 CS::Threading::Condition* waitCondition; 00815 csRef<iJob> job; 00816 }; 00817 00818 // trivial loadable (e.g. triggers, textures, ...) 00819 template<typename T, const char* TypeName> class TrivialLoadable : public Loadable 00820 { 00821 public: 00822 typedef T ObjectType; 00823 00824 TrivialLoadable(BgLoader* parent) : Loadable(parent) 00825 { 00826 } 00827 00828 TrivialLoadable(const TrivialLoadable& other) 00829 : Loadable(other.GetParent()), path(other.path), 00830 data(other.data) 00831 { 00832 } 00833 00834 bool LoadObject(bool wait) 00835 { 00836 if(!status.IsValid()) 00837 { 00838 if(!data.IsValid()) 00839 { 00840 LOADER_DEBUG_MESSAGE("%s %s was created, but never parsed!\n", TypeName, GetName()); 00841 return true; 00842 } 00843 status = GetParent()->GetLoader()->LoadNode(path, data); 00844 } 00845 00846 if(wait) 00847 { 00848 status->Wait(); 00849 } 00850 00851 if(status->IsFinished()) 00852 { 00853 if(!status->WasSuccessful()) 00854 { 00855 LOADER_DEBUG_MESSAGE("%s %s failed to load\n", TypeName, GetName()); 00856 } 00857 return true; 00858 } 00859 else 00860 { 00861 return false; 00862 } 00863 } 00864 00865 void UnloadObject() 00866 { 00867 csRef<T> ref = GetObject(); 00868 status.Invalidate(); 00869 Loadable::CheckRemove<T,TypeName>(ref); 00870 } 00871 00872 csPtr<T> GetObject() 00873 { 00874 if(status.IsValid() && status->IsFinished() && status->WasSuccessful()) 00875 { 00876 csRef<iBase> rawObj = status->GetResultRefPtr(); 00877 if(rawObj.IsValid()) 00878 { 00879 return scfQueryInterface<T>(rawObj); 00880 } 00881 } 00882 00883 return csPtr<T>(0); 00884 } 00885 00886 protected: 00887 // parse results 00888 csString path; 00889 csRef<iDocumentNode> data; 00890 00891 // load data 00892 csRef<iThreadReturn> status; 00893 }; 00894 00895 // helper class that allows a specific dependency type for an object 00896 template<typename T> class ObjectLoader 00897 { 00898 public: 00899 typedef CheckedLoad<T> HashObjectType; 00900 typedef csHash<HashObjectType, csString> HashType; 00901 00902 ObjectLoader() : objectCount(0) 00903 { 00904 } 00905 00906 ObjectLoader(const ObjectLoader& other) : objectCount(0) 00907 { 00908 CS::Threading::RecursiveMutexScopedLock lock(other.busy); 00909 typename HashType::ConstGlobalIterator it(other.objects.GetIterator()); 00910 while(it.HasNext()) 00911 { 00912 csString key; 00913 HashObjectType obj(it.Next(key)); 00914 objects.Put(key, obj); 00915 } 00916 } 00917 00918 ~ObjectLoader() 00919 { 00920 UnloadObjects(); 00921 } 00922 00923 size_t GetObjectCount() const 00924 { 00925 CS::Threading::RecursiveMutexScopedLock lock(busy); 00926 return objectCount; 00927 } 00928 00929 // workaround for bug in gcc 4.0: fails to parse default function arguments in template classes 00930 bool LoadObjects() 00931 { 00932 return LoadObjects(false); 00933 } 00934 00935 // load all dependencies of this type 00936 // return true if all are ready 00937 bool LoadObjects(bool wait) 00938 { 00939 CS::Threading::RecursiveMutexScopedLock lock(busy); 00940 if(objectCount == objects.GetSize()) 00941 { 00942 // nothing to be done 00943 return true; 00944 } 00945 00946 bool ready = true; 00947 typename HashType::GlobalIterator it(objects.GetIterator()); 00948 while(it.HasNext()) 00949 { 00950 HashObjectType& ref = it.Next(); 00951 if(!ref.checked) 00952 { 00953 ref.checked = ref.obj->Load(wait); 00954 if(ref.checked) 00955 { 00956 ++objectCount; 00957 } 00958 else 00959 { 00960 ready = false; 00961 } 00962 } 00963 } 00964 return ready; 00965 } 00966 00967 // unloads all dependencies of this type 00968 void UnloadObjects() 00969 { 00970 CS::Threading::RecursiveMutexScopedLock lock(busy); 00971 if(!objectCount) 00972 { 00973 // nothing to be done 00974 return; 00975 } 00976 00977 typename HashType::GlobalIterator it(objects.GetIterator()); 00978 while(it.HasNext()) 00979 { 00980 HashObjectType& ref = it.Next(); 00981 if(ref.checked) 00982 { 00983 ref.obj->Unload(); 00984 ref.checked = false; 00985 --objectCount; 00986 } 00987 } 00988 } 00989 00990 int UpdateObjects(const csBox3& loadBox, const csBox3& keepBox) 00991 { 00992 CS::Threading::RecursiveMutexScopedLock lock(busy); 00993 int oldObjectCount = objectCount; 00994 if(CS::Meta::IsBaseOf<RangeBased,T>::value) 00995 { 00996 typename HashType::GlobalIterator it(objects.GetIterator()); 00997 while(it.HasNext()) 00998 { 00999 HashObjectType& ref = it.Next(); 01000 if(ref.checked) 01001 { 01002 if(ref.obj->OutOfRange(keepBox)) 01003 { 01004 ref.obj->Unload(); 01005 ref.checked = false; 01006 --objectCount; 01007 } 01008 } 01009 else if(ref.obj->InRange(loadBox)) 01010 { 01011 ref.checked = ref.obj->Load(false); 01012 if(ref.checked) 01013 { 01014 ++objectCount; 01015 } 01016 } 01017 } 01018 } 01019 else 01020 { 01021 LoadObjects(false); 01022 } 01023 return (int)objectCount - oldObjectCount; 01024 } 01025 01026 void AddDependency(T* obj) 01027 { 01028 CS::Threading::RecursiveMutexScopedLock lock(busy); 01029 if(!objects.Contains(obj->GetName())) 01030 { 01031 objects.Put(obj->GetName(), csRef<T>(obj)); 01032 } 01033 } 01034 01035 void RemoveDependency(const T* obj) 01036 { 01037 CS::Threading::RecursiveMutexScopedLock lock(busy); 01038 const HashObjectType& ref = objects.Get(obj->GetName(), HashObjectType(csRef<T>())); 01039 if(ref.checked) 01040 { 01041 ref.obj->Unload(); 01042 --objectCount; 01043 } 01044 objects.DeleteAll(obj->GetName()); 01045 } 01046 01047 // workaround for bug in gcc 4.0: fails to parse default function argument in template classes 01048 const csRef<T>& GetDependency(const char* name) const 01049 { 01050 return GetDependency(name, csRef<T>()); 01051 } 01052 01053 const csRef<T>& GetDependency(const char* name, const csRef<T>& fallbackobj) const 01054 { 01055 CS::Threading::RecursiveMutexScopedLock lock(busy); 01056 const HashObjectType& ref = objects.Get(name,fallbackobj); 01057 return ref.obj; 01058 } 01059 01060 bool HasDependency(const char* name) const 01061 { 01062 CS::Threading::RecursiveMutexScopedLock lock(busy); 01063 return objects.Contains(name); 01064 } 01065 01066 HashType& GetDependencies() 01067 { 01068 return objects; 01069 } 01070 01071 const HashType& GetDependencies() const 01072 { 01073 return objects; 01074 } 01075 01076 protected: 01077 mutable CS::Threading::RecursiveMutex busy; 01078 01079 HashType objects; 01080 size_t objectCount; 01081 }; 01082 01083 // actual world objects 01084 01085 struct WaterArea 01086 { 01087 csBox3 bbox; 01088 csColor4 colour; 01089 }; 01090 01091 class ShaderVar : public CS::Utility::AtomicRefCount 01092 { 01093 public: 01094 ShaderVar(BgLoader* parent, ObjectLoader<Texture>* object) : parent(parent), object(object) 01095 { 01096 } 01097 01098 ~ShaderVar() 01099 { 01100 } 01101 01102 template<bool check> bool Parse(iDocumentNode* node, GlobalParserData& data); 01103 void LoadObject(csShaderVariable* var); 01104 CS::ShaderVarStringID GetID() const 01105 { 01106 return nameID; 01107 } 01108 01109 private: 01110 CS::ShaderVarStringID nameID; 01111 csShaderVariable::VariableType type; 01112 csString value; 01113 float vec1; 01114 csVector2 vec2; 01115 csVector3 vec3; 01116 csVector4 vec4; 01117 01118 BgLoader* parent; 01119 ObjectLoader<Texture>* object; 01120 }; 01121 01122 class Texture : public TrivialLoadable<iTextureWrapper,ObjectNames::texture> 01123 { 01124 public: 01125 Texture(BgLoader* parent) : TrivialLoadable<iTextureWrapper,ObjectNames::texture>(parent) 01126 { 01127 } 01128 01129 bool Parse(iDocumentNode* node, ParserData& data); 01130 }; 01131 01132 class Material : public Loadable, public ObjectLoader<Texture> 01133 { 01134 public: 01135 typedef iMaterialWrapper ObjectType; 01136 01137 using ObjectLoader<Texture>::AddDependency; 01138 01139 Material(BgLoader* parent) : Loadable(parent) 01140 { 01141 } 01142 01143 bool Parse(iDocumentNode* node, GlobalParserData& data); 01144 01145 bool LoadObject(bool wait); 01146 void UnloadObject(); 01147 csPtr<iMaterialWrapper> GetObject() 01148 { 01149 csRef<iMaterialWrapper> wrapper(materialWrapper); 01150 return csPtr<iMaterialWrapper>(wrapper); 01151 } 01152 01153 private: 01154 // dependencies 01155 struct Shader 01156 { 01157 csRef<iShader> shader; 01158 csStringID type; 01159 }; 01160 csArray<Shader> shaders; 01161 csRefArray<ShaderVar> shadervars; 01162 01163 // load data 01164 csRef<iMaterialWrapper> materialWrapper; 01165 }; 01166 01167 class MaterialLoader : public ObjectLoader<Material> 01168 { 01169 public: 01170 void ParseMaterialReference(GlobalParserData& data, const char* name, const char* parentName, const char* type); 01171 }; 01172 01173 class Trigger : public ObjectLoader<Sequence>, 01174 public ObjectLoader<MeshObj>, 01175 public ObjectLoader<Light>, 01176 public TrivialLoadable<iSequenceTrigger,ObjectNames::trigger>, 01177 public AlwaysLoaded 01178 { 01179 public: 01180 using ObjectLoader<Sequence>::AddDependency; 01181 using ObjectLoader<MeshObj>::AddDependency; 01182 using ObjectLoader<Light>::AddDependency; 01183 01184 Trigger(BgLoader* parent) : TrivialLoadable<iSequenceTrigger,ObjectNames::trigger>(parent) 01185 { 01186 } 01187 01188 bool LoadObject(bool wait) 01189 { 01190 bool ready = ObjectLoader<Sequence>::LoadObjects(true); 01191 ready &= ObjectLoader<MeshObj>::LoadObjects(true); 01192 ready &= ObjectLoader<Light>::LoadObjects(true); 01193 ready &= TrivialLoadable<iSequenceTrigger,ObjectNames::trigger>::LoadObject(true); 01194 return ready; 01195 //return TrivialLoadable<iSequenceTrigger,ObjectNames::trigger>::LoadObject(true); 01196 } 01197 01198 void UnloadObject() 01199 { 01200 TrivialLoadable<iSequenceTrigger,ObjectNames::trigger>::UnloadObject(); 01201 ObjectLoader<Sequence>::UnloadObjects(); 01202 ObjectLoader<MeshObj>::UnloadObjects(); 01203 ObjectLoader<Light>::UnloadObjects(); 01204 } 01205 01206 bool Parse(iDocumentNode* node, ParserData& data); 01207 }; 01208 01209 class Sequence : public ObjectLoader<Sequence>, 01210 public ObjectLoader<Trigger>, 01211 public ObjectLoader<Light>, 01212 public ObjectLoader<MeshObj>, 01213 public MaterialLoader, 01214 public TrivialLoadable<iSequenceWrapper,ObjectNames::sequence>, 01215 public AlwaysLoaded 01216 { 01217 public: 01218 using ObjectLoader<Sequence>::AddDependency; 01219 using ObjectLoader<Trigger>::AddDependency; 01220 using ObjectLoader<Light>::AddDependency; 01221 using ObjectLoader<MeshObj>::AddDependency; 01222 01223 Sequence(BgLoader* parent) : TrivialLoadable<iSequenceWrapper,ObjectNames::sequence>(parent) 01224 { 01225 } 01226 01227 bool Parse(iDocumentNode* node, ParserData& data); 01228 01229 bool LoadObject(bool wait) 01230 { 01231 // work around a race condition with engseqmgr 01232 wait = true; 01233 01234 bool ready = true; 01235 if(ready) 01236 { 01237 ready = ObjectLoader<MeshObj>::LoadObjects(wait); 01238 } 01239 01240 if(ready) 01241 { 01242 ready = ObjectLoader<Sequence>::LoadObjects(wait); 01243 } 01244 01245 if(ready) 01246 { 01247 ready = TrivialLoadable<iSequenceWrapper,ObjectNames::sequence>::LoadObject(wait); 01248 } 01249 01250 if(ready) 01251 { 01252 ready = ObjectLoader<Trigger>::LoadObjects(wait); 01253 } 01254 return ready; 01255 } 01256 01257 void UnloadObject() 01258 { 01259 TrivialLoadable<iSequenceWrapper,ObjectNames::sequence>::UnloadObject(); 01260 ObjectLoader<Sequence>::UnloadObjects(); 01261 ObjectLoader<Trigger>::UnloadObjects(); 01262 ObjectLoader<MeshObj>::UnloadObjects(); 01263 } 01264 }; 01265 01266 class Light : public Loadable, public RangeBased 01267 { 01268 public: 01269 typedef iLight ObjectType; 01270 01271 Light(BgLoader* parent) : Loadable(parent) 01272 { 01273 } 01274 01275 bool Parse(iDocumentNode* node, ParserData& data); 01276 01277 bool LoadObject(bool wait); 01278 void UnloadObject(); 01279 01280 csPtr<iLight> GetObject() 01281 { 01282 return csPtr<iLight>(light); 01283 } 01284 01285 private: 01286 // parse results 01287 csVector3 pos; 01288 float radius; 01289 csColor colour; 01290 csLightDynamicType dynamic; 01291 csLightAttenuationMode attenuation; 01292 csLightType type; 01293 01294 // dependencies 01295 Sector* sector; 01296 01297 // load data 01298 csRef<iLight> light; 01299 }; 01300 01301 class MeshFact : public TrivialLoadable<iMeshFactoryWrapper,ObjectNames::meshfact>, 01302 public MaterialLoader 01303 { 01304 public: 01305 using ObjectLoader<Material>::AddDependency; 01306 01307 MeshFact(BgLoader* parent) : TrivialLoadable<iMeshFactoryWrapper,ObjectNames::meshfact>(parent), 01308 cloned(false) 01309 { 01310 } 01311 01312 bool Parse(iDocumentNode* node, ParserData& data); 01313 bool ParseCells(iDocumentNode* node, ParserData& data); 01314 01315 csPtr<MeshFact> Clone(const char* name) 01316 { 01317 csRef<MeshFact> clone; 01318 clone.AttachNew(new MeshFact(GetParent())); 01319 clone->SetName(name); 01320 01321 clone->cloned = true; 01322 clone->parentFactory = &*this; 01323 return csPtr<MeshFact>(clone); 01324 } 01325 01326 bool operator==(const MeshFact& other) 01327 { 01328 if(cloned != other.cloned) 01329 { 01330 if(parentFactory.IsValid()) 01331 { 01332 if(*parentFactory != other) 01333 { 01334 return false; 01335 } 01336 } 01337 else 01338 { 01339 if(*this != *other.parentFactory) 01340 { 01341 return false; 01342 } 01343 } 01344 } 01345 else if(cloned) 01346 { 01347 if(parentFactory != other.parentFactory) 01348 return false; 01349 } 01350 else 01351 { 01352 if(filename != other.filename) 01353 return false; 01354 if((iDocumentNode*)data != (iDocumentNode*)other.data) 01355 return false; 01356 } 01357 01358 // ignore transformations for this check 01359 01360 return true; 01361 } 01362 01363 bool operator!=(const MeshFact& other) 01364 { 01365 return !(*this == other); 01366 } 01367 01368 csPtr<iMeshFactoryWrapper> GetObject() 01369 { 01370 csRef<iMeshFactoryWrapper> object; 01371 if(cloned) 01372 { 01373 if(factory.IsValid()) 01374 { 01375 object = factory; 01376 } 01377 else if(parentFactory.IsValid()) 01378 { 01379 object = parentFactory->GetObject(); 01380 } 01381 } 01382 else 01383 { 01384 object = TrivialLoadable<iMeshFactoryWrapper,ObjectNames::meshfact>::GetObject(); 01385 } 01386 return csPtr<iMeshFactoryWrapper>(object); 01387 } 01388 01389 void SetTransform(const csReversibleTransform& transform) 01390 { 01391 trans = transform; 01392 } 01393 01394 bool LoadObject(bool wait); 01395 void UnloadObject(); 01396 void FinishObject(); 01397 01398 bool FindSubmesh(const csString& name) const 01399 { 01400 return submeshes.Find(name) != csArrayItemNotFound; 01401 } 01402 01403 const csArray<csVector3>& GetVertices() const 01404 { 01405 return bboxvs; 01406 } 01407 01408 private: 01409 // cloning data 01410 bool cloned; 01411 csRef<MeshFact> parentFactory; 01412 csRef<iMeshFactoryWrapper> factory; 01413 01414 // transformation data 01415 csReversibleTransform trans; 01416 01417 // parser results 01418 csString filename; 01419 csArray<csVector3> bboxvs; 01420 csStringArray submeshes; 01421 }; 01422 01423 class MeshObj : public TrivialLoadable<iMeshWrapper,ObjectNames::meshobj>, 01424 public RangeBased, public ObjectLoader<Texture>, 01425 public MaterialLoader, public ObjectLoader<MeshFact> 01426 { 01427 public: 01428 using ObjectLoader<Texture>::AddDependency; 01429 using ObjectLoader<Material>::AddDependency; 01430 using ObjectLoader<MeshFact>::AddDependency; 01431 01432 MeshObj(BgLoader* parent) : TrivialLoadable<iMeshWrapper,ObjectNames::meshobj>(parent) 01433 { 01434 } 01435 01436 bool Parse(iDocumentNode* node, ParserData& data, bool& alwaysLoaded); 01437 bool ParseTriMesh(iDocumentNode* node, ParserData& data, bool& alwaysLoaded); 01438 01439 bool LoadObject(bool wait); 01440 void UnloadObject(); 01441 void FinishObject(); 01442 01443 bool FindSubmesh(const csString& name) const 01444 { 01445 typedef ObjectLoader<MeshFact>::HashType HashType; 01446 const HashType& factories = ObjectLoader<MeshFact>::GetDependencies(); 01447 HashType::ConstGlobalIterator it(factories.GetIterator()); 01448 bool found = false; 01449 while(it.HasNext() && !found) 01450 { 01451 const csRef<MeshFact>& factory = it.Next().obj; 01452 found |= factory->FindSubmesh(name); 01453 } 01454 return found; 01455 } 01456 01457 private: 01458 // parse results 01459 bool dynamicLighting; 01460 01461 // dependencies 01462 Sector* sector; 01463 csRefArray<ShaderVar> shadervars; 01464 }; 01465 01466 class MeshGen : public TrivialLoadable<iMeshGenerator,ObjectNames::meshgen>, public RangeBased, public MaterialLoader, 01467 public ObjectLoader<MeshFact> 01468 { 01469 public: 01470 using ObjectLoader<MeshFact>::AddDependency; 01471 using ObjectLoader<Material>::AddDependency; 01472 01473 MeshGen(BgLoader* parent) : TrivialLoadable<iMeshGenerator,ObjectNames::meshgen>(parent), 01474 sector(0) 01475 { 01476 } 01477 01478 bool Parse(iDocumentNode* node, ParserData& data); 01479 01480 bool LoadObject(bool wait); 01481 void UnloadObject(); 01482 01483 private: 01484 // parser data 01485 Sector* sector; 01486 01487 // dependencies 01488 csRef<MeshObj> mesh; 01489 }; 01490 01491 class Portal : public Loadable, public RangeBased 01492 { 01493 friend class Sector; 01494 public: 01495 typedef iMeshWrapper ObjectType; 01496 01497 Portal(BgLoader* parent, float renderDist) : Loadable(parent), flags(0), renderDist(renderDist), 01498 warp(false), ww_given(false), wv(0.f), ww(0.f), 01499 autoresolve(0), targetSector(0), sector(0) 01500 { 01501 } 01502 01503 bool Parse(iDocumentNode* node, ParserData& data); 01504 01505 bool LoadObject(bool wait); 01506 void UnloadObject(); 01507 01508 csPtr<iMeshWrapper> GetObject() 01509 { 01510 csRef<iMeshWrapper> obj(mObject); 01511 return csPtr<iMeshWrapper>(obj); 01512 } 01513 01514 private: 01515 // parser results 01516 uint32 flags; 01517 float renderDist; 01518 01519 // transformation data 01520 bool warp; 01521 bool ww_given; 01522 csMatrix3 matrix; 01523 csVector3 wv; 01524 csVector3 ww; 01525 csReversibleTransform transform; 01526 01527 // sector data 01528 bool autoresolve; 01529 Sector* targetSector; 01530 Sector* sector; 01531 01532 // vertex data 01533 csPoly3D poly; 01534 01535 // load data 01536 iPortal* pObject; 01537 csRef<iMeshWrapper> mObject; 01538 01539 // sector callback 01540 class MissingSectorCallback : public scfImplementation1<MissingSectorCallback, iPortalCallback> 01541 { 01542 private: 01543 csRef<Sector> targetSector; 01544 bool autoresolve; 01545 01546 public: 01547 MissingSectorCallback(Sector* target, bool resolve) : scfImplementationType(this),targetSector(target),autoresolve(resolve) 01548 { 01549 } 01550 01551 virtual ~MissingSectorCallback() 01552 { 01553 } 01554 01555 virtual bool Traverse(iPortal* p, iBase* /*context*/) 01556 { 01557 csRef<iSector> target = targetSector->GetObject(); 01558 if(target.IsValid()) 01559 { 01560 p->SetSector(target); 01561 } 01562 else 01563 { 01564 return false; 01565 } 01566 01567 if(!autoresolve) 01568 { 01569 p->RemoveMissingSectorCallback(this); 01570 } 01571 01572 return true; 01573 } 01574 }; 01575 }; 01576 01577 class Sector : public Loadable, 01578 public ObjectLoader<MeshGen>, public ObjectLoader<MeshObj>, 01579 public ObjectLoader<Portal>, public ObjectLoader<Light>, 01580 public ObjectLoader<Sequence>, public ObjectLoader<Trigger> 01581 { 01582 public: 01583 using ObjectLoader<MeshGen>::AddDependency; 01584 using ObjectLoader<MeshObj>::AddDependency; 01585 using ObjectLoader<Portal>::AddDependency; 01586 using ObjectLoader<Light>::AddDependency; 01587 using ObjectLoader<Sequence>::AddDependency; 01588 using ObjectLoader<Trigger>::AddDependency; 01589 01590 Sector(BgLoader* parent) : Loadable(parent), ambient(0.0f), objectCount(0), 01591 init(false), isLoading(false) 01592 { 01593 } 01594 01595 ~Sector() 01596 { 01597 } 01598 01599 bool Parse(iDocumentNode* node, ParserData& data); 01600 01601 bool LoadObject(bool wait); 01602 void UnloadObject(); 01603 int UpdateObjects(const csBox3& loadBox, const csBox3& keepBox, size_t recursions); 01604 01605 bool Initialize(); 01606 void ForceUpdateObjectCount(); 01607 void FindConnectedSectors(csSet<csPtrKey<Sector> >& connectedSectors); 01608 01609 void AddPortal(Portal* p) 01610 { 01611 CS::Threading::RecursiveMutexScopedLock lock(busy); 01612 activePortals.Add(p); 01613 } 01614 01615 void RemovePortal(Portal* p) 01616 { 01617 CS::Threading::RecursiveMutexScopedLock lock(busy); 01618 activePortals.Delete(p); 01619 } 01620 01621 void AddAlwaysLoaded(MeshObj* mesh) 01622 { 01623 alwaysLoaded.AddDependency(mesh); 01624 } 01625 01626 csPtr<iSector> GetObject() 01627 { 01628 csRef<iSector> obj(object); 01629 return csPtr<iSector>(obj); 01630 } 01631 01632 private: 01633 // parser results 01634 csString culler; 01635 csColor ambient; 01636 size_t objectCount; 01637 Zone* parent; 01638 01639 // dependencies 01640 csArray<WaterArea> waterareas; 01641 ObjectLoader<MeshObj> alwaysLoaded; 01642 01643 // load data 01644 CS::Threading::RecursiveMutex busy; 01645 csRef<iSector> object; 01646 csSet<csPtrKey<Portal> > activePortals; 01647 bool init; 01648 bool isLoading; 01649 }; 01650 01651 // Stores world representation. 01652 class Zone : public Loadable, public ObjectLoader<Sector> 01653 { 01654 public: 01655 using ObjectLoader<Sector>::AddDependency; 01656 01657 Zone(BgLoader* parent, const char* name) 01658 : Loadable(parent), priority(false) 01659 { 01660 Loadable::SetName(name); 01661 } 01662 01663 bool LoadObject(bool wait) 01664 { 01665 return ObjectLoader<Sector>::LoadObjects(wait); 01666 } 01667 01668 void UnloadObject() 01669 { 01670 ObjectLoader<Sector>::UnloadObjects(); 01671 } 01672 01673 void UpdatePriority(bool newPriority) 01674 { 01675 if(priority != newPriority) 01676 { 01677 priority = newPriority; 01678 01679 // upgrade sector priorities 01680 /*ObjectLoader<Sector>::HashType::GlobalIterator it(ObjectLoader<Sector>::objects.GetIterator()); 01681 while(it.HasNext()) 01682 { 01683 it.Next().obj->priority = newPriority; 01684 }*/ 01685 } 01686 } 01687 01688 bool GetPriority() const 01689 { 01690 return priority; 01691 } 01692 01693 private: 01694 // loader data 01695 bool priority; 01696 }; 01697 01698 struct GlobalParserData 01699 { 01700 // token lookup table 01701 csStringHash xmltokens; 01702 01703 // temporary parse-time data 01704 LockedType<Texture> textures; 01705 LockedType<MeshObj> meshes; 01706 csRef<iShaderVarStringSet> svstrings; 01707 01708 // plugin references 01709 csRef<iSyntaxService> syntaxService; 01710 iObjectRegistry* object_reg; 01711 01712 // persistent data 01713 csRef<iStringSet> strings; 01714 LockedType<Material> materials; 01715 LockedType<Sector> sectors; 01716 LockedType<MeshFact> factories; 01717 LockedType<Zone> zones; 01718 LockedType<StartPosition,false> positions; 01719 CS::Threading::ReadWriteMutex shaderLock; 01720 csHash<csString, csStringID> shadersByUsage; 01721 csStringArray shaders; 01722 csHash<csString, csString> shaderAliases; 01723 01724 // config 01725 struct ParserConfig 01726 { 01727 bool cache; 01728 uint enabledGfxFeatures; 01729 bool portalsOnly; 01730 bool meshesOnly; 01731 bool parseShaders; 01732 bool blockShaderLoad; 01733 bool parsedShaders; 01734 bool parseShaderVars; 01735 bool forceCuller; 01736 csString culler; 01737 } config; 01738 } parserData; 01739 01740 struct ParserData 01741 { 01742 ParserData(GlobalParserData& data) : data(data) 01743 { 01744 } 01745 01746 // global data 01747 GlobalParserData& data; 01748 01749 // temporary data used on a per-library basis 01750 csRefArray<iThreadReturn> rets; 01751 Zone* zone; 01752 csRef<Sector> currentSector; 01753 LockedType<Light> lights; 01754 LockedType<Sequence> sequences; 01755 LockedType<Trigger> triggers; 01756 csString vfsPath; 01757 csString path; 01758 bool realRoot; 01759 bool parsedMeshFact; 01760 }; 01761 01762 /***********************************************************************/ 01763 01764 /* Parsing Methods */ 01765 // parser tokens 01766 #define CS_TOKEN_ITEM_FILE "src/plugins/common/bgloader/parser.tok" 01767 #define CS_TOKEN_LIST_TOKEN_PREFIX PARSERTOKEN_ 01768 #include "cstool/tokenlist.h" 01769 #undef CS_TOKEN_ITEM_FILE 01770 #undef CS_TOKEN_LIST_TOKEN_PREFIX 01771 01772 void ParseMaterials(iDocumentNode* materialsNode); 01773 01774 /* shader methods */ 01775 void ParseShaders(); 01776 01777 /* Internal unloading methods. */ 01778 void CleanDisconnectedSectors(Sector* sector); 01779 01780 bool LoadSequencesAndTriggers (iDocumentNode* snode, iDocumentNode* tnode, ParserData& data); 01781 01782 // Pointers to other needed plugins. 01783 iObjectRegistry* object_reg; 01784 csRef<iEngine> engine; 01785 csRef<iGraphics2D> g2d; 01786 csRef<iThreadedLoader> tloader; 01787 csRef<iThreadManager> tman; 01788 csRef<iVFS> vfs; 01789 csRef<iCollideSystem> cdsys; 01790 CS::Threading::RecursiveMutex vfsLock; 01791 01792 // currently loaded zones - used by zone-based loading 01793 ObjectLoader<Zone> loadedZones; 01794 01795 // currently loading objects 01796 CS::Threading::RecursiveMutex loadLock; 01797 size_t loadOffset; 01798 size_t delayedOffset; 01799 csArray<csPtrKey<Loadable> > loadList; 01800 csArray<csPtrKey<iDelayedLoader> > delayedLoadList; 01801 01802 // Our load range ^_^ 01803 float loadRange; 01804 01805 // Whether the current position is valid. 01806 bool validPosition; 01807 01808 // Limit on how many portals deep we load. 01809 uint maxPortalDepth; 01810 01811 // Number of checks an object may be lingering 01812 // without aborting the load 01813 size_t maxLingerCount; 01814 01815 // The last valid sector. 01816 csRef<Sector> lastSector; 01817 01818 // The last valid position. 01819 csVector3 lastPos; 01820 01821 // current load step - use for ContinueLoading 01822 size_t loadStep; 01823 01824 // For world manipulation. 01825 csRef<iMeshWrapper> selectedMesh; 01826 csRef<MeshFact> selectedFactory; 01827 csRef<Material> selectedMaterial; 01828 csVector2 previousPosition; 01829 csVector3 origTrans; 01830 csVector3 rotBase; 01831 csVector3 origRot; 01832 csVector3 currRot_h; 01833 csVector3 currRot_v; 01834 bool resetHitbeam; 01835 }; 01836 } 01837 CS_PLUGIN_NAMESPACE_END(bgLoader) 01838 01839 #endif // __LOADER_H__ 01840