Planeshift

loader.h

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