Planeshift
loader.h
Go to the documentation of this file.
1 /*
2  * loader.h - Author: Mike Gist
3  *
4  * Copyright (C) 2009 Atomic Blue (info@planeshift.it, http://www.atomicblue.org)
5  *
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation (version 2 of the License)
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  */
19 
20 #ifndef __LOADER_H__
21 #define __LOADER_H__
22 
23 #include <csgeom/poly3d.h>
24 #include <csgfx/shadervar.h>
25 #include <csutil/scf_implementation.h>
26 #include <csutil/hash.h>
27 #include <csutil/threading/rwmutex.h>
28 #include <csutil/threadmanager.h>
29 #include <csutil/refcount.h>
30 #include <csutil/typetraits.h>
31 
32 #include <iengine/engine.h>
33 #include <iengine/material.h>
34 #include <iengine/mesh.h>
35 #include <iengine/meshgen.h>
36 #include <iengine/sector.h>
37 #include <iengine/texture.h>
38 #include <iengine/movable.h>
39 #include <imesh/object.h>
40 #include <imesh/objmodel.h>
41 #include <imap/loader.h>
42 #include <iutil/objreg.h>
43 #include <iutil/vfs.h>
44 
45 #include <ibgloader.h>
46 #include <iscenemanipulate.h>
47 
48 #ifdef CS_DEBUG
49 #define LOADER_DEBUG_MESSAGE(...) csPrintf(__VA_ARGS__)
50 #else
51 #define LOADER_DEBUG_MESSAGE(...)
52 #endif
53 
54 //#ifdef CS_DEBUG
55 #undef CS_ASSERT_MSG
56 #define CS_ASSERT_MSG(msg, x) if(!(x)) printf("ART ERROR: %s\n", msg)
57 //#endif
58 
59 struct iCollideSystem;
60 struct iEngineSequenceManager;
61 struct iSyntaxService;
62 
64 {
65 
66 // string literals for usage as template parameter
67 namespace ObjectNames
68 {
69  extern const char texture[8];
70  extern const char material[9];
71  extern const char trigger[8];
72  extern const char sequence[9];
73  extern const char meshobj[5];
74  extern const char meshfact[13];
75  extern const char meshgen[8];
76  extern const char light[6];
77  extern const char portal[7];
78  extern const char sector[7];
79 }
80 
90 class BgLoader : public ThreadedCallable<BgLoader>,
91  public scfImplementation3<BgLoader,
92  iBgLoader,
93  iSceneManipulate,
94  iComponent>
95 {
96 private:
97  // forward declaration
98  class Loadable;
99  struct iDelayedLoader;
100 
101 public:
102  BgLoader(iBase *p);
103  virtual ~BgLoader();
104 
108  bool Initialize(iObjectRegistry* _object_reg);
109 
113  csPtr<iThreadReturn> LoadMaterial(const char* name, bool wait = false);
114 
118  csPtr<iThreadReturn> LoadFactory(const char* name, bool wait = false);
119 
128  void CloneFactory(const char* name, const char* newName, bool* failed = NULL, const csReversibleTransform& trans = csReversibleTransform());
129 
136  THREADED_CALLABLE_DECL1(BgLoader, PrecacheData, csThreadReturn, const char*, path, THREADEDL, false, false);
137 
142  void ClearTemporaryData()
143  {
144  parserData.xmltokens.Empty();
145  parserData.textures.Clear();
146  parserData.meshes.Clear();
147  parserData.svstrings.Invalidate();
148  parserData.syntaxService.Invalidate();
149  tman.Invalidate();
150  }
151 
160  void UpdatePosition(const csVector3& pos, const char* sectorName, bool force);
161 
172  void ContinueLoading(bool waiting);
173 
177  iThreadedLoader* GetLoader() { return tloader; }
178 
182  size_t GetLoadingCount() { return loadList.GetSize(); }
183 
187  iObjectRegistry* GetObjectRegistry() const { return object_reg; }
188 
192  void SetLoadRange(float r) { loadRange = r; if (lastSector.IsValid()) UpdatePosition(lastPos, lastSector->GetName(), true); }
193 
198  bool HasValidPosition() const { return validPosition; }
199 
206  bool InWaterArea(const char* sector, csVector3* pos, csColor4** colour);
207 
211  bool LoadZones(iStringArray* regions, bool priority = false);
212 
217  bool LoadPriorityZones(iStringArray* regions);
218 
224  csPtr<iStringArray> GetShaderName(const char* usageType);
225 
233  iMeshWrapper* CreateAndSelectMesh(const char* factName, const char* matName,
234  iCamera* camera, const csVector2& pos);
235 
241  iMeshWrapper* SelectMesh(iCamera* camera, const csVector2& pos);
242 
250  bool TranslateSelected(bool vertical, iCamera* camera, const csVector2& pos);
251 
256  void RotateSelected(const csVector2& pos);
257 
264  void SetRotation(int flags_h, int flags_v);
265 
269  void SetPosition(const csVector2& pos) { previousPosition = pos; };
270 
274  void RemoveSelected();
275 
276  void GetPosition(csVector3 & pos, csVector3 & rot, const csVector2& screenPos);
277 
281  csRefArray<StartPosition> GetStartPositions()
282  {
283  csRefArray<StartPosition> array;
284  CS::Threading::ScopedReadLock lock(parserData.positions.lock);
285  LockedType<StartPosition>::HashType::GlobalIterator it(parserData.positions.hash.GetIterator());
286  while(it.HasNext())
287  {
288  array.Push(it.Next());
289  }
290  return array;
291  }
292 
293  // internal accessors
294  iEngine* GetEngine() const
295  {
296  return engine;
297  }
298 
299  iVFS* GetVFS()
300  {
301  vfsLock.Lock();
302  return vfs;
303  }
304 
305  void ReleaseVFS()
306  {
307  vfsLock.Unlock();
308  }
309 
310  iThreadedLoader* GetLoader() const
311  {
312  return tloader;
313  }
314 
315  iCollideSystem* GetCDSys() const
316  {
317  return cdsys;
318  }
319 
320  // increase load count - to be used by loadables only
321  void RegisterPendingObject(Loadable* obj)
322  {
323  CS::Threading::RecursiveMutexScopedLock lock(loadLock);
324  loadList.Push(obj);
325  }
326 
327  // decrease load count - to be used by loadables only
328  void UnregisterPendingObject(Loadable* obj)
329  {
330  CS::Threading::RecursiveMutexScopedLock lock(loadLock);
331  size_t index = loadList.Find(obj);
332 
333  // make sure ContinuedLoading won't skip any elements
334  if(index <= loadOffset)
335  {
336  --loadOffset;
337  }
338  loadList.DeleteIndex(index);
339  }
340 
341  // register delayed loader
342  void RegisterDelayedLoader(iDelayedLoader* loader)
343  {
344  CS::Threading::RecursiveMutexScopedLock lock(loadLock);
345  delayedLoadList.Push(loader);
346  }
347 
348  void UnregisterDelayedLoader(iDelayedLoader* loader)
349  {
350  CS::Threading::RecursiveMutexScopedLock lock(loadLock);
351  size_t index = delayedLoadList.Find(loader);
352 
353  // make sure ContinuedLoading won't skip any elements
354  if(index <= delayedOffset)
355  {
356  --delayedOffset;
357  }
358  delayedLoadList.DeleteIndex(index);
359  }
360 
361 private:
362  // The various gfx feature options we have.
363  enum gfxFeatures
364  {
365  useLowestShaders = 0x1,
366  useLowShaders = 0x2 | useLowestShaders,
367  useMediumShaders = 0x4 | useLowShaders,
368  useHighShaders = 0x8 | useMediumShaders,
369  useHighestShaders = 0x10 | useHighShaders,
370  useShadows = 0x20,
371  useMeshGen = 0x40,
372  useAll = (useHighestShaders | useShadows | useMeshGen)
373  };
374 
375  /********************************************************
376  * Data structures representing components of the world.
377  *******************************************************/
378 
379  // forward declarations
380  class Sector;
381  class Zone;
382  class Texture;
383  class MeshObj;
384  class Sequence;
385  class Light;
386  struct ParserData;
387  struct GlobalParserData;
388 
389  // generic objects used for loading/parsing
390 
391  // helper clases used with object classes that represent the world
392  template<typename T> struct CheckedLoad
393  {
394  csRef<T> obj;
395  bool checked;
396 
397  CheckedLoad(const csRef<T>& obj) : obj(obj), checked(false)
398  {
399  }
400 
401  CheckedLoad(const CheckedLoad& other) : obj(other.obj), checked(false)
402  {
403  }
404  };
405 
409  template<typename T, bool check = true> struct LockedType
410  {
411  public:
412  typedef csHash<csRef<T>, csStringID> HashType;
413  HashType hash;
414  csStringSet stringSet;
415  CS::Threading::ReadWriteMutex lock;
416 
417  csPtr<T> Get(const char* name)
418  {
419  csRef<T> object;
420  CS::Threading::ScopedReadLock scopedLock(lock);
421  if(stringSet.Contains(name))
422  {
423  csStringID objectID = stringSet.Request(name);
424  object = hash.Get(objectID, csRef<T>());
425  }
426  return csPtr<T>(object);
427  }
428 
429  // workaround for completely braindead gcc 4.0.x (thanks apple!)
430  void Put(const csRef<T>& obj)
431  {
432  Put(obj, 0);
433  }
434 
435  void Put(const csRef<T>& obj, const char* name)
436  {
437  CS::Threading::ScopedWriteLock scopedLock(lock);
438  csStringID objectID;
439  if(name)
440  {
441  objectID = stringSet.Request(name);
442  }
443  else
444  {
445  objectID = stringSet.Request(obj->GetName());
446  }
447 
448  // check for duplicates
449  if(check && hash.Contains(objectID))
450  {
451  //LOADER_DEBUG_MESSAGE("detected name conflict for object '%s'\n", name ? name : obj->GetName());
452  }
453  else
454  {
455  hash.Put(objectID, obj);
456  }
457  }
458 
459  void Delete(const char* name)
460  {
461  CS::Threading::ScopedWriteLock scopedLock(lock);
462  if(stringSet.Contains(name))
463  {
464  csStringID id = stringSet.Request(name);
465  hash.DeleteAll(id);
466  stringSet.Delete(id);
467  }
468  }
469 
470  void Clear()
471  {
472  stringSet.Empty();
473  hash.Empty();
474  }
475  };
476 
477  class RangeBased
478  {
479  protected:
480  csBox3 bbox;
481 
482  public:
483  inline bool InRange(const csBox3& curBBox) const
484  {
485  return curBBox.Overlap(bbox);
486  }
487 
488  inline bool OutOfRange(const csBox3& curBBox) const
489  {
490  return !curBBox.Overlap(bbox);
491  }
492  };
493 
494  // Loaded unconditionally - not range based.
495  class AlwaysLoaded
496  {
497  public:
498  inline bool InRange(const csBox3& /*curBBox*/) const
499  {
500  return true;
501  }
502 
503  inline bool OutOfRange(const csBox3& /*curBBox*/) const
504  {
505  return false;
506  }
507  };
508 
512  class Loadable : public csObject
513  {
514  public:
515  Loadable(BgLoader* parent) : parent(parent),
516  loading(false), useCount(0)
517  {
518  }
519 
520  Loadable(const Loadable& other) : csObject(0), parent(other.parent),
521  loading(false), useCount(0)
522  {
523  SetName(other.GetName());
524  }
525 
526  virtual ~Loadable()
527  {
528  }
529 
530  /*
531  * Return true if underlying CS object was loaded.
532  */
533  bool Load(bool wait = false)
534  {
535  CS::Threading::RecursiveMutexScopedLock lock(busy);
536  checked = true;
537  if(useCount == 0)
538  {
539  lingerCount = 0;
540 
541  if(!loading)
542  {
543  loading = true;
544  GetParent()->RegisterPendingObject(this);
545  }
546 
547  if(LoadObject(wait))
548  {
549  loading = false;
550  ++useCount;
551  GetParent()->UnregisterPendingObject(this);
552 
553  FinishObject();
554  }
555 
556  return !loading;
557  }
558  else
559  {
560  ++useCount;
561  return true;
562  }
563  }
564 
565  void AbortLoad()
566  {
567  CS::Threading::RecursiveMutexScopedLock lock(busy);
568  if(loading)
569  {
570  loading = false;
571  checked = false;
572 
573  // do a blocked load and then unload for now
574  // to prevent some race conditions with CS' internal loader
575  Load(true);
576  Unload();
577 
578  //UnloadObject();
579  GetParent()->UnregisterPendingObject(this);
580  }
581  }
582 
583  void Unload()
584  {
585  CS::Threading::RecursiveMutexScopedLock lock(busy);
586  if(useCount == 0)
587  {
588  LOADER_DEBUG_MESSAGE("tried to free not loaded object '%s'\n", GetName());
589  return;
590  }
591 
592  CS_ASSERT_MSG("unloading currently loading object!", !loading);
593 
594  --useCount;
595  if(useCount == 0)
596  {
597  UnloadObject();
598  }
599  }
600 
601  virtual bool LoadObject(bool wait) = 0;
602  virtual void UnloadObject() = 0;
603  virtual void FinishObject() {}
604 
605  bool IsLoaded() const
606  {
607  CS::Threading::RecursiveMutexScopedLock lock(busy);
608  return useCount > 0;
609  }
610 
611  inline BgLoader* GetParent() const
612  {
613  return parent;
614  }
615 
616  void ResetChecked()
617  {
618  CS::Threading::RecursiveMutexScopedLock lock(busy);
619  checked = false;
620  }
621 
622  bool IsChecked() const
623  {
624  CS::Threading::RecursiveMutexScopedLock lock(busy);
625  return checked;
626  }
627 
628  size_t GetLingerCount() const
629  {
630  CS::Threading::RecursiveMutexScopedLock lock(busy);
631  return lingerCount;
632  }
633 
634  void IncLingerCount()
635  {
636  CS::Threading::RecursiveMutexScopedLock lock(busy);
637  ++lingerCount;
638  }
639 
640  protected:
641  void MarkChecked()
642  {
643  CS::Threading::RecursiveMutexScopedLock lock(busy);
644  checked = true;
645  }
646 
647  template<typename T, const char* TypeName> void CheckRemove(csRef<T>& ref)
648  {
649  if(ref.IsValid())
650  {
651  csWeakRef<T> check(ref);
652  parent->GetEngine()->RemoveObject(ref);
653  ref.Invalidate();
654  if(check.IsValid())
655  {
656  LOADER_DEBUG_MESSAGE("detected leaking %s: %u %s\n", TypeName, check->GetRefCount(), GetName());
657  }
658  }
659  }
660 
661  private:
662  mutable CS::Threading::RecursiveMutex busy;
663 
664  BgLoader* parent;
665  bool loading;
666  bool checked;
667  size_t lingerCount;
668  size_t useCount;
669  };
670 
671  struct iDelayedLoader : public iThreadReturn
672  {
673  virtual void ContinueLoading(bool wait) = 0;
674  };
675 
676  template<typename T> class DelayedLoader : public scfImplementation1<DelayedLoader<T>, iDelayedLoader>
677  {
678  public:
679  DelayedLoader(T* target) : scfImplementation1<DelayedLoader<T>, iDelayedLoader>(this),
680  target(target), finished(false),
681  waitLock(0), waitCondition(0)
682  {
683  if(target)
684  {
685  // valid target, register us with the parent
686  BgLoader* parent = target->GetParent();
687  parent->RegisterDelayedLoader(this);
688  }
689  else
690  {
691  finished = true;
692  }
693  }
694 
695  virtual ~DelayedLoader()
696  {
697  if(!target.IsValid())
698  {
699  return;
700  }
701 
702  // free result
703  result.Invalidate();
704 
705  if(finished)
706  {
707  // unload the object
708  target->Unload();
709  }
710  else
711  {
712  // unregister us with the parent
713  BgLoader* parent = target->GetParent();
714  parent->UnregisterDelayedLoader(this);
715 
716  // don't abort load here - we're still on the load
717  // list so we'll be detected as lingering if applicaple
718  // and removed accordingly
719  }
720  }
721 
722  void ContinueLoading(bool wait)
723  {
724  CS::Threading::MutexScopedLock lock(busy);
725  if(target.IsValid() && !finished && target->Load(wait))
726  {
727  // done loading
728 
729  // unregister us with the parent
730  BgLoader* parent = target->GetParent();
731  parent->UnregisterDelayedLoader(this);
732 
733  if(waitLock) waitLock->Lock();
734 
735  // mark finished and set result accordingly;
736  finished = true;
737  csRef<typename T::ObjectType> ref = target->GetObject();
738  result = ref;
739 
740  // notify tm if it's waiting for us
741  if(waitCondition)
742  {
743  waitCondition->NotifyAll();
744  }
745 
746  if(waitLock) waitLock->Unlock();
747  }
748  }
749 
750  void Wait(bool /*process*/)
751  {
752  ContinueLoading(true);
753  }
754 
755  void* GetResultPtr()
756  {
757  CS::Threading::MutexScopedLock lock(busy);
758  return result;
759  }
760 
761  csRef<iBase> GetResultRefPtr()
762  {
763  CS::Threading::MutexScopedLock lock(busy);
764  return result;
765  }
766 
767  bool IsFinished()
768  {
769  CS::Threading::MutexScopedLock lock(busy);
770  return finished;
771  }
772 
773  bool WasSuccessful()
774  {
775  CS::Threading::MutexScopedLock lock(busy);
776  return result.IsValid();
777  }
778 
779  void SetWaitPtrs(CS::Threading::Condition* c, CS::Threading::Mutex* m)
780  {
781  CS::Threading::MutexScopedLock lock(busy);
782  waitCondition = c;
783  waitLock = m;
784  }
785 
786  // doesn't have to be threadsafe
787  void SetJob(iJob* newJob)
788  {
789  job = newJob;
790  }
791 
792  // doesn't have to be threadsafe
793  iJob* GetJob() const
794  {
795  return job;
796  }
797 
798  private:
799  // disable functions iThreadReturn requires but we don't want to implement
800  void MarkSuccessful() {}
801  void MarkFinished() {}
802  void SetResult(csRef<iBase> /*result*/) {}
803  void SetResult(void* /*result*/) {}
804  void Copy(iThreadReturn* /*other*/) {}
805 
806  // private data
807  CS::Threading::Mutex busy;
808  csRef<T> target;
809  csRef<iBase> result;
810  bool finished;
811 
812  // thread return specific data
813  CS::Threading::Mutex* waitLock;
814  CS::Threading::Condition* waitCondition;
815  csRef<iJob> job;
816  };
817 
818  // trivial loadable (e.g. triggers, textures, ...)
819  template<typename T, const char* TypeName> class TrivialLoadable : public Loadable
820  {
821  public:
822  typedef T ObjectType;
823 
824  TrivialLoadable(BgLoader* parent) : Loadable(parent)
825  {
826  }
827 
828  TrivialLoadable(const TrivialLoadable& other)
829  : Loadable(other.GetParent()), path(other.path),
830  data(other.data)
831  {
832  }
833 
834  bool LoadObject(bool wait)
835  {
836  if(!status.IsValid())
837  {
838  if(!data.IsValid())
839  {
840  LOADER_DEBUG_MESSAGE("%s %s was created, but never parsed!\n", TypeName, GetName());
841  return true;
842  }
843  status = GetParent()->GetLoader()->LoadNode(path, data);
844  }
845 
846  if(wait)
847  {
848  status->Wait();
849  }
850 
851  if(status->IsFinished())
852  {
853  if(!status->WasSuccessful())
854  {
855  LOADER_DEBUG_MESSAGE("%s %s failed to load\n", TypeName, GetName());
856  }
857  return true;
858  }
859  else
860  {
861  return false;
862  }
863  }
864 
865  void UnloadObject()
866  {
867  csRef<T> ref = GetObject();
868  status.Invalidate();
869  Loadable::CheckRemove<T,TypeName>(ref);
870  }
871 
872  csPtr<T> GetObject()
873  {
874  if(status.IsValid() && status->IsFinished() && status->WasSuccessful())
875  {
876  csRef<iBase> rawObj = status->GetResultRefPtr();
877  if(rawObj.IsValid())
878  {
879  return scfQueryInterface<T>(rawObj);
880  }
881  }
882 
883  return csPtr<T>(0);
884  }
885 
886  protected:
887  // parse results
888  csString path;
889  csRef<iDocumentNode> data;
890 
891  // load data
892  csRef<iThreadReturn> status;
893  };
894 
895  // helper class that allows a specific dependency type for an object
896  template<typename T> class ObjectLoader
897  {
898  public:
899  typedef CheckedLoad<T> HashObjectType;
900  typedef csHash<HashObjectType, csString> HashType;
901 
902  ObjectLoader() : objectCount(0)
903  {
904  }
905 
906  ObjectLoader(const ObjectLoader& other) : objectCount(0)
907  {
908  CS::Threading::RecursiveMutexScopedLock lock(other.busy);
909  typename HashType::ConstGlobalIterator it(other.objects.GetIterator());
910  while(it.HasNext())
911  {
912  csString key;
913  HashObjectType obj(it.Next(key));
914  objects.Put(key, obj);
915  }
916  }
917 
918  ~ObjectLoader()
919  {
920  UnloadObjects();
921  }
922 
923  size_t GetObjectCount() const
924  {
925  CS::Threading::RecursiveMutexScopedLock lock(busy);
926  return objectCount;
927  }
928 
929  // workaround for bug in gcc 4.0: fails to parse default function arguments in template classes
930  bool LoadObjects()
931  {
932  return LoadObjects(false);
933  }
934 
935  // load all dependencies of this type
936  // return true if all are ready
937  bool LoadObjects(bool wait)
938  {
939  CS::Threading::RecursiveMutexScopedLock lock(busy);
940  if(objectCount == objects.GetSize())
941  {
942  // nothing to be done
943  return true;
944  }
945 
946  bool ready = true;
947  typename HashType::GlobalIterator it(objects.GetIterator());
948  while(it.HasNext())
949  {
950  HashObjectType& ref = it.Next();
951  if(!ref.checked)
952  {
953  ref.checked = ref.obj->Load(wait);
954  if(ref.checked)
955  {
956  ++objectCount;
957  }
958  else
959  {
960  ready = false;
961  }
962  }
963  }
964  return ready;
965  }
966 
967  // unloads all dependencies of this type
968  void UnloadObjects()
969  {
970  CS::Threading::RecursiveMutexScopedLock lock(busy);
971  if(!objectCount)
972  {
973  // nothing to be done
974  return;
975  }
976 
977  typename HashType::GlobalIterator it(objects.GetIterator());
978  while(it.HasNext())
979  {
980  HashObjectType& ref = it.Next();
981  if(ref.checked)
982  {
983  ref.obj->Unload();
984  ref.checked = false;
985  --objectCount;
986  }
987  }
988  }
989 
990  int UpdateObjects(const csBox3& loadBox, const csBox3& keepBox)
991  {
992  CS::Threading::RecursiveMutexScopedLock lock(busy);
993  int oldObjectCount = objectCount;
994  if(CS::Meta::IsBaseOf<RangeBased,T>::value)
995  {
996  typename HashType::GlobalIterator it(objects.GetIterator());
997  while(it.HasNext())
998  {
999  HashObjectType& ref = it.Next();
1000  if(ref.checked)
1001  {
1002  if(ref.obj->OutOfRange(keepBox))
1003  {
1004  ref.obj->Unload();
1005  ref.checked = false;
1006  --objectCount;
1007  }
1008  }
1009  else if(ref.obj->InRange(loadBox))
1010  {
1011  ref.checked = ref.obj->Load(false);
1012  if(ref.checked)
1013  {
1014  ++objectCount;
1015  }
1016  }
1017  }
1018  }
1019  else
1020  {
1021  LoadObjects(false);
1022  }
1023  return (int)objectCount - oldObjectCount;
1024  }
1025 
1026  void AddDependency(T* obj)
1027  {
1028  CS::Threading::RecursiveMutexScopedLock lock(busy);
1029  if(!objects.Contains(obj->GetName()))
1030  {
1031  objects.Put(obj->GetName(), csRef<T>(obj));
1032  }
1033  }
1034 
1035  void RemoveDependency(const T* obj)
1036  {
1037  CS::Threading::RecursiveMutexScopedLock lock(busy);
1038  const HashObjectType& ref = objects.Get(obj->GetName(), HashObjectType(csRef<T>()));
1039  if(ref.checked)
1040  {
1041  ref.obj->Unload();
1042  --objectCount;
1043  }
1044  objects.DeleteAll(obj->GetName());
1045  }
1046 
1047  // workaround for bug in gcc 4.0: fails to parse default function argument in template classes
1048  const csRef<T>& GetDependency(const char* name) const
1049  {
1050  return GetDependency(name, csRef<T>());
1051  }
1052 
1053  const csRef<T>& GetDependency(const char* name, const csRef<T>& fallbackobj) const
1054  {
1055  CS::Threading::RecursiveMutexScopedLock lock(busy);
1056  const HashObjectType& ref = objects.Get(name,fallbackobj);
1057  return ref.obj;
1058  }
1059 
1060  bool HasDependency(const char* name) const
1061  {
1062  CS::Threading::RecursiveMutexScopedLock lock(busy);
1063  return objects.Contains(name);
1064  }
1065 
1066  HashType& GetDependencies()
1067  {
1068  return objects;
1069  }
1070 
1071  const HashType& GetDependencies() const
1072  {
1073  return objects;
1074  }
1075 
1076  protected:
1077  mutable CS::Threading::RecursiveMutex busy;
1078 
1079  HashType objects;
1080  size_t objectCount;
1081  };
1082 
1083  // actual world objects
1084 
1085  struct WaterArea
1086  {
1087  csBox3 bbox;
1088  csColor4 colour;
1089  };
1090 
1091  class ShaderVar : public CS::Utility::AtomicRefCount
1092  {
1093  public:
1094  ShaderVar(BgLoader* parent, ObjectLoader<Texture>* object) : parent(parent), object(object)
1095  {
1096  }
1097 
1098  ~ShaderVar()
1099  {
1100  }
1101 
1102  template<bool check> bool Parse(iDocumentNode* node, GlobalParserData& data);
1103  void LoadObject(csShaderVariable* var);
1104  CS::ShaderVarStringID GetID() const
1105  {
1106  return nameID;
1107  }
1108 
1109  private:
1110  CS::ShaderVarStringID nameID;
1111  csShaderVariable::VariableType type;
1112  csString value;
1113  float vec1;
1114  csVector2 vec2;
1115  csVector3 vec3;
1116  csVector4 vec4;
1117 
1118  BgLoader* parent;
1119  ObjectLoader<Texture>* object;
1120  };
1121 
1122  class Texture : public TrivialLoadable<iTextureWrapper,ObjectNames::texture>
1123  {
1124  public:
1125  Texture(BgLoader* parent) : TrivialLoadable<iTextureWrapper,ObjectNames::texture>(parent)
1126  {
1127  }
1128 
1129  bool Parse(iDocumentNode* node, ParserData& data);
1130  };
1131 
1132  class Material : public Loadable, public ObjectLoader<Texture>
1133  {
1134  public:
1135  typedef iMaterialWrapper ObjectType;
1136 
1137  using ObjectLoader<Texture>::AddDependency;
1138 
1139  Material(BgLoader* parent) : Loadable(parent)
1140  {
1141  }
1142 
1143  bool Parse(iDocumentNode* node, GlobalParserData& data);
1144 
1145  bool LoadObject(bool wait);
1146  void UnloadObject();
1147  csPtr<iMaterialWrapper> GetObject()
1148  {
1149  csRef<iMaterialWrapper> wrapper(materialWrapper);
1150  return csPtr<iMaterialWrapper>(wrapper);
1151  }
1152 
1153  private:
1154  // dependencies
1155  struct Shader
1156  {
1157  csRef<iShader> shader;
1158  csStringID type;
1159  };
1160  csArray<Shader> shaders;
1161  csRefArray<ShaderVar> shadervars;
1162 
1163  // load data
1164  csRef<iMaterialWrapper> materialWrapper;
1165  };
1166 
1167  class MaterialLoader : public ObjectLoader<Material>
1168  {
1169  public:
1170  void ParseMaterialReference(GlobalParserData& data, const char* name, const char* parentName, const char* type);
1171  };
1172 
1173  class Trigger : public ObjectLoader<Sequence>,
1174  public ObjectLoader<MeshObj>,
1175  public ObjectLoader<Light>,
1176  public TrivialLoadable<iSequenceTrigger,ObjectNames::trigger>,
1177  public AlwaysLoaded
1178  {
1179  public:
1180  using ObjectLoader<Sequence>::AddDependency;
1181  using ObjectLoader<MeshObj>::AddDependency;
1182  using ObjectLoader<Light>::AddDependency;
1183 
1184  Trigger(BgLoader* parent) : TrivialLoadable<iSequenceTrigger,ObjectNames::trigger>(parent)
1185  {
1186  }
1187 
1188  bool LoadObject(bool wait)
1189  {
1190  bool ready = ObjectLoader<Sequence>::LoadObjects(true);
1191  ready &= ObjectLoader<MeshObj>::LoadObjects(true);
1192  ready &= ObjectLoader<Light>::LoadObjects(true);
1193  ready &= TrivialLoadable<iSequenceTrigger,ObjectNames::trigger>::LoadObject(true);
1194  return ready;
1195  //return TrivialLoadable<iSequenceTrigger,ObjectNames::trigger>::LoadObject(true);
1196  }
1197 
1198  void UnloadObject()
1199  {
1200  TrivialLoadable<iSequenceTrigger,ObjectNames::trigger>::UnloadObject();
1201  ObjectLoader<Sequence>::UnloadObjects();
1202  ObjectLoader<MeshObj>::UnloadObjects();
1203  ObjectLoader<Light>::UnloadObjects();
1204  }
1205 
1206  bool Parse(iDocumentNode* node, ParserData& data);
1207  };
1208 
1209  class Sequence : public ObjectLoader<Sequence>,
1210  public ObjectLoader<Trigger>,
1211  public ObjectLoader<Light>,
1212  public ObjectLoader<MeshObj>,
1213  public MaterialLoader,
1214  public TrivialLoadable<iSequenceWrapper,ObjectNames::sequence>,
1215  public AlwaysLoaded
1216  {
1217  public:
1218  using ObjectLoader<Sequence>::AddDependency;
1219  using ObjectLoader<Trigger>::AddDependency;
1220  using ObjectLoader<Light>::AddDependency;
1221  using ObjectLoader<MeshObj>::AddDependency;
1222 
1223  Sequence(BgLoader* parent) : TrivialLoadable<iSequenceWrapper,ObjectNames::sequence>(parent)
1224  {
1225  }
1226 
1227  bool Parse(iDocumentNode* node, ParserData& data);
1228 
1229  bool LoadObject(bool wait)
1230  {
1231  // work around a race condition with engseqmgr
1232  wait = true;
1233 
1234  bool ready = true;
1235  if(ready)
1236  {
1237  ready = ObjectLoader<MeshObj>::LoadObjects(wait);
1238  }
1239 
1240  if(ready)
1241  {
1242  ready = ObjectLoader<Sequence>::LoadObjects(wait);
1243  }
1244 
1245  if(ready)
1246  {
1247  ready = TrivialLoadable<iSequenceWrapper,ObjectNames::sequence>::LoadObject(wait);
1248  }
1249 
1250  if(ready)
1251  {
1252  ready = ObjectLoader<Trigger>::LoadObjects(wait);
1253  }
1254  return ready;
1255  }
1256 
1257  void UnloadObject()
1258  {
1259  TrivialLoadable<iSequenceWrapper,ObjectNames::sequence>::UnloadObject();
1260  ObjectLoader<Sequence>::UnloadObjects();
1261  ObjectLoader<Trigger>::UnloadObjects();
1262  ObjectLoader<MeshObj>::UnloadObjects();
1263  }
1264  };
1265 
1266  class Light : public Loadable, public RangeBased
1267  {
1268  public:
1269  typedef iLight ObjectType;
1270 
1271  Light(BgLoader* parent) : Loadable(parent)
1272  {
1273  }
1274 
1275  bool Parse(iDocumentNode* node, ParserData& data);
1276 
1277  bool LoadObject(bool wait);
1278  void UnloadObject();
1279 
1280  csPtr<iLight> GetObject()
1281  {
1282  return csPtr<iLight>(light);
1283  }
1284 
1285  private:
1286  // parse results
1287  csVector3 pos;
1288  float radius;
1289  csColor colour;
1290  csLightDynamicType dynamic;
1291  csLightAttenuationMode attenuation;
1292  csLightType type;
1293 
1294  // dependencies
1295  Sector* sector;
1296 
1297  // load data
1298  csRef<iLight> light;
1299  };
1300 
1301  class MeshFact : public TrivialLoadable<iMeshFactoryWrapper,ObjectNames::meshfact>,
1302  public MaterialLoader
1303  {
1304  public:
1305  using ObjectLoader<Material>::AddDependency;
1306 
1307  MeshFact(BgLoader* parent) : TrivialLoadable<iMeshFactoryWrapper,ObjectNames::meshfact>(parent),
1308  cloned(false)
1309  {
1310  }
1311 
1312  bool Parse(iDocumentNode* node, ParserData& data);
1313  bool ParseCells(iDocumentNode* node, ParserData& data);
1314 
1315  csPtr<MeshFact> Clone(const char* name)
1316  {
1317  csRef<MeshFact> clone;
1318  clone.AttachNew(new MeshFact(GetParent()));
1319  clone->SetName(name);
1320 
1321  clone->cloned = true;
1322  clone->parentFactory = &*this;
1323  return csPtr<MeshFact>(clone);
1324  }
1325 
1326  bool operator==(const MeshFact& other)
1327  {
1328  if(cloned != other.cloned)
1329  {
1330  if(parentFactory.IsValid())
1331  {
1332  if(*parentFactory != other)
1333  {
1334  return false;
1335  }
1336  }
1337  else
1338  {
1339  if(*this != *other.parentFactory)
1340  {
1341  return false;
1342  }
1343  }
1344  }
1345  else if(cloned)
1346  {
1347  if(parentFactory != other.parentFactory)
1348  return false;
1349  }
1350  else
1351  {
1352  if(filename != other.filename)
1353  return false;
1354  if((iDocumentNode*)data != (iDocumentNode*)other.data)
1355  return false;
1356  }
1357 
1358  // ignore transformations for this check
1359 
1360  return true;
1361  }
1362 
1363  bool operator!=(const MeshFact& other)
1364  {
1365  return !(*this == other);
1366  }
1367 
1368  csPtr<iMeshFactoryWrapper> GetObject()
1369  {
1370  csRef<iMeshFactoryWrapper> object;
1371  if(cloned)
1372  {
1373  if(factory.IsValid())
1374  {
1375  object = factory;
1376  }
1377  else if(parentFactory.IsValid())
1378  {
1379  object = parentFactory->GetObject();
1380  }
1381  }
1382  else
1383  {
1384  object = TrivialLoadable<iMeshFactoryWrapper,ObjectNames::meshfact>::GetObject();
1385  }
1386  return csPtr<iMeshFactoryWrapper>(object);
1387  }
1388 
1389  void SetTransform(const csReversibleTransform& transform)
1390  {
1391  trans = transform;
1392  }
1393 
1394  bool LoadObject(bool wait);
1395  void UnloadObject();
1396  void FinishObject();
1397 
1398  bool FindSubmesh(const csString& name) const
1399  {
1400  return submeshes.Find(name) != csArrayItemNotFound;
1401  }
1402 
1403  const csArray<csVector3>& GetVertices() const
1404  {
1405  return bboxvs;
1406  }
1407 
1408  private:
1409  // cloning data
1410  bool cloned;
1411  csRef<MeshFact> parentFactory;
1412  csRef<iMeshFactoryWrapper> factory;
1413 
1414  // transformation data
1415  csReversibleTransform trans;
1416 
1417  // parser results
1418  csString filename;
1419  csArray<csVector3> bboxvs;
1420  csStringArray submeshes;
1421  };
1422 
1423  class MeshObj : public TrivialLoadable<iMeshWrapper,ObjectNames::meshobj>,
1424  public RangeBased, public ObjectLoader<Texture>,
1425  public MaterialLoader, public ObjectLoader<MeshFact>
1426  {
1427  public:
1428  using ObjectLoader<Texture>::AddDependency;
1429  using ObjectLoader<Material>::AddDependency;
1430  using ObjectLoader<MeshFact>::AddDependency;
1431 
1432  MeshObj(BgLoader* parent) : TrivialLoadable<iMeshWrapper,ObjectNames::meshobj>(parent)
1433  {
1434  }
1435 
1436  bool Parse(iDocumentNode* node, ParserData& data, bool& alwaysLoaded);
1437  bool ParseTriMesh(iDocumentNode* node, ParserData& data, bool& alwaysLoaded);
1438 
1439  bool LoadObject(bool wait);
1440  void UnloadObject();
1441  void FinishObject();
1442 
1443  bool FindSubmesh(const csString& name) const
1444  {
1445  typedef ObjectLoader<MeshFact>::HashType HashType;
1446  const HashType& factories = ObjectLoader<MeshFact>::GetDependencies();
1447  HashType::ConstGlobalIterator it(factories.GetIterator());
1448  bool found = false;
1449  while(it.HasNext() && !found)
1450  {
1451  const csRef<MeshFact>& factory = it.Next().obj;
1452  found |= factory->FindSubmesh(name);
1453  }
1454  return found;
1455  }
1456 
1457  private:
1458  // parse results
1459  bool dynamicLighting;
1460 
1461  // dependencies
1462  Sector* sector;
1463  csRefArray<ShaderVar> shadervars;
1464  };
1465 
1466  class MeshGen : public TrivialLoadable<iMeshGenerator,ObjectNames::meshgen>, public RangeBased, public MaterialLoader,
1467  public ObjectLoader<MeshFact>
1468  {
1469  public:
1470  using ObjectLoader<MeshFact>::AddDependency;
1471  using ObjectLoader<Material>::AddDependency;
1472 
1473  MeshGen(BgLoader* parent) : TrivialLoadable<iMeshGenerator,ObjectNames::meshgen>(parent),
1474  sector(0)
1475  {
1476  }
1477 
1478  bool Parse(iDocumentNode* node, ParserData& data);
1479 
1480  bool LoadObject(bool wait);
1481  void UnloadObject();
1482 
1483  private:
1484  // parser data
1485  Sector* sector;
1486 
1487  // dependencies
1488  csRef<MeshObj> mesh;
1489  };
1490 
1491  class Portal : public Loadable, public RangeBased
1492  {
1493  friend class Sector;
1494  public:
1495  typedef iMeshWrapper ObjectType;
1496 
1497  Portal(BgLoader* parent, float renderDist) : Loadable(parent), flags(0), renderDist(renderDist),
1498  warp(false), ww_given(false), wv(0.f), ww(0.f),
1499  autoresolve(0), targetSector(0), sector(0)
1500  {
1501  }
1502 
1503  bool Parse(iDocumentNode* node, ParserData& data);
1504 
1505  bool LoadObject(bool wait);
1506  void UnloadObject();
1507 
1508  csPtr<iMeshWrapper> GetObject()
1509  {
1510  csRef<iMeshWrapper> obj(mObject);
1511  return csPtr<iMeshWrapper>(obj);
1512  }
1513 
1514  private:
1515  // parser results
1516  uint32 flags;
1517  float renderDist;
1518 
1519  // transformation data
1520  bool warp;
1521  bool ww_given;
1522  csMatrix3 matrix;
1523  csVector3 wv;
1524  csVector3 ww;
1525  csReversibleTransform transform;
1526 
1527  // sector data
1528  bool autoresolve;
1529  Sector* targetSector;
1530  Sector* sector;
1531 
1532  // vertex data
1533  csPoly3D poly;
1534 
1535  // load data
1536  iPortal* pObject;
1537  csRef<iMeshWrapper> mObject;
1538 
1539  // sector callback
1540  class MissingSectorCallback : public scfImplementation1<MissingSectorCallback, iPortalCallback>
1541  {
1542  private:
1543  csRef<Sector> targetSector;
1544  bool autoresolve;
1545 
1546  public:
1547  MissingSectorCallback(Sector* target, bool resolve) : scfImplementationType(this),targetSector(target),autoresolve(resolve)
1548  {
1549  }
1550 
1551  virtual ~MissingSectorCallback()
1552  {
1553  }
1554 
1555  virtual bool Traverse(iPortal* p, iBase* /*context*/)
1556  {
1557  csRef<iSector> target = targetSector->GetObject();
1558  if(target.IsValid())
1559  {
1560  p->SetSector(target);
1561  }
1562  else
1563  {
1564  return false;
1565  }
1566 
1567  if(!autoresolve)
1568  {
1569  p->RemoveMissingSectorCallback(this);
1570  }
1571 
1572  return true;
1573  }
1574  };
1575  };
1576 
1577  class Sector : public Loadable,
1578  public ObjectLoader<MeshGen>, public ObjectLoader<MeshObj>,
1579  public ObjectLoader<Portal>, public ObjectLoader<Light>,
1580  public ObjectLoader<Sequence>, public ObjectLoader<Trigger>
1581  {
1582  public:
1583  using ObjectLoader<MeshGen>::AddDependency;
1584  using ObjectLoader<MeshObj>::AddDependency;
1585  using ObjectLoader<Portal>::AddDependency;
1586  using ObjectLoader<Light>::AddDependency;
1587  using ObjectLoader<Sequence>::AddDependency;
1588  using ObjectLoader<Trigger>::AddDependency;
1589 
1590  Sector(BgLoader* parent) : Loadable(parent), ambient(0.0f), objectCount(0),
1591  init(false), isLoading(false)
1592  {
1593  }
1594 
1595  ~Sector()
1596  {
1597  }
1598 
1599  bool Parse(iDocumentNode* node, ParserData& data);
1600 
1601  bool LoadObject(bool wait);
1602  void UnloadObject();
1603  int UpdateObjects(const csBox3& loadBox, const csBox3& keepBox, size_t recursions);
1604 
1605  bool Initialize();
1606  void ForceUpdateObjectCount();
1607  void FindConnectedSectors(csSet<csPtrKey<Sector> >& connectedSectors);
1608 
1609  void AddPortal(Portal* p)
1610  {
1611  CS::Threading::RecursiveMutexScopedLock lock(busy);
1612  activePortals.Add(p);
1613  }
1614 
1615  void RemovePortal(Portal* p)
1616  {
1617  CS::Threading::RecursiveMutexScopedLock lock(busy);
1618  activePortals.Delete(p);
1619  }
1620 
1621  void AddAlwaysLoaded(MeshObj* mesh)
1622  {
1623  alwaysLoaded.AddDependency(mesh);
1624  }
1625 
1626  csPtr<iSector> GetObject()
1627  {
1628  csRef<iSector> obj(object);
1629  return csPtr<iSector>(obj);
1630  }
1631 
1632  private:
1633  // parser results
1634  csString culler;
1635  csColor ambient;
1636  size_t objectCount;
1637  Zone* parent;
1638 
1639  // dependencies
1640  csArray<WaterArea> waterareas;
1641  ObjectLoader<MeshObj> alwaysLoaded;
1642 
1643  // load data
1644  CS::Threading::RecursiveMutex busy;
1645  csRef<iSector> object;
1646  csSet<csPtrKey<Portal> > activePortals;
1647  bool init;
1648  bool isLoading;
1649  };
1650 
1651  // Stores world representation.
1652  class Zone : public Loadable, public ObjectLoader<Sector>
1653  {
1654  public:
1655  using ObjectLoader<Sector>::AddDependency;
1656 
1657  Zone(BgLoader* parent, const char* name)
1658  : Loadable(parent), priority(false)
1659  {
1660  Loadable::SetName(name);
1661  }
1662 
1663  bool LoadObject(bool wait)
1664  {
1665  return ObjectLoader<Sector>::LoadObjects(wait);
1666  }
1667 
1668  void UnloadObject()
1669  {
1670  ObjectLoader<Sector>::UnloadObjects();
1671  }
1672 
1673  void UpdatePriority(bool newPriority)
1674  {
1675  if(priority != newPriority)
1676  {
1677  priority = newPriority;
1678 
1679  // upgrade sector priorities
1680  /*ObjectLoader<Sector>::HashType::GlobalIterator it(ObjectLoader<Sector>::objects.GetIterator());
1681  while(it.HasNext())
1682  {
1683  it.Next().obj->priority = newPriority;
1684  }*/
1685  }
1686  }
1687 
1688  bool GetPriority() const
1689  {
1690  return priority;
1691  }
1692 
1693  private:
1694  // loader data
1695  bool priority;
1696  };
1697 
1698  struct GlobalParserData
1699  {
1700  // token lookup table
1701  csStringHash xmltokens;
1702 
1703  // temporary parse-time data
1704  LockedType<Texture> textures;
1705  LockedType<MeshObj> meshes;
1706  csRef<iShaderVarStringSet> svstrings;
1707 
1708  // plugin references
1709  csRef<iSyntaxService> syntaxService;
1710  iObjectRegistry* object_reg;
1711 
1712  // persistent data
1713  csRef<iStringSet> strings;
1714  LockedType<Material> materials;
1715  LockedType<Sector> sectors;
1716  LockedType<MeshFact> factories;
1717  LockedType<Zone> zones;
1718  LockedType<StartPosition,false> positions;
1719  CS::Threading::ReadWriteMutex shaderLock;
1720  csHash<csString, csStringID> shadersByUsage;
1721  csStringArray shaders;
1722  csHash<csString, csString> shaderAliases;
1723 
1724  // config
1725  struct ParserConfig
1726  {
1727  bool cache;
1728  uint enabledGfxFeatures;
1729  bool portalsOnly;
1730  bool meshesOnly;
1731  bool parseShaders;
1732  bool blockShaderLoad;
1733  bool parsedShaders;
1734  bool parseShaderVars;
1735  bool forceCuller;
1736  csString culler;
1737  } config;
1738  } parserData;
1739 
1740  struct ParserData
1741  {
1742  ParserData(GlobalParserData& data) : data(data)
1743  {
1744  }
1745 
1746  // global data
1747  GlobalParserData& data;
1748 
1749  // temporary data used on a per-library basis
1750  csRefArray<iThreadReturn> rets;
1751  Zone* zone;
1752  csRef<Sector> currentSector;
1753  LockedType<Light> lights;
1754  LockedType<Sequence> sequences;
1755  LockedType<Trigger> triggers;
1756  csString vfsPath;
1757  csString path;
1758  bool realRoot;
1759  bool parsedMeshFact;
1760  };
1761 
1762  /***********************************************************************/
1763 
1764  /* Parsing Methods */
1765  // parser tokens
1766 #define CS_TOKEN_ITEM_FILE "src/plugins/common/bgloader/parser.tok"
1767 #define CS_TOKEN_LIST_TOKEN_PREFIX PARSERTOKEN_
1768 #include "cstool/tokenlist.h"
1769 #undef CS_TOKEN_ITEM_FILE
1770 #undef CS_TOKEN_LIST_TOKEN_PREFIX
1771 
1772  void ParseMaterials(iDocumentNode* materialsNode);
1773 
1774  /* shader methods */
1775  void ParseShaders();
1776 
1777  /* Internal unloading methods. */
1778  void CleanDisconnectedSectors(Sector* sector);
1779 
1780  bool LoadSequencesAndTriggers (iDocumentNode* snode, iDocumentNode* tnode, ParserData& data);
1781 
1782  // Pointers to other needed plugins.
1783  iObjectRegistry* object_reg;
1784  csRef<iEngine> engine;
1785  csRef<iGraphics2D> g2d;
1786  csRef<iThreadedLoader> tloader;
1787  csRef<iThreadManager> tman;
1788  csRef<iVFS> vfs;
1789  csRef<iCollideSystem> cdsys;
1790  CS::Threading::RecursiveMutex vfsLock;
1791 
1792  // currently loaded zones - used by zone-based loading
1793  ObjectLoader<Zone> loadedZones;
1794 
1795  // currently loading objects
1796  CS::Threading::RecursiveMutex loadLock;
1797  size_t loadOffset;
1798  size_t delayedOffset;
1799  csArray<csPtrKey<Loadable> > loadList;
1800  csArray<csPtrKey<iDelayedLoader> > delayedLoadList;
1801 
1802  // Our load range ^_^
1803  float loadRange;
1804 
1805  // Whether the current position is valid.
1806  bool validPosition;
1807 
1808  // Limit on how many portals deep we load.
1809  uint maxPortalDepth;
1810 
1811  // Number of checks an object may be lingering
1812  // without aborting the load
1813  size_t maxLingerCount;
1814 
1815  // The last valid sector.
1816  csRef<Sector> lastSector;
1817 
1818  // The last valid position.
1819  csVector3 lastPos;
1820 
1821  // current load step - use for ContinueLoading
1822  size_t loadStep;
1823 
1824  // For world manipulation.
1825  csRef<iMeshWrapper> selectedMesh;
1826  csRef<MeshFact> selectedFactory;
1827  csRef<Material> selectedMaterial;
1828  csVector2 previousPosition;
1829  csVector3 origTrans;
1830  csVector3 rotBase;
1831  csVector3 origRot;
1832  csVector3 currRot_h;
1833  csVector3 currRot_v;
1834  bool resetHitbeam;
1835 };
1836 }
1837 CS_PLUGIN_NAMESPACE_END(bgLoader)
1838 
1839 #endif // __LOADER_H__
1840 
bool operator!=(T *p, const scoped_ptr< T > &b)
Definition: scoped_ptr.h:139
const char * GetName(int id)
CS_PLUGIN_NAMESPACE_BEGIN(bgLoader)
Definition: loader.h:63
#define LOADER_DEBUG_MESSAGE(...)
Definition: loader.h:51
#define CS_ASSERT_MSG(msg, x)
Definition: loader.h:56
void void Initialize(iObjectRegistry *object_reg)
bool operator==(T *p, const scoped_ptr< T > &b)
Definition: scoped_ptr.h:134